I want to make the following http request
POST /v1/images HTTP/1.1
Host: api.medium.com
Authorization: Bearer 181d415f34379af07b2c11d144dfbe35d
Content-Type: multipart/form-data; boundary=FormBoundaryXYZ
Accept: application/json
Accept-Charset: utf-8
--FormBoundaryXYZ
Content-Disposition: form-data; name="image"; filename="filename.png"
Content-Type: image/png
IMAGE_DATA
--FormBoundaryXYZ--
It is Medium API
I have attempted following.
var axios = require("axios")
var data = (await axios("https://example.com/image.png")).data;
axios.post("https://api.medium.com/v1/images",{image: data},{
headers: {
"Content-Type" : "multipart/form-data",
"Authorization" : "Bearer " + process.env.key
}
}).then(x=>console.log(x.data))
And I get following error.
Error: Request failed with status code 400
It uses Medium API to upload image, I want to fetch a remote image, and convert it into multipart/form-data and upload it via API, the HTTP request seems confusing, I want the equivalent axios code, someone please help?
Try using FormData instead of plain object?
Example should be like this
const formData = new FormData();
formData.append('image', data);
axios.post('https://api.medium.com/v1/images', formData, {
headers: {
"Content-Type" : "multipart/form-data",
"Authorization" : "Bearer " + process.env.key
}
});
Reference: How to post a file from a form with Axios
Related
I'm writing a REST API client that calls an API endpoint to obtain a PDF.
I'm using axios to consume the API:
const res = await axios({
method: 'GET',
url: url,
headers: {
'authorization': 'Bearer ' + at,
},
proxy: false,
httpsAgent: httpsAgent
});
console.log(res.data);
The response is of type multipart/form-data, in the following way:
content-type: multipart/form-data; boundary=95b77841-292d-4a0b-a689-787fcc0aa889
body:
--95b77841-292d-4a0b-a689-787fcc0aa889
Content-Disposition: form-data; name="metadata"
Content-Type: application/json
{"documentId":"123"}
--95b77841-292d-4a0b-a689-787fcc0aa889
Content-Disposition: form-data; name="document"; filename="document.pdf"
Content-Type: application/pdf
%PDF-1.4
....
%%EOF
--95b77841-292d-4a0b-a689-787fcc0aa889--
How can I save the 2nd part as a valid PDF file to disk?
I'm currently trying to implement Polar accesslink API on an app, but when trying to POST a new user I still get this error:
url: 'https://www.polaraccesslink.com/v3/users/',
status: 400,
statusText: 'Bad Request',
headers: Headers { [Symbol(map)]: [Object: null prototype] },
counter: 0
I already have the authorization token, which I know expires every 10min, and I'm using the service through a function that takes the token and the userID as parameters. This is my code:
postUser(memberId: string, token: string) {
const inputBody = { 'member-id': memberId };
const headers = {
'Content-Type': 'application/xml', 'Accept': 'application/json', 'Authorization': 'Bearer ' + token
};
const options = {
method: "POST",
headers: headers,
body: JSON.stringify(inputBody)
}
return new Promise<object>((resolve, reject) => {
fetch('https://www.polaraccesslink.com/v3/users', options)
.then(function(res: any) {
console.log(res)
return res.json();
}).then(function(body: any) {
console.log(body);
});
})
}
I'm implementing it the same way as it is specified in https://www.polar.com/accesslink-api/?javascript--nodejs#users but really don't know what might I be doing wrong. Thanks for helping me!.
I don't have experience with this specific API but i can see you send in the header Content-Type the value application/xml but the request body is JSON formatted.
Try send application/json in that header.
The Content-Type header is used in HTTP to specify the body mime type.
more info in: Content-Type HTTP Header - MDN
I also see this is the exact code in the sample but notice they have 2 sample requests and 2 sample results, one in XML and one in JSON each.
Any ideea why this POST gives 'invalid_Request'?
curl --location --request POST 'https://polarremote.com/v2/oauth2/token?grant_type=authorization_code&code=1f9edc0c5e60a0bab4fd3f1f00571a58' --header 'Authorization: Basic ... DA4OS05ZDc2LTJlNTQwZjFkZTc5ZA==' --header 'Content-Type: application/x-www-form-urlencoded' --header 'Accept: application/json'
const form_data = new FormData();
form_data.append("File", fs.createReadStream(pathToFile));
form_data.append('Login', alias.toUpperCase());
const request_config = {
headers: {
"Authorization": "Basic 123",
"Content-Type": 'multipart/form-data'
},
data: form_data
};
await axios.post(url, params, request_config).then(response => {
Posting to an endpoint I can't debug. The response is a 500.
This is the error:
Is this the correct way do it?
Can I somehow see exactly what Axios is sending?
This is a postman request I received from the author of the API. This passes:
POST /api/upload HTTP/1.1
Host: api.test.contoso.se
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Authorization: Basic 123
User-Agent: PostmanRuntime/7.13.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 089af753-fa12-46c4-326f-dfc39c36faab,c5977145-ece3-4b53-93ff-057788eb0dcf
Host: api.test.contoso.se
accept-encoding: gzip, deflate
content-length: 18354
Connection: keep-alive
cache-control: no-cache
Content-Disposition: form-data; name="Lang"
SV
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Content-Disposition: form-data; name="File"; filename="/C:/Users/file.docx
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Content-Disposition: form-data; name="Login"
ABC
The error message in your screenshot is clear: "Missing content-type boundary".
To use axios for multipart/form-data request, you need to set boundary to upload the file. Example code is:
const form_data = new FormData();
...
const request_config = {
headers: {
"Authorization": "Basic 123",
"Content-Type": 'multipart/form-data; boundary=' + form._boundary
},
data: form_data
};
await axios.post(...)
"Can I somehow see exactly what Axios is sending?"
You can use HTTP proxy software such as Charles to intercept the request, and check what data is sent.
This is a CURL example which works fine:
curl -X POST \
<url> \
-H 'authorization: Bearer <token>' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F file=#algorithm.jpg \
-F userId=<userId>
I'm trying to reproduce this request using isomorphic-fetch.
I've tried the following code:
const formData = new FormData();
formData.append('file', file);
formData.append('userId', userId);
return fetch(`<url>`, {
method: 'POST',
headers: {
'Content-Length': file.length
'Authorization: Bearer <authorization token>',
'Content-Type': 'multipart/form-data'
},
body: formData
})`
I use fs.readFileSync in order to generate the file passed to FormData.
The previous example returns a 401 HTTP status code (unauthorized) with an error message saying that the userId embedded in the token (sent via header) does not match the userId passed from formData.
So my suspicion is that the FormData that arrives to the REST API is not adequately formed.
The problem may be related with the Content-Length header, but I didn't find a better way to calculate it (if I don't use the Content-Length header I get a 411 HTTP status code Content-Length header missing).
Could be the case that this is failing because of an incorrect value in the Content-Length header?
Any other suggestions on why this is failing or how to better debug it?
If further info is needed to clarify this problem, please just ask.
UPDATE
I've tried the form-data module in order to get the right Content-Length value using the method formData.getLengthSync()
However the problem remains the same (401 error HTTP status code response).
Just remove the Content-Length and Content-Type headers from your code as these headers will be set automatically by the browser.
If you open up your network inspector, run this code snippet, and submit the form you should see that the Content-Length is set correctly:
const foo = document.getElementById('foo')
foo.addEventListener('submit', (e) => {
e.preventDefault()
const formData = new FormData(foo)
formData.append('userId', 123)
fetch('//example.com', {
method: 'POST',
body: formData
})
})
<form id="foo">
<input id="file" type="file" name="file"/><br><br>
<button type="submit">Submit</button>
</form>
I hit my head against a similar wall, specifically using isomorphic-fetch on node to POST a multipart form. The key for me was finding .getHeaders(). Note that NPM description for form-data suggests that it'll "just work" without this, but it doesn't seem to, at least not in node (I think browsers inject header stuff?).
// image is a Buffer containing a PNG image
// auth is the authorization token
const form_data = new FormData();
form_data.append("image", png, {
filename: `image.png`,
contentType: 'application/octet-stream',
mimeType: 'application/octet-stream'
});
const headers = Object.assign({
'Accept': 'application/json',
'Authorization': auth,
}, form_data.getHeaders());
try {
const image_res = await fetch(url, {
method: 'POST',
headers: headers,
body: form_data
});
if (!image_res.ok) {
const out = await image_res.json();
console.dir(out);
return;
}
}
catch (e) {
console.error(`Chart image generation exception: ${e}`);
}
I'm trying to use the request.jslibrary to upload a file to box.com using request.post.
I consistently get a return code of 400 and a null body in the response. Not sure how to get at the actual error that box is seeing. The err argument to the callback is null, so there is a response from box.com, but with a statuscode of 400 and a null body.
FYI, the upload succeeds using curl, so the auth token etc. is fine.
I pointed the function below to http://echo.200please.com', and it seems the HTTP POST request I'm sending out is fine.
How do I get to see what error is being seen by box?
request = require"request");
UploadFile = function(filename, callback) {
var formData = {
attributes: JSON.stringify( {
name: filename,
parent: { id: '' + 2764913765 }
}),
file: fs.createReadStream('./temp.bin')
}
var options = {
url: 'https://upload.box.com/api/2.0/files.content',
headers: { Authorization: 'Bearer ' + tokens.access_token},
formData: formData
}
request.post(options,
function(err, response, body) {
if (err) {
console.log('Error Uploading the file');
} else {
console.log('returned:' + body + JSON.stringify(response.headers))
}
});
If I change the URL to point to echo.200please.com, the response I get from echo.200please.com is below, which seems to be the correct format for a file upload request.
> POST / HTTP/1.0
Host: echo.200please.com
Connection: close
Content-Length: 1951
Authorization: Bearer bVPDzG8PgIVRNoqb5LOzD61h6NXhJ6h0
content-type: multipart/form-data; boundary=--------------------------799592280904953105406767
----------------------------799592280904953105406767
Content-Disposition: form-data; name="attributes"
{"name":"testchunkname.1","parent":{"id":"2764913765"}}
----------------------------799592280904953105406767
Content-Disposition: form-data; name="file"; filename="temp.bin"
Content-Type: application/octet-stream
<... file data ...>
OK ... I found the bug :-)
It's a typo in the url
in my program it got set to api/2.0/files.content whereas the correct path in the url should be api/2.0/files/content