Angular post call not working (Getting 415 error) - javascript

I'm trying to fetch the response from the below code. Which gives the JSON output. In server i'm getting 415 issue and the response also not coming.
constructor(private http: HttpClient){}
public getReports(postData: IRreq) {
let headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
return this.http.post(sampleurl, JSON.stringify(postData), { headers: headers })
.pipe(map((res:any) => this.report = res));
};
No issue from the API, getting 200 and response in postman. Not sure what was the issue here, need some help on this. Thanks

You are using example for Angular 2. That times json content-type was not standard way.
Now when you want to make request with json content-type you only do following:
const body = { title: "Angular PUT Request Example" };
this.http
.put<any>("https://jsonplaceholder.typicode.com/posts/1", body)
.subscribe((data) => console.warn(data));
So you don't need to do any magic with json encoding etc.

Related

What is the correct way to post images on django-rest-framework server using javascript?

I have a POST API view that accepts an image and a style sting and returns a styled image.
It works on postman just fine but I cannot get it to work using fetch API.
Serializer:
class GetImageSerializer(serializers.Serializer):
image = serializers.ImageField()
style = serializers.CharField()
DRF view:
class PostImage(APIView):
serializer_class = GetImageSerializer
parser_classes = [MultiPartParser]
def post(self, request, format=None):
print(request.data) # Debug
img = request.data.get('image')
# Process
response = FileResponse(img)
return response
The fetch call:
json = {}
json["image"] = this.state.image
json["style"] = "models\\wave\\wave200.pth"
console.log("sending --- ", json) //debug
fetch('/style_transfer/style/',
{
headers: { "Content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" },
body: json,
method: "POST"
}
).then(response => {
if (!response.ok) {
console.log("couldn't fetch image")
}
return response.json()
})
.then(data => {
console.log("fetched data")
console.log(data)
outputs of console logs. This shows that the correct data is in json dictionary
But the data isn't received by DRF server.
The print(request.data) from the view returns <QueryDict: {}>.
The strange part is that the same code works with postman.
Things I've tried:
Remove the headers from fetch request - This throws unsupported media type error
Set content-type to "application/json" - This reads the string parameter but image key is empty. this is what request.data looks like {'image': {}, 'style': 'models\\wave\\wave200.pth'}
I want to understand what's causing this issue. I've read several similar threads but I couldn't find the recommended way to do something like this. So, what's the issue and what is the recommended way of doing this?

Why does Axios send my POST request with Content-Type application/x-www-form-urlencoded when using a string as the request body?

I found this interesting behavior with axios while making POST requests. I am sending URLs that the user types in to my Spring RestController which accepts the request body as a String. It looks like this:
#PostMapping("user/{userId}/link")
public ResponseEntity<UserLinkDTO> addUserLink(
#PathVariable(value = "userId") Integer userId, #RequestBody String url) {
...
}
On the front end, my axios request looks like this:
const saveUserLink = async (userId: number, url: string): Promise<UserLinkDTO> => {
return axiosInstance.post(`user/${userId}/link`, url))
.then(r => r.data)
);
When I send some arbitrary URLs (with = in them) like these:
https://www.google.com/search?client=firefox
https://www.yahoo.com/somePage?key=value&hello=world
the Spring POST method receives the url exactly as it was sent.
However, when I send some URLs like this (without any = in them):
https://www.google.com
https://www.yahoo.com/somePage
my Spring POST method receives the url with = appended to them! So the links are received as:
https://www.google.com=
https://www.yahoo.com/somePage=
I noticed the requests are being sent with Content-Type: application/x-www-form-urlencoded in my Network tab. However, based on axios docs, all requests should be serialized to JSON which would imply being sent with Content-Type: application/json. All the other requests I'm using are sent with Content-Type: application/json. It's only this one that gets converted to Content-Type: application/x-www-form-urlencoded.
I edited my axios post request to include some custom headers so I could change the Content-Type back to application/json:
const saveUserLink = async (userId: number, url: string): Promise<UserLinkDTO> => {
return axiosInstance.post(`user/${userId}/link`, url, {
headers: {
'Content-Type': 'application/json',
}
})
.then(r => r.data)
);
My Spring POST method is now able to receive the URLs above exactly as provided, regardless of if they have = in them or not. There is no longer an extra = appended to the links without any =.
Why is it that axios seems to change the Content-Type from application/json to application/x-www-form-urlencoded when providing a string as the request body?
the default content-type in axios is 'application/x-www-form-urlencoded'
//https://github.com/axios/axios/blob/master/lib/defaults.js
var DEFAULT_CONTENT_TYPE = {
'Content-Type': 'application/x-www-form-urlencoded'
};
//...
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});
while when request's data is an Object, axios sets contentType to 'application/json':
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}

Make a correct POST request and get response data

I have an application hosted on pythonanywhere.com. It throws a 400 error if sended data does not contain data property, otherwise it returns a response data. This is Flask code of the server:
#app.route('/api', methods=['POST'])
def get_post():
if not request.json or not 'data' in request.json:
abort(400)
data = request.json['data']
# do something with the data...
return jsonify({'response': str(data)}), 200
And my front-end part of application should send a POST request with a data and get a response. I am trying to use fetch but it gets a 400 error though I send a JSON object with a data object:
function sendData(value) {
data = { 'data': value };
fetch('http://' + appUrl, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
mode: 'no-cors',
body: JSON.stringify(data),
})
.then(data => { return data.json() })
}
Also I tried to use XMLHttpRequest:
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://' + appUrl, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
But I can't find out how to disable CORS and get a response data.
if you are having CORS issue, always check if the server accept your origin of request (other than pythonanywhere.com) if not, you should allow it from your server.
you mentioned that you are using Flask as your backend, you might want to check out this library:
https://flask-cors.readthedocs.io/en/latest/
if you follow the docs from the link, you can allow, accept http request depends on the parameter you provided.
Happy Coding

Angular 2 Http with custom headers getting 405

I've run into this issue with custom headers when trying to perform and Http GET request from angular 2. Preforming the same request from Postman works fine, however I get a following 405 error in Angular2:
OPTIONS http://[somehost.com]/api/v1/admin/account/singin 405 (Method Not Allowed)
The API has a GET operation where you pass a username and password in the header and it returns a 200 with a token in it's header. Here is an example of the code block I am using:
constructor (private http: Http) {
}
login (userName: string, password: string): Observable<any> {
const endPointUrl = this.baseUrl + '/admin/account/singin';
const headers = new Headers({
'Accept': 'application/json',
'X-Rem-Username': userName,
'X-Rem-Password': password
});
const options = new RequestOptions({headers: headers});
return this.http.get(endPointUrl, options)
.map((response: Response) => {
console.log(response);
return response;
});
}
As I mentioned, performing this request in Postman and in he WebStorm REST client with these headers works fine. If I remove these 'X-Rem' headers I get a 401, which is expected. Any help would be appreciated, thanks.
Try this
const headers = new Headers({
'Accept': 'application/json',
'X-Rem-Username': userName,
'X-Rem-Password': password
});
this.http.get('url', {headers: headers})
This is not problem with angular app. Your app and rest api server are different server/domain. You should configure cross domain allow in server. Whenever you request any api on server by web browser, it first check cross domain allow options by request a OPTION method. In postman api directly send, there is no cross domain.
I am not sure but you can try add this header:
"Access-Control-Expose-Headers" : "Authorization"
I found it in this discussion

POST from Typescript to Web API API, unable to pass a JSON Object

I am trying to pass a JSON Object from a typescript POST call to a Web API method.
Fiddler shows that the object has been converted into JSON and the Content-Type is 'application/JSON'. But at the API controller, the parameter value displays null instead of JSON.
Typescript:
createPO(product: string): Promise<string> {
var headers = new Headers();
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers });
return this._http.post(this._creatPOUrl, JSON.stringify(product), options)
.toPromise()
.then(response => <string>response.statusText)
.catch(this.handleError);
}
Web API:
[HttpPost]
public async Task CreatePOInMO([FromBody] string product)
{
return Ok();
}
product contains null.
If I pass the actual value inside product object from typescript(which is a JSON) , it works. But I cannot hard code like this.
I followed this post : Angular2 Service not passing JSON to WebAPI
But it looks like I am doing whatever is mentioned here.
In Angular 2, when posting JSON with the Http client, you should not call JSON.stringify:
this._http.post(this._creatPOUrl, product, options)

Categories

Resources