Making fetch API work with CORS after OPTIONS response - javascript

I are trying to fetch data from our API. The API has enabled CORS support and returns the below response to the OPTIONS request:
Access-Control-Request-Headers:content-type
Access-Control-Allow-Origin:*
The API doesn't allow 'Content-type' anything other than 'application/json'.
Using this limitation, I am trying to use the fetch method of React-Native to get the data.
Method 1 (no-cors):
{
method: 'POST',
mode: "no-cors",
headers: {
'content-type': 'application/json'
}
With this method, the browser automatically sends the content-type as 'text/plain'. I assume this is because CORS allow just one of the three headers by default. However, since the server doesn't support this content-type, it returns an error back for unsupported content type.
Method 2 (with cors or with nothing):
{
method: 'POST',
mode: "cors", // or without this line
redirect: 'follow',
headers: {
'content-type': 'application/json'
}
}
...
.then(response => console.log(response))
In this scenario, using Chrome's F12 network tool, I can see the server returning data : the first request to the server is a fetch for OPTIONS. To this, the server replies back with an empty object along with the above headers set. The next call is the actual POST API call, to which the server responds back with a proper JSON response containing some data. However, the response which is getting on the console via my code is {}. I assume this is because the react's fetch API is returning back the response of the OPTIONS call instead of the actual POST call.
Is there any way to ignore the response of the OPTIONS request and get the then method to process the response of the subsequent request?

The immediate problem you’re hitting is, your code as currently written expects the response to be JSON but the response is actually a Promise that you need to handle to get the JSON.
So you need to instead do something like this:
fetch("https://example.com")
.then(response => response.json())
.then(jsondata => console.log(jsondata))

Related

TypeError on fetch request on "e-raktakosha" web site api

I am new to javascript. I was trying to make an api call.
My code
const options = {
method: 'GET',
headers: {
Authorization: 'Basic dW5kZWZpbmVkOnVuZGVmaW5lZA==',
'content-type': 'application/json',
}
};
fetch(
'https://www.eraktkosh.in/BLDAHIMS/bloodbank/nearbyBB.cnt?hmode=GETNEARBYSTOCKDETAILS&stateCode=21&districtCode=378&bloodGroup=all&bloodComponent=11&lang=0',
options
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.error(err));
but I encountered with an error saying
Error: Failed to fetch
This api call works perfectly with Hoppscotch
If I try to hit the url right on my url bar, it also works fine.
Any help is strongly appreciated. Thank you from Manoranjan
As other People already mentioned, you can't pass a Body when doing a GET HTTP call, instead you can pass Query Params
Notice this part on the URL
hmode=GETNEARBYSTOCKDETAILS&stateCode=21&districtCode=378&bloodGroup=all&bloodComponent=11&lang=0
Still looking into the code it seems the server have a cors policy, look at this sandbox
See this codesandbox -> https://codesandbox.io/s/peaceful-mcclintock-exuzol?file=/src/index.js
Summary:
GET accept body/payload but it could cause errors, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET
Using the Web API (new headers, new request) for doing the HTTP call
It is better to just avoid sending payloads in GET requests.
Please don't use body with a get request. The GET request is purely meant to collect back data from server, which allows you to sent Queries, not data on the request. Just remove body:'false' or use body:false. The best way is to remove the body from your request so unexpected input is not sent via this GET request.

Google Cloud Functions node JS - POST request from client-side fetch, request body is not coming through [duplicate]

This question already has answers here:
Can't send a post request when the 'Content-Type' is set to 'application/json'
(2 answers)
Closed 2 years ago.
I'm trying to send a POST request using Javascript fetch with application/json as the content-type and am having issues. When I do the request in Postman, it works fine. When I try to do it via Javascript fetch, I get an error and on the GCF logging side, when I try to log console.log(req.body), nothing is registered.
I am able to successfully get the request body to show up and register when I change the request content-type to text/plain and then parse the JSON after the fact in my cloud function, but I'd like to remove this extra step if possible (and also figure out why this isn't working).
Here is the client-side fetch request (essentially pasted from Postman) where the body doesn't get passed for some reason, I've tried various combinations of removing quotes from the property names and also removing the stringify:
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({"key1":"value1","key2":"value2"});
var requestOptions = {
method: 'post',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("mycloudfunctionsurl", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
Here is my Node.JS runtime 10 Cloud Function code:
exports.helloHttp = async ( req, res ) => {
res.set('Access-Control-Allow-Origin', '*');
console.log(req.body); // <-- Shows up with Postman but not above code, unless I change to text/plain
var key1 = req.body.key1;
console.log('key1 is ' + key1);
// other functions to process the response body
};
This is probably a CORS issue. When making a cross-site request, there is an initial pre-flight request made to the function that is not request body that you posted. The fact that you see no body in the function is likely to do the fact that it's receiving this pre-flight request ahead of the intended post. Since the response isn't authorizing the cross-site request, your followup POST is never making it.
I suggest looking at this other question and use the nodejs cors module to implement it properly.

POST working with Postman but not via fetch in JavaScript

The post request to the Django Rest API framework works via Postman when the appropriate parameters are filled in the 'body' section. But the same does not work with the following JavaScript code:
var data = {emp_id:50,emp_name:'test',password:'pass123'};
fetch('http://127.0.0.1:8000/signup/',{
method:"POST",
body: JSON.stringify(data),
mode:"no-cors",
headers: {
"Content-Type": "application/json",
// "Content-Type": "application/x-www-form-urlencoded",
},
})
.then(response => response.json());
The following is the def that handles the POST request in the views.py of the REST-API:
#api_view(['GET', 'POST', ])
def signup(request):
serializer = employeeSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I'm new to this, can anyone tell me why the JavaScript code won't work?
EDIT:
The error which the browser console shows is:
POST http://127.0.0.1:8000/signup/ 415 (Unsupported Media Type)
The issue is that by using no-cors mode you constrain yourself to using simple requests, which in turn cannot have content-type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain. In fact, if you look at the headers sent by the browser with your request, you'll see that the content type changes from application/json to text/plain - hence the error.
To fix your issue: remove no-cors mode and add cors headers to responses in your django app. You can use django-cors-headers for that.
Also, you have no issues with postman because it does not care about same-origin policy.
Try change headers to
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
The accept header is used by to determine what format to sent the data back to the client in the response, guess it might be needed
I found the solution here : https://learning.postman.com/docs/sending-requests/generate-code-snippets/#generating-code-snippets-in-postman
with postman you can see the code of headers sent on the request on many languages (Node Axios, javascript fetch ...), then just copy paste the headers and all the data sent by postman to your app

Error in console of AXIOS

I am using axios in reactjs application. My code is like below
axios.post('/api/addresses/upload/',formData,config)
.then(function (response) {
})
.catch(error => {
});
I did not use any console.log() statement any where but I am getting below error in console.
How this error printed in console ?
Try by setting the header for the axios request,
The HyperText Transfer Protocol (HTTP) 422 Unprocessable Entity response status code indicates that the server understands the content type of the request entity, and the syntax of the request entity is correct, but it was unable to process the contained instructions.
May be you will be missing some of your required fields which is mandatory while processing the operations like insertion or updation of a record in your Database. May be you can have the look at it. If everything works well then try the following settings to the header of your request.
If your submitting the form with files then use the header's content-type as
'multipart/form-data',
without files means then set the content-type as 'application/x-www-form-urlencoded',
If you need to post the json means then set the content-type as 'application/json' and "Accept: 'application/json'"
If any cors error occurs then use 'crossDomain': true
var formData = new FormData();
axios.post('/api/addresses/upload/', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})

Unable to send POST request via HTTP in Angular 4

I am building a small Angular frontend support by a REST api in the backend, but I have ran into a very strange problem: doing http.post(url, data, params) results in nothing happening (there's no sign the request ever hits the webserver, in Chrome Developer tools there's absolutely no request logged as opposed to this.http.get() requests, which work fine for URLs on the same server).
export class RestComponent {
constructor ( private http: Http ) {}
sendStuff() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
this.http.post('http://localhost:3021/api/data', {'data': 3}, options)
.catch(this.handleError);
}
}
CORS is enabled on the server
this.http.get on the URL works as expected
there's no evidence in the server logs that the request was ever sent
there's no evidence in Chrome developer tools that the request was sent (no such post request)
logging stuff in the method just before the .post() call shows that everything is as expected (headers, data, etc)
replicating the request in Postman works (identical headers and data)
tried stringyfying the data as well
the error handler does some simple logging, but it's not triggered
I feel quite dumb as it must be something that's fairly obvious yet it escapes me. I've created a simple component which just two methods, one that sends hardcoded data via post and the other that fetches a hardcoded json via get, the second works but the first doesn't.
Would appreciate any pointers.
Thanks!
Essentially you had created just an observable and Observable are lazy in nature. They will get call/emit only when someone has subscribe to them. Hence you have to call subscribe to Observable returned from it to make your code working. Apart from this Everything seems to be perfect.
sendStuff() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post('http://localhost:3021/api/data', {'data': 3}, options)
.catch(this.handleError)
.subscribe(
(data) => console.log(data)
);
}
There's no server code for us to see but make sure that the route is setup to expect content-type application/json because by default a post route will expect post data, depending on what technology you are using for your server.
Also try just doing a relative path maybe: .post('/api/data')

Categories