what is Difference between $httpParamSerializerJQLike and json.stringify - angularjs

Here i wrote simple code for saving data into api when i user data: $httpParamSerializerJQLike(savingdata) is Binding data into server side but when i use data: JSON.stringify(savingdata) its not Binding at server side what is the reason
this.saveEmp = function (savingdata) {
var sersave = $http({
url: Privateurl2 + 'SaveEmpData',
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded ;charset=utf-8'
},
// data: $httpParamSerializerJQLike(savingdata),
data: JSON.stringify(savingdata),
})
return sersave;
}

You ask
what is Difference between $httpParamSerializerJQLike and json.stringify
The answer is simple. The former produces a string in form-url-encoded format, the latter JSON. To illustrate...
const savingdata = {
foo: 'abc',
bar: 123,
baz: ['A', 'B']
}
$httpParamSerializerJQLike(savingdata)
// <- foo=abc&bar=123&baz%5B%5D=A&baz%5B%5D=B
JSON.stringify(savingdata)
// <- {"foo":"abc","bar":123,"baz":["A","B"]}
As for why one works with your server and the other does not; you are setting the request Content-type to application/x-www-form-urlencoded. If you attempt to send a JSON formatted request body, your server will fail to decode it because it does not match the format you specified.
Your server may be able to handle a JSON request payload (if it has been coded / configured to do so) in which case you can simply use the AngularJS defaults and use
return $http.post(Privateurl2 + 'SaveEmpData', savingdata)
This will set the Content-type to application/json and will use JSON.stringify to serialize the request payload.
If your server is not set up to handle requests in this format, the operation will obviously fail.

Related

How to post data to a local route using fetch in flask/react.js?

I am trying to send the contents of a flashcard to a backend route http://127.0.0.1:5000/post onClick and it works when I send the data to webhook.site but when I change it to http://127.0.0.1:5000/post I get the error " question = data['question' TypeError: 'NoneType' object is not subscriptable ". Here is the code for the fetch request:
async function postData() {
try {
let result = await fetch('http://127.0.0.1:5000/post', {
method: 'POST',
mode: 'no-cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `${Date.now()}`,
question: flashcard.question,
answer: flashcard.answer,
options: flashcard.options
})
});
} catch(e) {
console.log(e)
}
}
and here is the code for the backend route in flask:
#app.route('/post', methods=['GET', 'POST'])
def post():
#save data to db
data = request.get_json()
question = data['question']
answer = data['answer']
options = data['options']
key = data['key']
return jsonify({'question' : question, 'answer' : answer, 'options' : options, 'key' : key})
if __name__ == "__main__":
app.run(debug=True)
I get that the error is stating that "data" has no value which I assume means it's not recieving the JSON objects that I'm posting. It's weird because it works perfectly when I use a webhook.site url. can anyone help? thanks for your time!
Seems like your content is not a valid json request. If that is the case then content will be equal to None(not subscriptable).
Try to debug how data looks in flask and based on that you will know if its valid json.

Apollo REST Data Source and Imgur API - Keep getting 400 Bad Request using form data

I am trying to implement apollo-datasource-rest to handle image uploading by URL via Imgur's API (documentation here: https://apidocs.imgur.com/)
I initially was getting a 400 error which read We don't support that file type!, and determined that it was due to apollo-datasource-rest automatically setting the Content-Type to application/json. After fixing that issue using the form-data npm package, here's what my code looks like:
class ImgurAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = "https://api.imgur.com/3/";
}
willSendRequest(request) {
request.headers.set("Content-Type", "multipart/form-data");
request.headers.set(
"Authorization",
`Client-ID ${process.env.IMGUR_CLIENT_ID}`
);
console.log(request);
}
async uploadImageFromUrl(url) {
const formData = new FormData();
formData.append("image", url);
return this.post("upload", formData);
}
}
I now no longer get the We don't support that file type! error, but I still get a 400 response with a status text of just Bad Request. The console.log() from the previous code snippet prints this:
{
method: 'POST',
path: 'upload',
body: FormData {
_overheadLength: 104,
_valueLength: 80,
_valuesToMeasure: [],
writable: false,
readable: true,
dataSize: 0,
maxDataSize: 2097152,
pauseStreams: true,
_released: false,
_streams: [
'----------------------------594660553626244976225816\r\n' +
'Content-Disposition: form-data; name="image"\r\n' +
'\r\n',
'https://upload.wikimedia.org/wikipedia/commons/a/a0/Sunflower_as_gif_websafe.gif',
[Function: bound ]
],
_currentStream: null,
_insideLoop: false,
_pendingNext: false,
_boundary: '--------------------------594660553626244976225816'
},
params: URLSearchParams {},
headers: Headers {
[Symbol(map)]: [Object: null prototype] {
'Content-Type': [Array],
Authorization: [Array]
}
}
}
What am I missing here? The API seems to be accepting my form data so I would think that maybe there's some issue with one of the other headers, but in Postman it looks like there's only a few required headers, most of which are calculated (e.g. Content-Length) and so I assume apollo-datasource-rest must be handling that.
After doing some more research into multipart/form-data, I found that the boundary parameter is mandatory, and must be added to the Content-Type value in the request for the server to be able to parse the payload. Furthermore I am unable to manually set it as a parameter in the request (at least not in a way that actually works). Postman normally calculates this field when the request is sent, but apollo-datasource-rest doesn't automatically handle that.
Changing the Content-Type to application/x-www-form-urlencoded and using a url encoded string instead of form-data fixed the issue.
Here's the updated code:
willSendRequest(request) {
request.headers.set("Content-Type", `application/x-www-form-urlencoded`);
request.headers.set(
"Authorization",
`Client-ID ${process.env.IMGUR_CLIENT_ID}`
);
console.log(request);
}
async uploadImageFromUrl(url) {
const formData = `image=${url}&album=${process.env.IMGUR_ALBUM_DELETE_HASH}&type=url`;
return this.post("upload", formData);
}

Modify Returned Response

I am trying to get a Session Key response to use in my future request inside a Zapier Session Authentication, however the response back from a successful authentication is "OK: hbsdakjdkaskjdfvbasdkjh". I need the hbsdakjdkaskjdfvbasdkjh extracted and then saved as the session key variable in the below zapier cli code
I am a little new to parsing JSON, but I think the response is actually raw... I tried a Regex but couldn't figure out the right statement and wondered if someone could help point me in the right direction.
The session URL params etc are working, and the Session Key responding after the OK: is actually correct and one I can use for the remainder of the session manually....
const options = {
url: 'https://theconsole.domain.com.au/api/auth.pl',
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded',
'accept': 'application/json'
},
params: {
'AccountNo': bundle.authData.AccountNo,
'UserId': bundle.authData.UserId,
'Password': bundle.authData.Password
},
}
return z.request(options)
.then((response) => {
response.throwForStatus();
const results = z.JSON.parse(response.content);
// You can do any parsing you need for results here before returning them
return {
'sessionKey': results.sessionKey
};
});
Cool, so if your response is not json, you'll want to remove the z.JSON.parse line, since that'll throw an error.
As for pulling the key out of the response, success will depend on knowing that the response will always have a certain format. In this case, it sounds like it's OK: somekey.
If we can safely assume that there'll only ever be one space () and it's directly before the key, you can try something like:
// the rest of the code
respone.throwForStatus(); // important, assuming the server gives a non-2xx code for a bad auth
const sessionKey = response.content.split(' ')[1];
return {sessionKey}; // shorthand for {sessionKey: sessionKey}
Assuming those assumptions hold true, that should work!

Post controller recognizes only parameters sent by "from-data" or "x-www-form-urlencoded" from postman

I have a very simple controller
[AllowAnonymous]
[HttpPost]
[Route("login")]
public IActionResult Login([FromForm]PhotoLoginDto photologin)
{
//doing some stuff here
}
And even simpler sender on the client side:
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(photologin)
};
console.log("request");
console.log(requestOptions);
return fetch(config.apiUrl + "/PhotoLogin/login", requestOptions).then(
handleResponse,
handleError
);
However after the sending request controller is called, IActionResult works fine but the variable photologin always has empty/default fields. "console.log(requestOptions);" displays:
{method: "POST", headers: {…}, body: "{"Pin":"3","LoginTime":1553604239315,"Photo":"data…ur1DU622EzHVJTtskqJGPzoooqisUBz/s0VJzWpP6E//9k="}"}
body: "{"Pin":"3","LoginTime":1553604239315,"Photo":"adsf"}"
headers: {Content-Type: "application/json"}
method: "POST"
If I try to use the same json via postman (body/raw) I have the same result. It works fine however as "form-data" or "x-www-form-urlencoded".
I also tried to put those three values separetly (not as one obiect) on both sides, client and server in different configurations. I replaced "FromForm" to "FromBody" or remove that attribute complitley but still nothing.
Dto props are identical as sended data. I allow all the sources for CORS.
If any of you had similar problem I would appreciate little help.
EDIT. Also captured response<br/>
body: ReadableStream
locked: true
__proto__: ReadableStream
bodyUsed: true
headers: Headers
__proto__: Headers
ok: false
redirected: false
status: 400
statusText: "Bad Request"
type: "cors"
It might siggest problem with cors, but, as I said everything is set to "allow any origin, allow any method, allow any header, allow credentials"
You're binding as [FromForm], which literally means that it will only bind x-www-form-urlencoded and multipart/form-data encoded requests. If you want something like JSON or XML, then you need to use [FromBody].
If your question is actually that you want to accept all of x-www-form-urlencoded, multipart/form-data and JSON/XML, then the answer is you cannot - not from the same action. If you need to do this, you'll need two separate actions (and routes). The common code can then be factored out into a private method. For example:
private IActionResult LoginCore(PhotoLoginDto photologin)
{
//doing some stuff here
}
[AllowAnonymous]
[HttpPost]
[Route("login")]
public IActionResult LoginForm([FromForm]PhotoLoginDto photologin) =>
LoginCore(photologin);
[AllowAnonymous]
[HttpPost]
[Route("login2")]
public IActionResult Login([FromBody]PhotoLoginDto photologin) =>
LoginCore(photologin);

Multipart form parse error - Invalid boundary in multipart: None

I am very frustrated and could not find the soloution:
I am creating a project using angularjs and nodejs.I get image data from angular side in node js and send this data to further api.I got error
{
"error": {
"detail": "Multipart form parse error - Invalid boundary in multipart: None"
}
}
here is my code in nodejs side:
var request = require('request');
console.log(req.files);
var data = {
website:'www.gamail.xom',
contact_number:'dsdsd',
services_offered:'dsadasd',
contact_name:'dasdas',
provider_category:'exchange',
email:'kk#gmail.com',
image:req.files
}
var api_url = global.common.base_url + 'vcard/1.0.0/visit_card/' + req.param('uuid') +'/';
request({
url: api_url,
method: 'PUT',
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': 'Bearer '+req.cookies.apitoken
},
json: data
}, function(error, response, body) {
if(response.statusCode == 200 && !error){
res.end(JSON.stringify(body));
}else{
res.send(response.statusCode, { error: body });
}
});
}
In req.files i get
{ image:
[ { fieldName: 'image[0]',
originalFilename: 'icon_dd_chart_grey.png',
path: 'C:\\Users\\karakuma\\AppData\\Local\\Temp\\op74_gLSzPs-_49aT1GF0si
7.png',
headers: [Object],
size: 1474,
name: 'icon_dd_chart_grey.png',
type: 'image/png' } ] }
Try defining the content type as follows.
content_type='multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
I was facing the same issue and it worked for me in python.
I also faced this issue while trying to upload file. For me the issue was the FormData, which was coming as Object instead of FormData instance
So i converted my object to FormData using below code:
const getFormData = object => Object.keys(object).reduce((formData, key) => {
formData.append(key, object[key]);
return formData;
}, new FormData());
And the just executed my post request, in my case using Vue resource:
return Vue.http.post(url,
getFormData(formData),
{
headers: {
'Content-Type': 'multipart/form-data'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
There is no need to mention the content type in header, fetch() will detect it's content type by itself.
let formData = new FormData()
formData.append("email", email);
formData.append("password", password);
formData.append("image", image);
const response = await fetch('http://localhost:8000/api/authentication/register/', {
method: 'POST',
headers: {'X-CSRFToken': csrftoken}, //django specific
body: formData,
});
I have been facing this problem in angular 11 connected to Django rest API, I was able to curl with something like this in order to upload a JSON with a form:
curl -X POST -S \
-H 'Accept: application/json' \
-u "user:password" \
-F "name=name" \
-F "label=mylabel" \
-F "otherfields=something" \
-F "photo=#./example.png;type=image/png" \
http://127.0.0.1:8000/api/v1/item/
But I was getting that exception using my header as httpOptions:
'content-type': 'multipart/form-data',
So I just commented out the content-type and it seems angular is so clever that he creates the header for you and will set the multipart together with the boundaries.
For more information on this:
What is the boundary in multipart/form-data?
A boundary is just the 'key' to separate the multiple "parts" of a multipart payload. Normally something like '&' is enough to separate the variables but you need something more unique to separate the payloads within the payload comment
You can use any value that not occurs in the data sent.
NOTE: Because boundary delimiters must not appear in the body parts being encapsulated, a user agent must exercise care to choose a unique boundary parameter value.
The simplest boundary delimiter line possible is something like "---", with a closing boundary delimiter line of "-----".

Resources