Node-fetch problems with POST requests - javascript

In postman, I can successfully make this request:
And get this response:
Now I want to do the same request in my server.js file in node.js:
const fetch = require('node-fetch')
const SEN_URL = "http://www.sentiment140.com/api/bulkClassifyJson" // URL of sentiment analysis
app.get('/api/sentimenttest', async (req, res) => {
try{
var sentiments = await fetch(SEN_URL, {method: "POST", body: {"data": [{"text": "I love you"}, {"text": "I hate you"}]}})
console.log(sentiments)
res.send(sentiments)
}catch(error){
console.log(error)
}
})
This doesn't work. Here's what shows up in the browser when I go to localhost:5000/api/sentimenttest:
{"size":0,"timeout":0}
and here's the console output:
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]:
{ body:
PassThrough {
_readableState: [ReadableState],
readable: true,
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: true,
_transformState: [Object] },
disturbed: false,
error: null },
[Symbol(Response internals)]:
{ url: 'http://www.sentiment140.com/api/bulkClassifyJson',
status: 200,
statusText: 'OK',
headers: Headers { [Symbol(map)]: [Object] } } }
Since the request works just fine in postman, I think that the problem is with node-fetch, or the way that I use it, specifically how the body parameter is provided in the fetch() call. It seems like the API call does not contain what I want it to, since in the browser it says "size":0.
What should I do to fix this?

You need to await for json.
var sentiments = await fetch(SEN_URL, {method: "POST", body: {"data": [{"text": "I love you"}, {"text": "I hate you"}]}})
//Here
await sentiments.json()
Also you can make request with JSON.stringify() for body. And it will be easier to manage your js object. Like this:
var data = {data: [{text: "I love you"}, {text: "I hate you"}]};
var body = JSON.stringify(data);
var sentiments = await fetch(SEN_URL, { method: "POST", body: body });

Since it can be easily overlooked within the accepted best answer, just wanted to point out that it's especially crucial to return the response as response.json(). The await part can all be in place correctly and still result in OP's Response { size: 0, timeout: 0 etc } if the .json() method is left off. This whole thread is about POST requests but the same applies to GET etc too.

Related

Getting Status : 415 while making POST Request using fetch

I am trying to make POST request using fetch. I am actually following docs example. Docs Provided curl example to make POST request
curl -X POST https://example.com/upload/01
-d "api_key=948324jkl3h45h"
-d "#path/filename.mp4"
-H "Content-Type: application/x-www-form-urlencoded"
There is .mp4 file in my dir. I wrote a simple script to make POST request using fetch. Here is my code.
const filePath = path.join(__dirname , "/video/video.mp4");
const fileData = fs.createReadStream(filePath);
fetch(url, {
body: `api_key=${API_KEY}&${fileData}`,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
}).then(result => {
console.log(result)
})
When I make POST request I am getting this error.
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]: {
body: PassThrough {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: true,
[Symbol(kCapture)]: false,
[Symbol(kCallback)]: null
},
disturbed: false,
error: null
},
[Symbol(Response internals)]: {
url: 'https:/example.com/upload/01',
status: 415,
statusText: 'Unsupported Media Type',
headers: Headers { [Symbol(map)]: [Object: null prototype] },
counter: 0
}
}
I read file using fs.createReadStream. Is that actually right? If there is something wrong, please point me out. I thought some of my file system getting wrong while reading mp4. I wish someone can help me.
Thank youu.

Creating a single exact project, POST results in 500 error

I have access to Exact (OAUTH), access-, refresh-tokens, division No. ...
I get, 'GET' information From Exact API.
But I have problems in 'POST'-ing a new project, using Exact API.
And I have no Clue what is the problem.
As a user, I have 'POST' privileges ().
https://start.exactonline.nl/api/v1/2999609/Users/UserHasRights?endpoint='project/Projects'&action='POST' => true
I've no clue what to do next. Maybe I need to provide more data, but the documentations, state those three fields are enough to create a project.
const data = {
"Code":"P99A",
"Description":"P99A Descr",
"Type": 1
}
const response = await fetch('https://start.exactonline.nl/api/v1/2999609/project/Projects', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Prefer': 'return=representation',
'Authorization': `Bearer ${accessToken}`
},
body: JSON.stringify(data)
})
console.log(response)
Exact Server response:
Response {
size: 0,
timeout: 0,
[Symbol(Body internals)]: {
body: PassThrough {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: true,
[Symbol(kCapture)]: false,
[Symbol(kCallback)]: null
},
disturbed: false,
error: null
},
[Symbol(Response internals)]: {
url: 'https://start.exactonline.nl/api/v1/2999609/project/Projects',
status: 500,
statusText: 'Internal Server Error',
headers: Headers { [Symbol(map)]: [Object: null prototype] },
counter: 0
}
}
Please try with a different value for Type : 4 means Non-billable which requires no other fields normally.
API Documentation shows that 1 is for Campaign. That value is not available via UI.

How handle errors with JS fetch again Laravel Api

My Goal
I would like to display the error messages in the Form. But for this I would need to have access to the JSON?
Code
HTML blade
<form>
<input name="name">
<p class="text-red-500 text-xs italic">Please fill out this field.</p> {{-- $message --}}
<button id="submit">SUBMIT</button>
</form>
javascript
<script>
const submitBtn = document.getElementById('submit');
submitBtn.addEventListener('click', (e) => {
e.preventDefault();
const fel = document.getElementById('commentForm');
const formData = new FormData(fel);
const url = '/api/comments';
let fetchData = {
method: 'POST',
body: formData,
headers: new Headers()
}
fetch(url, fetchData)
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
return response.json();
})
.then(data => {
console.log("Success");
console.log(data);
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
console.log("Json error from API");
console.log(jsonError);
}).catch(genericError => {
console.log("Generic error from API");
console.log(error.statusText);
});
} else {
console.log("Fetch error");
console.log(error);
}
});
</script>
Response after a faulty request
HttpStatus: 400
// console.log(res) output
Response { type: "basic", url: "http://127.0.0.1:8000/api/comments", redirected: false, status: 400, ok: false, statusText: "Bad Request", headers: Headers, body: ReadableStream, bodyUsed: false }
​
body: ReadableStream { locked: false }​
bodyUsed: false​
headers: Headers { }​
ok: false​
redirected: false​
status: 400​
statusText: "Bad Request"​
type: "basic"​
url: "http://127.0.0.1:8000/api/comments"
​
<prototype>: ResponsePrototype { clone: clone(), arrayBuffer: arrayBuffer(), blob: blob(), … }
repellendus-dolor-quibusdam-sint-qui-news:147:29
Problem
In the Devtool Network tab, when I go to response of the request, I get a JSON
JSON: {"comment_content":["The comment content field is required."],"comment_name":["The comment name field is required."]}
When I output res.json() via the console within my fetch method, I get a Promise:
XHRPOSThttp://127.0.0.1:8000/api/comments
[HTTP/1.1 400 Bad Request 100ms]
Promise { <state>: "pending" }​
<state>: "fulfilled"​
<value>: Object { comment_content: (1) […], comment_name: (1) […] }​​
comment_content: Array [ "The comment content field is required." ]​​
comment_name: Array [ "The comment name field is required." ]​​
<prototype>: Object { … }
Additional question:
Is there a better way to display the errors from the response in the form? Maybe with the help of the form data object?
Considering you are making the request from JavaScript means you will also need to update the UI to reflect any error states. This includes targeting the right input elements based on the validation errors and appending them to the DOM. There may be libraries which can make this easier on the JS side but ultimately, you will need to write this logic.
As an aside, if you were using a traditional POST request, Laravel provides the $errors variable and #error blade directive. These help check for / display validation errors and are available in your application views. Since you are using blade, you may want to consider this.

Cache Storage API, can't get header back

I would like to a check for max-age so I remove items from cache when they get old, but I can't get my own header back for some reason.
export function cacheResponse(url, response) {
caches.open('my-cache').then(function(cache) {
cache.put(url, new Response(JSON.stringify(response), {
headers: {
'Cache-Control': 'max-age=1',
'Content-Type': 'application/json;charset=UTF-8'
}
}));
});
}
cacheResponse('/hello', {hello: "world"})
I can see this working in the Application tab in chrome and I can see those 2 headers in the preview, but when I pull the item back out the headers object is null.
cache.match(url).then(async function(object) {
console.log(object.headers) // null
var body = await object.clone().json(); // {hello: "world"}
})
The object looks like this
object: Response
body: ReadableStream
bodyUsed: false
headers: Headers
__proto__: Headers
ok: true
redirected: false
status: 200
statusText: ""
type: "default"
url: ""
Seems like I should be able to lookup the headers from calling match() no?
That should work; you should be able to call response.headers.get('cache-control') to retrieve the value (assuming this is a same-origin response).
Here's a snippet of code that I just tested which worked when run in the JS console:
async function test() {
const constructedResponse = new Response('test', {
headers: {'cache-control': 'max-age=1'}
});
const cache = await caches.open('test');
cache.put('/test', constructedResponse);
const matchedResponse = await cache.match('/test');
console.log(`cache-control: ${matchedResponse.headers.get('cache-control')}`);
}

Mapnik can't determine image type

I'm trying to load an image from a WMS into mapnik, but I'm getting an error Unhandled rejection Error: image_reader: can't determine type from input data. The code, stripped down, is
const request = require('request-promise');
const mapnik = require('mapnik');
request(`${wmsUrl}/GetMap`, {
qs: {
bbox: '-90,32,-89,33',
format: 'image/png',
height: 200,
layers: '5',
request: 'GetMap',
'srs(crs)': 'EPSG:4326,
styles: 'default',
version: '1.1',
width: 200,
},
}).then(res => {
const buffer = new Buffer(res);
return mapnik.Image.fromBytesSync(buffer); // This is the error line
});
I've run the request manually and it works, and I've inspected the buffer and it looks good (i.e. has 'PNG' at the start). I'm not sure what else to try.
In case anyone else encounters something similar to this, the problem is that request (or in this case request-promise) assumes that the response body should be a string and implicitly performs toString on it. To solve, the request should be
request(url, {
qs: { ... },
encoding: null,
}).then({ ... });
See more details here: https://github.com/request/request#requestoptions-callback
I solved my issue by specifying BOTH the responseType and the Content-Type header:
return axios.get(url, {
responseType: 'arraybuffer',
headers: {
'Content-Type': 'image/png',
},
});

Categories