I have written a small react component which fetches some data from the open weather api. The fetch succeeds and I can get a json object in the response.
I then save this response to the components state using this.setState({})
And the react dev tools show the forecast object is infact saved in state.
However when I come to rendering any of the data i always get an error stating `cannot read property 'forecast' of null.
Below is the react component and a screen shot of the object itself.
export default class Weather extends Component {
getWeather () {
var self = this;
fetch('http://api.openweathermap.org/data/2.5/weather?zip=sl44jn,uk&units=metric&APPID=ed066f80b6580c11d8d0b2fb71691a2c')
.then (function (response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' + response.status);
return;
}
response.json().then(function(data) {
self.setWeather(data);
});
})
.catch (function (err) {
console.log('Fetch Error :-S', err);
});
}
setWeather (forecast) {
console.log(forecast);
this.setState({
forecast: forecast.name
})
}
componentWillMount () {
this.getWeather();
}
componentDidMount () {
// window.setInterval(function () {
// this.getWeather();
// }.bind(this), 1000);
}
render() {
return (
<h1>{this.state.forecast}</h1>
)
}
}
And this is the data object itself, right now I am simply trying to access the name attribute.
Looks like you forgot couple of things, in order to a Component to setState you need to bind it to this preferably in the constructor. You also need to set the initial state, in your case an empty object, and you can save the whole response in the object and access just the parts you want. have a look:
export default class Weather extends Component {
constructor() {
super();
this.state = {
forecast: {}
};
this.setWeather = this.setWeather.bind(this);
}
getWeather () {
let self = this;
fetch('http://api.openweathermap.org/data/2.5/weather?zip=sl44jn,uk&units=metric&APPID=ed066f80b6580c11d8d0b2fb71691a2c')
.then (function (response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' + response.status);
return;
}
response.json().then(function(data) {
self.setWeather(data);
});
})
.catch (function (err) {
console.log('Fetch Error :-S', err);
});
}
setWeather (forecast) {
this.setState({
forecast: forecast
});
}
componentWillMount() {
this.getWeather();
}
render() {
const { forecast } = this.state;
return (
<h1>{forecast.name}</h1>
)
}
}
Related
I am trying to create a Request via Axios JS to the API Route and trying to send the data from the database over the controller back to the view of the page. When I am just put an string as return value it is working.
I am always getting following a 500 Error.
JS File
function getSelectedItem() {
var e = document.getElementById("Objekt");
if (e.value > 0) {
axios({
method: 'get',
url: '/api/zimmer/' + e.value,
responseType: 'stream'
})
.then(function(response) {
zimmer_select.disabled = false;
console.log(response.data);
})
.catch(function(error) {
console.log(error);
});
} else {
zimmer_select.disabled = true;
}
console.log(e.value);
}
API Route:
Route::controller(MieterController::class)->group(function () {
Route::get('/zimmer/{id}', 'relocate_update')->name('api.get.zimmer');
});
Controller:
public function relocate_update($id) {
$zimmer_zu_objekt = Zimmer::findOrFail()->where('objekt_id', $id);
return response()->json(['alle_zimmer' => $zimmer_zu_objekt], 200);
}
I got it.
I changed it to VanillaJS and the main problem was my Eloquent Query in the Controller. Corret is
return Zimmer::where('objekt_id','=', $id)->get();
and used the fetch-method is JS:
fetch('/api/zimmer/' + e.value)
.then(function(response) {
zimmer_select.disabled = false;
console.log(response.json());
})
.catch(function(error) {
console.log(error);
});
I'm trying to call json file from url and get data. But no error and nothing working. I don't have any idea how to solve it.
service
export class JsonService {
public getMenuData(): Observable<any> {
return new Observable((observer) => {
this.http.get('https://demored.ddns.net:50443/demored/path_image/menu.json').subscribe((response)=> {
observer.next(response);
observer.complete();
});
});
}
Component
ngOnInit() {
this.getJson();
}
getJson(){
this.jsonService.getMenuData().toPromise().then(data => {
this.menuJson = data;
console.log("Menu from json file ",this.menuJson);
}).catch((err) => {
console.log('error in fetching data',err);
});
}
You make the GET request on the service, where you convert the request into a promise with toPromise(). From there in any component you can call the method for the service declared in the constructor this.serviceJson() and resolve the promise with a .then () or .catch ()
export class JsonService {
getMenuData(): Promise<any> {
return this.http.get<any>('https://demored.ddns.net:50443/demored/path_image/menu.json').toPromise()
}
component
ngOnInit() {
this.getJson();
}
async getJson(){
await this.jsonService.getMenuData().then(data => {
this.menuJson = data;
console.log("Menu from json file ",this.menuJson);
}).catch((err) => {
console.log('error in fetching data',err);
});
}
I'm currently using axios and NextJS.
I currently have this code in my component:
export async function getServerSideProps(context) {
const data = await getVideo(context.query.id);
console.log('data: ', data);
// console.log('context: ', context);
console.log('context params: ', context.params);
console.log('context query: ', context.query);
if (!data) {
return { notFound: true };
}
return {
props: {
videoId: context.params.id,
videoSlug: context.params.slug,
videoContent: data
}
};
}
This getserverSideProps call the function of getVideo which looks exactly like this:
export const getVideo = (id) => async (dispatch) => {
dispatch({ type: CLEAR_VIDEO });
try {
console.log('Action file: ', id);
const res = await api.get(`/videos/${id}`);
return dispatch({
type: GET_VIDEO,
payload: res.data
});
} catch (err) {
dispatch({
type: VIDEO_ERROR,
payload: { msg: err.response?.statusText, status: err.response?.status }
});
}
};
Said function goes through my api function to make requests to backend:
import axios from 'axios';
import { LOGOUT } from '../actions/types';
import { API_URL } from '../config';
const api = axios.create({
baseURL: `${API_URL}/api/v1`,
headers: {
'Content-Type': `application/json`
}
});
/**
intercept any error responses from the api
and check if the token is no longer valid.
ie. Token has expired
logout the user if the token has expired
**/
api.interceptors.response.use(
(res) => {
res;
console.log('Res: ', res.data);
},
(err) => {
if (err?.response?.status === 401) {
typeof window !== 'undefined' &&
window.__NEXT_REDUX_WRAPPER_STORE__.dispatch({ type: LOGOUT });
}
return Promise.reject(err);
}
);
export default api;
It works great when doing POST, PUT,PATCH requests.
As you can see, I'm doing a console.log('data: ',data) but it returns [AsyncFunction (anonymous)] whenever I read the terminal; on the other hand, the front-end returns this error:
Server Error Error: Error serializing .videoContent returned from
getServerSideProps in "/videos/[id]/[slug]". Reason: function
cannot be serialized as JSON. Please only return JSON serializable
data types.
Does anyone knows how to solve this?
NOTE: I'm using react-redux, redux and next-redux-wrapper.
That is because your getVideo function returns another function. The right way to call it would be:
const data = await getVideo(context.query.id)()//<- pass in the dispatch here
But you should not use redux in the backend like that. I think you can completely remove it.
export const getVideo async (id) => {
try {
console.log('Action file: ', id);
const res = await api.get(`/videos/${id}`);
return res.data
});
} catch (err) {
return { msg: err.response?.statusText, status: err.response?.status }
}
};
// call
const data = await getVideo(context.query.id)
I have a following function which uses streaming-query-rows of mysql node js module. How can i unit test the below function and also i want to mock the database behavior instead of connecting to database while unit test.
'processRow' and ''wirteCsvFile'' function both are synchronous task.
function executeTask(sql_connection,sql_query) {
let query = sql_connection.query(sql_query);
let showInfo = {};
let showids = [];
query
.on('error', (error) => {
console.error(`error executing query --> ${error}`);
})
.on('result', function (row) {
sql_connection.pause();
processRow(row, showInfo, showids, function () {
sql_connection.resume();
});
})
.on('end', function () {
showids.forEach(showid => {
if (showInfo[showid].faults.length === 0) {
delete showInfo[showid];
}
});
wirteCsvFile(showInfo, (error, done) => {
if (error) {
console.error(error);
} else {
console.log("done");
process.exit();
}
})
});
}
You can stub the query function to return whatever you want instead of making request to database:
sinon.stub(connection, "query").callsFake(() => /* whatever you want here */);
You should also break executeTask into smaller functions, for ex:
function errorHandler(error) {
console.error(`error executing query --> ${error}`);
}
function resultHandler(data, row) {
sql_connection.pause();
processRow(row, data.showInfo, data.showids, function() {
sql_connection.resume();
});
}
function endHandler(data) {
data.showids.forEach(showid => {
if (data.showInfo[showid].faults.length === 0) {
delete data.showInfo[showid];
}
});
wirteCsvFile(data.showInfo, (error, done) => {
if (error) {
console.error(error);
} else {
console.log("done");
process.exit();
}
})
}
function executeTask(sql_connection, sql_query) {
let query = sql_connection.query(sql_query);
let data = {
showInfo: {},
showids: [],
};
query.on('error', errorHandler)
.on('result', resultHandler.bind(null, data))
.on('end', endHandler.bind(null, data));
}
Now you can test errorHandler, resultHandler, endHandler separately
What I'm thinking is we can mock the sql_connection with a class of Event Emitter.
const sinon = require("sinon");
const assert = require('assert');
const EventEmitter = require('events');
const src = require('....'); // your source file that contain `executeTask`
// Create mock emitter
class QueryEmitter extends EventEmitter {}
describe('test execute task', function() {
const queryEmitter = new QueryEmitter();
// we build mock connection that contains all methods used as in `sql_connection`
const conn = {
query: sinon.stub().returns(queryEmitter),
pause: sinon.spy(),
resume: sinon.spy()
};
const query = 'SELECT *';
before(function() {
src.executeTask(conn, query);
});
it('calls query', function() {
assert(conn.query.calledWith(query));
});
it('on result', function() {
queryEmitter.emit('result');
assert(conn.pause.called);
// assert if processRow is called with correct arguments
// assert if conn.resume is called
});
it('on end', function() {
queryEmitter.emit('end');
// assert if writeCsvFile is called
});
// probably is not needed since you only call console.log here
it('on error', function() {
queryEmitter.emit('error');
});
});
Hope it helps
I'm attempting to query an API which responds with a ReadableStream of XML.
The code below uses a recursive Promise. Recursive because it sometimes doesn't decode the stream in a singular iteration and this is whats causing my headache.
While I'm successfully fetching the data, for some reason the decoding stage doesn't complete sometimes, which leads me to believe it's when the stream is too large for a single iteration.
componentDidMount() {
fetch("http://thecatapi.com/api/images/get?format=xml&size=med&results_per_page=9")
.then((response) => {
console.log('fetch complete');
this.untangleCats(response);
})
.catch(error => {
this.state.somethingWrong = true;
console.error(error);
});
}
untangleCats({body}) {
let reader = body.getReader(),
string = "",
read;
reader.read().then(read = (result) => {
if(result.done) {
console.log('untangling complete'); // Sometimes not reaching here
this.herdingCats(string);
return;
}
string += new TextDecoder("utf-8").decode(result.value);
}).then(reader.read().then(read));
}
I think that the next iteration was sometimes being called before the current iteration had completed, leading to incorrectly concatenation of the decoded XML.
I converted the function from sync to async and as a regular recursive method of the component rather than a recursive promise with a method.
constructor({mode}) {
super();
this.state = {
mode,
string: "",
cats: [],
somethingWrong: false
};
}
componentDidMount() {
fetch("http://thecatapi.com/api/images/get?format=xml&size=med&results_per_page=9")
.then( response => this.untangleCats( response.body.getReader() ) )
.catch(error => {
this.setState({somethingWrong: true});
console.error(error);
});
}
async untangleCats(reader) {
const {value, done} = await reader.read();
if (done) {
this.herdingCats();
return;
}
this.setState({
string: this.state.string += new TextDecoder("utf-8").decode(value)
});
return this.untangleCats(reader);
}