Fastify returns FST_ERR_CTP_INVALID_CONTENT_LENGTH - fastify

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

Related

Use supertest to create test with JSON and multipart/formData

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" }]))

Nodejs post Json data with headers

How to post Json data via node js either with form-data or via request ?
Using form-data. It does not allow to send custom headers and if replaced bodyParams.getHeaders() with custom headers it does not send request data
https://www.npmjs.com/package/form-data
const smsResponse = await request.post(url, bodyParams, {headers:bodyParams.getHeaders()})
Using Request it does not allow to send parameters
require('request');
const subscription = await request.post(url, body, {headers:{'Accept':'text/html'}})
Postman curl request It works via postman. tried to use postman nodejs request code but it fails
curl --location --request POST 'https://personalsite.com//test.php' \
--header 'accept: text/html' \
--header 'SECRET-TOKEN-MESSAGE: dataforport' \
--header 'Content-Type: application/json' \
--header 'Cookie: PHPSESSID=1d2shuebo7lal8sn2itgppvfk4' \
--data-raw '{
"mobileno": "888888888",
"messagetext": "Test message"
}'
Tried but it did not worked
Node.js: How to send headers with form data using request module?
Use new Headers() to build your header.
https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
var myHeaders = new Headers();
myHeaders.append('Accept', 'text/html');
var myInit = { method: 'POST',
headers: myHeaders,
mode: 'cors',
cache: 'default',
body: JSON.stringify({coffee: 'yes...'})
};
var myRequest = new Request('https://personalsite.com//test.php',myInit);
fetch(myRequest).then(function(response) {
console.log(response)
});

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.

How to forward file upload request to another domain in nodejs?

How to forward the upload request to another domain?
UI will send upload request to
curl -X POST \
http://localhost:4000/uploadFile \
-H 'Accept: */*' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Length: 814459' \
-H 'Host: localhost:4000' \
-H 'cache-control: no-cache' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F attachment1=#/C:/Users/superman/Desktop/tester.pdf
Need to attached 2 additional header and forward the request to
curl -X POST \
http://anotherdomain.com/anotherUploadFile \
-H 'Accept: */*' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'newheader1: headervalue1' \
-H 'newheader2: headervalue2' \
-H 'Content-Length: 814459' \
-H 'Host: anotherdomain.com' \
-H 'cache-control: no-cache' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F attachment1=#/C:/Users/superman/Desktop/tester.pdf
First you will save image in first domain then you will initiate a new post request that will get that saved image and will forward to next domain like below. I am using 'request' npm package for it
var options = { method: 'POST',
url: server2 url,
headers:
{
'cache-control': 'no-cache',
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' },
formData:
{
filename:
{ value: fs.createReadStream(req.file.path),
options: { filename: req.file.path, contentType: null } } } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
});

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

Resources