How to post JSON String NOT Object in request body? - json

The body is String similar to this. I tried many different ways as below, but none worked.
await http.post(
Uri.parse(url),
headers: {
"content-type": "application/json",
},
body: "3ea9554d-7a1f-4f20-f6f5-08da74d069a8", // "'a' is invalid within a number, immediately after a sign character
// body: "\"3ea9554d-7a1f-4f20-f6f5-08da74d069a8\"", // The JSON value could not be converted to
// body: jsonEncode("3ea9554d-7a1f-4f20-f6f5-08da74d069a8"), // The JSON value could not be converted to
// body: jsonEncode("\"3ea9554d-7a1f-4f20-f6f5-08da74d069a8\""), // The JSON value could not be converted to
// body: jsonEncode(jsonDecode('3ea9554d-7a1f-4f20-f6f5-08da74d069a8')), // FormatException: Missing expected digit (at character 3)
// body: jsonEncode(jsonDecode("\"3ea9554d-7a1f-4f20-f6f5-08da74d069a8\"")), // The JSON value could not be converted to
);

Use postman to autogenerate code like this

Thanks to the answer given by Wali Khan. The solution is
final request = http.Request('POST', Uri.parse(url));
request.headers.addAll({
"content-type": "application/json",
});
request.body = json.encode("3ea9554d-7a1f-4f20-f6f5-08da74d069a8");
http.StreamedResponse response = await request.send();

Since you set the content-type to application/json, you can't pass a string, only an object, like:
body: jsonEncode({"value": "3ea9554d-7a1f-4f20-f6f5-08da74d069a8"})
To pass your string as you'd like, set the content type like this:
"content-type": "text/plain"
But according to the documentation you can try to remove the headers part completely, since it seems that it will be text/plain automatically if you pass a string as body.

Related

How to get title/item from response.body (HTTP - JSON)

I want to pull certain headers and items under the headers as string data from the JSON.
Map dataSignUpEmployeer = {
'corporationName': employeer.getCorporationName(),
'webSiteName': employeer.getWebSiteName(),
'email': employeer.getEmail(),
'password': employeer.getPassword(),
};
String bodySignUpEmployeer = json.encode(dataSignUpEmployeer);
postDataSignUpEmployeer() async {
final response = await http.post(
Uri.parse(urlSignUp),
headers: {"Content-Type": "application/json"},
body: bodySignUpEmployeer,
);
return response.body;
}
response.body return JSON
Eesponse.body's return:
Please help me in any way.
your code is working as well i see so i think you wrong in a part of your code for get the success: true from your response body so maybe you need to authorize your user in header of post method with Token. to get back success true and get all of each user data. any way we should see your api url.

node request module: parsing XML as JSON

Until recently I've been fetching XML data using the node request module, and then running that XML through an XML to JSON converter. I discovered by accident that if I set json: true as an option (even knowing the endpoint returns XML, not JSON), I was actually getting back JSON:
var request = require('request');
var options = { gzip: true, json: true, headers: { 'User-Agent': 'stackoverflow question (https://stackoverflow.com/q/52609246/4070848)' } };
options.uri = 'https://api.met.no/weatherapi/locationforecast/1.9/?lat=40.597&lon=-74.26';
request(options, function (error, response, body) {
console.log(`body for ${options.uri}: ${JSON.stringify(body)}`);
});
The above call returns JSON, whereas the raw URL is actually sending XML. Sure enough, with json: false the returned data is XML:
var request = require('request');
var options = { gzip: true, json: true, headers: { 'User-Agent': 'stackoverflow question (https://stackoverflow.com/q/52609246/4070848)' } };
options.uri = 'https://api.met.no/weatherapi/locationforecast/1.9/?lat=40.597&lon=-74.26';
options.json = false; // <<--- the only difference in the request
request(options, function (error, response, body) {
console.log(`body for ${options.uri}: ${body}`);
});
So I thought "that's handy", until I tried the same trick with a different URL that also returns XML, and in this case the returned data is still XML despite using the same request options:
var request = require('request');
var options = { gzip: true, json: true, headers: { 'User-Agent': 'stackoverflow question (https://stackoverflow.com/q/52609246/4070848)' } };
options.uri = 'https://graphical.weather.gov/xml/SOAP_server/ndfdXMLclient.php?whichClient=NDFDgen&lat=40.597&lon=-74.26&product=time-series&temp=tempSubmit=Submit';
request(options, function (error, response, body) {
console.log(`body for ${options.uri}: ${body}`);
});
What is the difference here? How do I get the latter request to return the data in JSON format (so that I can avoid the step of converting XML to JSON myself)? Maybe the endpoint in the first example can detect that JSON is requested and it does in fact return JSON rather than XML?
EDIT weirdly, the first request is now returning XML rather than JSON even with json: true. So maybe this behaviour was down to what was being sent from the endpoint, and they've changed this even since I posted a few hours ago
So now that the behavior is unrepeatable, the answer is less useful for your particular problem, but I think it's worth pointing out that when you set json:true on the request module, it does a few things under the hood for you:
Sets the Accept header to 'application/json'
Parses the response body using JSON.parse()
Request types with a body also get the body automatically serialized as JSON
Request types with a body also get the Content-Type header added as 'application/json'
So perhaps they did change it, but there are plenty of web services I've seen that will detect the content-type to send based on the Accept header and respond appropriately for some set of types that make sense (usually XML or JSON, but sometimes CSV, TXT, HTML, etc).
To handle XML query, I usually do something like this using the request module:
import parser from "xml2json";
const resp = await rp({
method: "POST",
url: 'some url',
form: {xml_query}, // set XML query to xml_query field
});
const parsedData = parser.toJson(resp, {
object: true, // returns a Javascript object instead of a JSON string
coerce: true, // makes type coercion.
});

typescript Cannot add headers to a fetch api using react-native

I am using Fetch API from react-native and I am using typescript.
My code looks like this:
let responseLogin = await fetch('http://url_example', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: requestBody
});
But I get the following error where the header is:
Argument of type '{ method: string; headers: { 'Content-Type': string; }; body: string; }' is not assignable to parameter of type 'RequestInit'.
Types of property 'headers' are incompatible.
Type '{ 'Content-Type': string; }' is not assignable to type 'Headers | string[][]'.
Object literal may only specify known properties, and ''Content-Type'' does not exist in type 'Headers | string[][]'.
I have also tried to create a custom header but without any luck:
let requestHeaders = new Headers();
requestHeaders.set('Content-Type', 'application/json');
// I have also tried adding this at the end but no luck
// requestHeaders.get('Content-Type');
How could I add a header to this? Because I cannot find any way to make this happen and I don't know what is the problem. If I test these in postman, I get a 200 response, here I get a 401 response.
I have also tried this library just to add custom headers: https://www.npmjs.com/package/fetch-headers
I use:
Visual studio code 1.81.1
"react-native": "0.50.0",
"typescript": "2.6.1"
Can you try typing it as HeadersInit?
const requestHeaders: HeadersInit = new Headers();
requestHeaders.set('Content-Type', 'application/json');
const responseLogin = await fetch('URL', {
method: 'POST',
headers: requestHeaders,
body: requestBody
});
If not, can you show the error you are getting when you are initiating it with the Headers() constructor, you showed in the question?
What TypeScript libraries are you including with your build? It looks like your definition for the headers property is wrong. In TypeScript 2.6.2, the headers property is of type HeadersInit, which is defined as:
type HeadersInit = Headers | string[][] | { [key: string]: string };
I solved the problem by importing Headers like this:
import fetch, { Headers } from 'node-fetch';
The accepted answer has the caveat that it doesn't handle the scenario where you encapsulate fetch into a function of your own that receives the same arguments as fetch and sets defaults to the headers property. For example:
async function myFetch(input: RequestInfo, init: RequestInit) {
// set some headers here
const res = await fetch(input, init)
// return something from the response here, handle errors
}
The problem with the resolved answer is that RequestInit.headers is of type HeadersInit whose definition is:
type HeadersInit = string[][] | Record<string, string> | Headers;
When I try to set defaults for headers but still use headers passed by the calling function, I run into issues because of these possible multiple types that I need to deal with.
What I resolved out of complete exasperation is to define my own RequestInit type where headers is only Record<string, string>. I don't care about the other types, an object of string key/values IS fine.
export interface MyRequestInit extends Omit<RequestInit, 'headers'> {
headers?: Record<string, string>;
}
export async function fetchJson<JSON = unknown>(
input: RequestInfo,
init: MyRequestInit = {},
) {
// set my own default headers here
const res = await fetch(input, init)
// ...
}
I have solved the problem like this:
let requestHeaders: any = { 'Content-Type': 'application/json' };
let responseLogin = await fetch('URL', {
method: 'POST',
headers: requestHeaders,
body: requestBody
});
All that I had to do was to ignore that error message because JS interprets the syntax correctly, only typescript doesn't and I did that by creating a variable in which I stored those two strings.

How to return a JSON object from an Azure Function with Node.js

With Azure Functions, what do you need to do to return a JSON object in the body from a function written in node.js? I can easily return a string, but when I try to return a json object as shown below I appear to have nothing returned.
context.res = {
body: jsonData,
contentType: 'application/json'
};
Based on my recent testing (March 2017). You have to explicitly add content type to response headers to get json back otherwise data shows-up as XML in browser.
"Content-Type":"application/json"
res = {
status: 200, /* Defaults to 200 */
body: {message: "Hello " + (req.query.name || req.body.name)},
headers: {
'Content-Type': 'application/json'
}
};
Full Sample below:
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
context.log(context);
if (req.query.name || (req.body && req.body.name)) {
res = {
// status: 200, /* Defaults to 200 */
body: {message: "Hello " + (req.query.name || req.body.name)},
headers: {
'Content-Type': 'application/json'
}
};
}
else {
res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
context.done(null, res);
};
If your data is a JS object, then this should just work, e.g.
module.exports = function(context, req) {
context.res = {
body: { name: "Azure Functions" }
};
context.done();
};
This will return an application/json response.
If instead you have your data in a json string, you can have:
module.exports = function(context, req) {
context.res = {
body: '{ "name": "Azure Functions" }'
};
context.done();
};
Which will return an application/json response because it sniffs that it is valid json.
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.name || (req.body && req.body.name)) {
context.res = {
// status: 200, /* Defaults to 200 */
body: {"data":"Hello"},
headers: {
'Content-Type': 'application/json'
}
};
}
else {
// res = {
// status: 400,
// body: "Please pass a name on the query string or in the request body"
// };
}
context.done(null,res);
I would like to add one more point. Apart from making the body: a JSON object, the request should also contain proper headers telling server what content type we are interested in. I could see that same Azure function when just invoked via browser using URL gives XML response, but when invoking from script or tools like Postman it gives JSON.
I feel like the answer has been given but it hasn't been clearly presented so I thought I'd answer as well in case it will help anyone coming behind me. I too have created a function that most definitely returns a Javascript object but if I copy and paste the URL in the Azure Function UI and just open a new tab in Chrome and try to view the output, I actually get back an XML document that tells me there's an error (not surprising there's an error as many characters in the Javascript would have blown up the XML). So, as others have mentioned, the key is sending the appropriate headers with your request. When you copy/paste the URL into your browser, the browser is sending a request header that looks similar to this:
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
When that happens, you see the XML return as described in this link:
https://github.com/strongloop/strong-remoting/issues/118
In order to get around this problem and see what the data would look like with a JSON request, either use a utility like Postman:
https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en
Accept: application/json
Or use a CURL command and pass in the proper Accept header.
As you can see in the screenshot above, when I provided the proper header, I get back the JSON response I would expect.
You can also use JSON.stringify() to make a valid json string out of your js-object:
jsonData = { value: "test" }:
context.res = {
body: JSON.stringify(jsonData)
};

UrlFetchApp upload file multipart/form-data in Google Apps Script

I need to upload files to a 3rd party service. The files are created on Google Drive, and I get the blob-data for it.
I want to create a multipart request which now looks like this when I do the UrlFetchApp Post.
This is the payload as string. I have some code that generates the payload. Getting it properly formatted is not the problem, it's the format it is supposed to be.
-----------------0.13accb4c42d338
Content-Disposition: form-data; name="source"; filename="Zzapps.jpg"
Content-Type: application/octet-stream
[[[IMAGE DATA HERE -- OMITTED FOR BREVITY]]]
-----------------0.13accb4c42d338
Content-Disposition: form-data; name="filename"
Zzapps.jpg
-----------------0.13accb4c42d338--
This is the piece of code that does the UrlFetchApp command.
var authHeaders = {
Authorization: 'OAuth2 '+access_token
}
var params = {
accept: "application/json",
method: 'POST',
payload: payload,
contentType: 'multipart/form-data; boundary='+boundaryKey,
headers: authHeaders,
ContentLength: payload.length,
muteHttpExceptions: true
}
var resx = UrlFetchApp.fetch(url, params);
The recieving party gives an error (missing source). I am not sure if my multipart-post is okay in the first place, I do not find any testing URL's to check if I do a proper upload.
How could I send blob-data as a multipart upload the proper way?
And now I use blob.getDataAsString() <-- is this correct ?
If you're building the payload string yourself, you want to do blob.getBytes(), not blob.getDataAsString().
However, there's an easier way. Rather than building the payload string yourself, you can just set a javascript object as the payload, and UrlFetchApp will automatically generate the appropriate payload string, select the correct content-type, boundary, and most of the other options. Just use the "name" attribute of the HTML form's input fields as your object keys. For files, use blobs as the key's values.
function sendReportToSteve() {
var url = "https://example.com/stevedore.html";
var form = {
date : new Date(),
subject : "Happy birthday!",
comment : "quakehashprismkeepkick",
attachment1 : DriveApp.getFileById("sH1proy0lradArgravha9ikE").getBlob(),
attachment2 : DriveApp.getFileById("traCetRacErI3hplVnkFax").getBlob()
};
uploadFile(url,form);
}
function uploadFile(url,form) {
var options = {
method : "POST",
payload : form
};
var request = UrlFetchApp.getRequest(url,options); // (OPTIONAL) generate the request so you
console.info("Request payload: " + request.payload); // can examine it (useful for debugging)
var response = UrlFetchApp.fetch(url,options);
console.info("Response body: " + response.getContentText());
}