Unable to retrieve all the data in chunks using Observable - javascript

I am attempting to use a streaming strategy to send data in chunks to the browser. However, when the data is read it does not send them in chunks from the code written to stream the results. It reads and sends the first batch and then gives a message that there are some more items left. Why isn't the rest of the data streamed? I thought was how Observables work, to read the data in chunks in the next callback. Here are how the results are displayed, but with the ... more items, shown below
[
...,
{
productCode: 1829222,
productName: 'Twizzlers'
} ,
... 141 more items
]
Here is the code that tries to stream the data:
const fetch = (url, payload) =>{
try{
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
};
const request = new Request(url, requestOptions);
const data$ = fromFetch(request).pipe(
switchMap(response => {
if (response.ok) {
return response.json();
} else {
return of({ error: true, message: `Error ${ response.status }` });
}
}),
catchError(err => {
console.error(err);
return of({ error: true, message: err.message })
})
);
data$.subscribe({
next: result => console.log(result),
complete: () => console.log('done')
});
}catch(e){
console.error(e)
}
}

I am attempting to use a streaming strategy to send data in chunks to the browser.
Data is sent to the browser in chunks. When the server sends data to the browser, the server is sending it in "chunks" and the browser is storing it in a buffer. You are decoding that buffer to something useable when you run response.json().
For further reading on TCP connections (How GET, POST, etc) work under the hood, I suggest reading the "Bulding blocks of TCP" chapter in the book "High Performance Browser Networking" https://hpbn.co/building-blocks-of-tcp/
Your code works well with standard GET request for some dummy json. I can see the response well and I'm not seeing the error you are seeing
https://stackblitz.com/edit/rxjs-xwyctu?file=index.ts
If you are actually trying to "stream" data to the browser, you can look into Server Sent Events (SSE) https://hpbn.co/server-sent-events-sse/. This is how you can establish a long running GET request to stream data from the server to the client.
You can see an example here: https://github.com/Fallenstedt/server-sent-events-example

Related

API Call returning Gibberish [duplicate]

I have used Postman to explore an API for Samsung's SmartThings. I have that working as expected. But when I take that information and try to implement it in node with Axios the data returned looks like it is compressed or some other blob. Here is the code I am trying to use to get the response:
const axios = require("axios");
function main() {
const st_api = axios.create();
st_api
.get("https://api.smartthings.com/v1/locations/", {
headers: {
get: {
Accept: "application/vnd.smartthings+json",
},
Authorization: process.env.my_home_token,
},
responseType: "json",
responseEncoding: "utf8",
decompress: true,
})
.then(function (res) {
console.log("Status: ", res.status);
console.log("Data: ", res.data);
})
.catch(function (err) {
console.log("Error: ", err);
});
}
main();
And the console log returned is:
Status: 200
Data: �$ͱ�0��W1wn��-H�����d���6KK��»[�v�/���������BC���BXn���%�ek3��j��&�� m�x�M��i�i1 ��פ��8�`�����4�r_����d�ޤ�A�Z��K�K��UV�rk²�<\�_㿻���wA��
I have tried inserting gzip to decompress it or other header information but nothing changes. I am expecting some json returned (or at least something human readable would be a start). I believe I distilled my simple (I hope) api call to a brief test and nothing I try has changed the data being returned.
This is a bug in Axios. Downgrade your Axios version to 1.1.3 or lower, and don't upgrade until 1.3.0 is released. Ref: https://github.com/axios/axios/pull/5300, https://github.com/axios/axios/pull/5306

Axios get unexpected data in Nextjs [duplicate]

I have used Postman to explore an API for Samsung's SmartThings. I have that working as expected. But when I take that information and try to implement it in node with Axios the data returned looks like it is compressed or some other blob. Here is the code I am trying to use to get the response:
const axios = require("axios");
function main() {
const st_api = axios.create();
st_api
.get("https://api.smartthings.com/v1/locations/", {
headers: {
get: {
Accept: "application/vnd.smartthings+json",
},
Authorization: process.env.my_home_token,
},
responseType: "json",
responseEncoding: "utf8",
decompress: true,
})
.then(function (res) {
console.log("Status: ", res.status);
console.log("Data: ", res.data);
})
.catch(function (err) {
console.log("Error: ", err);
});
}
main();
And the console log returned is:
Status: 200
Data: �$ͱ�0��W1wn��-H�����d���6KK��»[�v�/���������BC���BXn���%�ek3��j��&�� m�x�M��i�i1 ��פ��8�`�����4�r_����d�ޤ�A�Z��K�K��UV�rk²�<\�_㿻���wA��
I have tried inserting gzip to decompress it or other header information but nothing changes. I am expecting some json returned (or at least something human readable would be a start). I believe I distilled my simple (I hope) api call to a brief test and nothing I try has changed the data being returned.
This is a bug in Axios. Downgrade your Axios version to 1.1.3 or lower, and don't upgrade until 1.3.0 is released. Ref: https://github.com/axios/axios/pull/5300, https://github.com/axios/axios/pull/5306

How can I log in to an API and catch login errors using fetch on React Native?

I'm making an application that requires login to an API. I have a login form which sends the ID number and password to the API, and the API should respond like this:
[
{
"user_id":"032984",
"user_number":"140521351",
"token":"990nZtMtEUUMY"
}
]
If there is a login error, the API responds with:
[
{
"ERROR": "INVALID PASSWORD | NOT FOUND 1SELECT user_id, lastname, password, user_number FROM user where user_number = 'INVALIDVALUE'",
},
]
I want to be able to catch a login error with an if statement, like if there is the ERROR object in this JSON, display an alert, else login and save the user_id and token to variables I can use in different screens of the app to send more requests to the API, get those responses in JSON, and show the data I need.
How can I make this happen?
So far, here's the code for my login function:
// login function
_userLogin = () => {
this.setState({ isLoggingIn: true, message: '' });
// send request to API properly
fetch("https://api.company.com/v4/users/json.php", {
method: "POST",
// our headers
headers: {
'Content-Type': 'application/json',
'Connection': 'close',
'Accept': '*/*',
'User-Agent': 'InternalApp/0.1 (InternalApp; ReactNative) Expo/33',
'Accept-Language': 'en-US;q=1.0',
'Accept-Encoding': 'gzip, deflate'
},
// body of the request with number/password
body: JSON.stringify({
user_number: this.state.number,
password: this.state.password,
}),
})
.then(response => {
return response.json(); // make it json?!
}).then(responseData => {
// debug messages
console.log(responseData);
console.log("Moving on to parsing JSON"); // CODE WORKS TO HERE
// parse json
var jsonObj = JSON.parse(responseData); // CODE STUCK HERE
// debug messages
console.log("JSON parsed");
if (jsonObj.ERROR)
console.log("Error caught");
else
this.setState(prevState => ({
credentialJson: prevState.credentialJson = responseData,
isLoggingIn: false,
}))
this.props.onLoginPress();
})
};
I'm really new to React Native and StackOverflow, please excuse any formatting issues with the question. I hope I've provided enough detail.
Based on your comments to this answer and the output of console.log(responseData) your responseData is an Array and your data is an Object inside the first array element. Access your data through responseData[0]. For example:
responseData[0].token
//Should return "990nZtMtEUUMY"
Here is how you would check if there is an error set:
if(responseData[0].ERROR){}
Your fetch library fetch returns a Promise so if the API actually throws an error you can add a catch statement.
fetch(url).then().catch((error) => {
console.log("Error", error);
});
The other thing is the reason your code is halting at JSON.parse is that you already parsed the json in a previous .then clause (response.json()) so your trying to parse an object, not a string, which JSON.parse expects.

can't get success response data/status from node/express to my client app(react): "referenceerror response is not defined"

i've made a basic node/express server, and have a route that handles submission of form data(i've made using react), the post request is handled using async/await with fetch api.. i'm not sure if the issue is with my server-side route or my implementation of the post request with async/await fetch. however the server does receive the form data it just doesn't return a response.
my code:
node/express route
router.post('/add', function (req, res) {
console.log(req.body);
res.json({success : "Updated Successfully", status : 200});
});
note: the console.log(prints the expected data, but the response isn't being picked up by client correcly)
post request implementation:
const postRequestHelper = async (routePath, objectPayload) => {
console.log("posting payload object: ");
console.log(objectPayload);
const rawResponse = await fetch(routePath, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(objectPayload)
});
const response = await rawResponse.json();
return response;
};
export default postRequestHelper;
form submission code where post request is called:
async handleSubmit(event) {
if(typeof this.state.validationMessages === "undefined"){
// create payload data object
let objectPayload = Object.assign({}, this.state);
for(let key in objectPayload){
if(!isInObject(key, formKeyConstants)) // delete any prop keys that aren't in formPropertyKeys js file
delete objectPayload[key]
}
// send post request
console.log(objectPayload);
const response = await postRequestHelper("http://localhost:8080/user/add", objectPayload);
// log response data
console.log("response");
console.log(response);
}
event.preventDefault();
}
What about trying in your server
return res.send(JSON.stringify({success : "Updated Successfully", status : 200}));
issue was with async await fetch api it seems, issue with await was breaking the response from the server.
If routing takes place in app , then use :
app.use(express.json)
If routing takes place in router folder , then use :
router.use(express.json)
It'll by default uncover the req.body into json format.(For which installing and initializing express is a must)

React button connection with database through axios.post()

I have 4 inputs and button which takes all data from them and sends to my PostreSQL database through axios.post() request. Not clearly understand how .then() is working. So, here is my button code which just calls this.addNewPainting function:
<button onClick={ this.addNewPainting }>Submit</button>
Here is my addNewPainting function:
addNewPainting() {
axios.post(`http://localhost:333/api/add`, {
title: this.state.titleInput,
year: this.state.yearInput,
size: this.state.yearInput,
location: this.state.locationInput
})
.then(function(response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
Before this project, I used to put response.data to the array with this.setState, but now I have the database and I'm just stuck.
Here is my controller function:
add_painting: (req, res, next) => {
const db = req.app.get('db');
const { title, year, size, location } = req.body;
console.log(title, year, size, location);
db.add_painting([ title, year, size, location ])
.then( () => res.status(200).send() )
.then( () => res.status(500).send() );
}
And the endpoint:
app.post('/api/add', paintings_controller.add_painting);
For future reading (becase you requested it): I'm not an expert using promises, but it works similarly like the AJAX requests.
When you make a request to the server (GET, POST, PUT, etcetera), you're waiting for a response from this (a collection of data, a message, a succesful/unsuccesful POST/PUT/DELETE, etcetera). Depending of the response, you'll code the expected events (error, success, complete, etcetera).
In this case you're using axios, a new way to do AJAX requests. The equivalent way of the error/success/complete/... events is the then() function. Using this approach you can perform operations that makes new tasks or simply print a response message (in your case) of the server.
From MDN:
The then() method returns a Promise. It takes up to two arguments:
callback functions for the success and failure cases of the Promise.
Let's suppose that we have this snippet of code in AJAX:
$.ajax(
{
url : yourURL,
type : 'POST',
data : yourData,
datatype : 'json',
success : function(data) {
yourSuccessFunction(data);
},
error : function(jqXHR, textStatus, errorThrown) {
yourErrorFunction();
}
});
Using axios, you'll code something like this:
axios.post('/user', {
YourData: yourData
}).then(() => { this.yourSuccessFunction() })
}).catch(() => { this.yourErrorFunction() });
I just found the error. I was making a request to PORT 333 in my axios.post(), but the server was working on port 3333.

Categories

Resources