Use supertest to create test with JSON and multipart/formData - node.js

I need to test an endpoint like this:
curl -X 'POST' \
'http://localhost:3001/api/v1/gateways/sendPhoto' \
-H 'accept: */*' \
-H 'Authorization: Bearer xxx' \
-H 'Content-Type: multipart/form-data' \
-F 'targets=[
{
"target": "Telegram",
"channelId": "-xxx"
}
]' \
-F 'action=photo' \
-F 'message=<b>hello</b> World' \
-F 'filename=#Screenshot 2022-11-07 at 17.30.08.png;type=image/png'
the endpoint works and the authentication works as well in my test suite.
I'm trying to test this route in that way:
it('Create a picture message: /api/v1/gateways/sendPhoto (POST)', () => {
return request(app.getHttpServer())
.post('/gateways/sendPhoto')
.set('Content-Type', 'multipart/form-data')
.auth(newUserApiToken, {
type: 'bearer',
})
.expect(201)
.field('action', 'photo')
.field('message', "<b>hello Test!</b>"+Date.now())
.field("targets", JSON.stringify([{ "target": "Telegram","channelId": "xxxx" }]))
.attach("filename", imageCat)
.then(({ body }) => {
console.log(body)
});
});
and I get the 400 Status code.
I don't know if is possible to dump the "curl" from supertest in order to check if the request is ok.
My doubt is on
.field("targets", JSON.stringify([{ "target": "Telegram","channelId": "xxxx" }]))

Related

-F file=#foo.png equivalent in node fetch

I'm trying to perform an API call to Squarespace using node-fetch.
const FormData = new FormData();
formData.append(
"file",
"testimage.jpg",
fs.createReadStream("testimg.jpg")
);
const send_img = await fetch(
"https://api.squarespace.com/1.0/commerce/products/" + img_id + "/images",
{
method: "POST",
headers: {
Authorization: "Bearer " + process.env.SQUARESPACE_API_KEY,
"User-Agent": "foobar",
"Content-Type": "multipart/form-data",
},
body: formData,
}
);
After performing this call I was getting the error
{
type: 'INVALID_REQUEST_ERROR',
subtype: null,
message: "Expected exactly one file part named 'file', but found none.",
details: null,
contextId: 'IEBROFREUTEWDREAYEAF'
}
The following cURL call successfully uploads the image
curl "https://api.squarespace.com/1.0/commerce/products/63ab0ff8796311649603ee49/images" \
-i \;
-H "Authorization: Bearer <myAPIKey>" \
-H "User-Agent: foobar" \
-H "Content-Type: multipart/form-data" \
-X POST \
-F file=#testimg.png
What if -F and what is the equivalent of it in a fetch call?
Squarespace API reference:
https://developers.squarespace.com/commerce-apis/upload-product-image

routes with parameters on express mongodb and mongoose

Good evening,
I have a problem with my node express mongodb and mongoose server.
my routes with parameters do not work.
do we need to clarify or add something?
Very important
thank you
You are not receiving any data, because you are saving in mongodb the req.body attributes.
In order to do that you have to post data in request body.
Here is a curl example:
curl --location --request POST 'http://localhost:4000/signup/' \
--header 'Content-Type: application/json' \
--data-raw '{
"idade":123,
"nome":"teste",
"profissao":"programador top",
"email": "a#a.com"
}'
Also for return your data correctly you have to change a little your code from get request.
app.get('/user/:email', (req, res, next) => {
console.log("login 1", req.params);
User.findOne({ email: req.params.email })
.then(user => res.status(200).json(user))
.catch(error => res.status(404).json({ error }));
});
Here is a curl for a working get request:
curl --location --request GET 'http://localhost:4000/user/a#a.com' \
--header 'Content-Type: application/json'
Tested local and it is working with success.

Fastify returns FST_ERR_CTP_INVALID_CONTENT_LENGTH

I'm struggling with pretty weird error I'm getting from the Fastify on Node JS.
The server has a post service which is supposed to handle requests of gzipped JSONs body.
When I try to test it using curl or any other http client, I'm getting Request body size did not match Content-Length
My request does provide the Content-Length, the length of compressed file
curl -v -i http://127.0.0.1:8081/eventproxy/track -H 'Content-Encoding: gzip' -H "Content-Type: application/json" -H "Content-Length:479" --data-binary #sampleBatch.json.gz
I'm pretty sure it's related to the Fastify, but can't figure out what I'm missing. Any idea how to get it working.
Thanks
You need to change approach because the default content parser doesn't manage compression and will try to parse the body.
So to manage the compression you can overwrite the default addContentTypeParser and add the decompression logic:
const zlib = require('zlib')
const port = 8081
var fastify
fastify = require('fastify')({ logger: true })
/**
* Setup an fastify server and define port to listen all incoming requests for this application
*/
const setUpFastify = () => {
fastify.addContentTypeParser('application/json', { parseAs: 'buffer' }, function (req, body, done) {
if (req.headers['content-encoding'] && req.headers['content-encoding'] === 'gzip') {
zlib.gunzip(body, function (err, dezipped) {
if (err) {
done(err, null)
} else {
done(err, JSON.parse(dezipped.toString('utf-8')))
}
})
} else {
done(null, JSON.parse(body.toString('utf-8')))
}
})
fastify.post('/track', function (req, reply) {
reply.send(req.body)
})
fastify.listen(port, 'localhost', () => {
console.log('Worker listening on ' + port + ` PID: ${process.pid}`)
})
}
setUpFastify()
Note that fastify uses secure-json-parse to parse the json string.
And the curl, note the --data-binary:
curl --request POST \
--url http://127.0.0.1:8081/track \
--header 'Accept: */*' \
--header 'Accept-Encoding: gzip, deflate' \
--header 'Connection: keep-alive' \
--header 'Content-Encoding: gzip' \
--header 'Content-Length: 739' \
--header 'Content-Type: application/json' \
--header 'Host: 127.0.0.1:8081' \
--data-binary #package.json.gz
PS trying the curl with the #, the payload sent was 1-byte length

I can't get the linkedin access token with axios, keep getting status 400

The API says that status code 400 is probably syntax error, but I wasn't able to find it. I already have the authentication code and app credentials, and the url is registered.
I've tried with and without qs.
exports.getAccessToken = (req, res, next) => {
let payload = req.body;
let request_body = qs.stringify({
"grant_type": "authorization_code",
"code": payload.code,
"redirect_uri": linkedin.redirect_uri,
"client_id": linkedin.clientId,
"client_secret": linkedin.clientSecret
});
let config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
axios.post("https://www.linkedin.com/oauth/v2/accessToken", request_body, config).then(
response => {
res.json(response.data);
},
error => {
res.json(error);
}
);
}
You are using the wrong url to get accesstoken.
Step 1
First you need to use following url
curl -X GET \
'https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=[CLIENT_ID]&redirect_uri=https://getpostman.com/oauth2/callback&state=CA&scope=r_emailaddress%20r_ads%20w_organization_social%20rw_ads%20r_basicprofile%20r_liteprofile%20r_ads_reporting%20r_organization_social%20rw_organization_admin%20w_member_social' \
-H 'Postman-Token: 1c7d6199-f41b-43bc-b9ae-10d4bde0d968' \
-H 'cache-control: no-cache'
Response contains code which needs to used in Step 2
Step 2
use CODE received from Step 1
curl -X GET \
'https://www.linkedin.com/oauth/v2/accessToken?grant_type=authorization_code&code=[CODE]&redirect_uri=https://getpostman.com/oauth2/callback&client_id=[CLIENT_ID]&client_secret=[CLIENT_SECRET]' \
-H 'Postman-Token: f9542a93-fc9d-4cc4-aa38-a10f6cf2eb6f' \
-H 'cache-control: no-cache'
This will give you the access Token

--data-urlencode curl to Node.js request or express module

I am trying to transform this curl command
curl '<url>' -X POST \
--data-urlencode 'To=<phone>' \
--data-urlencode 'From=<phone>' \
--data-urlencode 'Body=<message>' \
-u '<user>:<pass>'
into this Node.js code
var request = require('request');
var options = {
url: 'url',
method: 'POST',
auth: {
'user': 'user',
'pass': 'pass'
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
}
request(options, callback);
I don't get how I can add the --data-urlencode option in the Node.js version of this code.
From curl documentation :
--data-urlencode
(HTTP) This posts data, similar to the other -d, --data options with
the exception that this performs URL-encoding.
So you would use form option to send form URL encoded like this :
var options = {
url: 'url',
method: 'POST',
auth: {
'user': 'user',
'pass': 'pass'
},
form: {
To: 'phone',
From: 'phone',
Body: 'message'
},
headers: {
'Accept': '*/*'
}
};
Note that you can use request-debug to show the actual request where you could check that body is :
To=phone&From=phone&Body=message
And to show the actual data sent by curl use as stated here, use --trace-ascii /dev/stdout :
curl '<url>' -X POST --data-urlencode "Body=<message>" -u <user>:<pass> --trace-ascii /dev/stdout

Resources