Fastify get item by title always returning raw JSON as null - fastify

I'm just starting with Fastify and ran into an issue where I started creating a get request to get an item by its title, but it keeps giving me a response of null when I try and log the request.body.
My get request:
// Get points by title
fastify.route({
method: 'GET',
url: '/pointz/title',
handler: (request, reply) => {
return request.body
}
})
My get request in postman (as code):
curl --location --request GET 'http://localhost:3000/pointz/title' \
--header 'Content-Type: application/json' \
--data-raw '{
"title": "test"
}'
Screenshot of my input and output in Postman
The expected result would be that the request returns a body that contains the JSON that's being sent, so I can change the code to access request.body.title with a return value of test.
UPDATE:
Found a workaround for now. If I change the GET request to a POST request it works just like it's supposed to. I question however if this is considered good practice.

As discussed in this GitHub Issue GET request validated scheme body?
the body should not be send in GET request, a datailed answer about it
and fastify ignore it by default.
But legacy code does, and if you need to support it, you have to consume the raw request:
const fastify = require('fastify')({ logger: true })
fastify.get('/', async (req) => {
let body = ''
for await (const data of req.raw) {
body += data.toString()
}
return body
})
fastify.listen(3000)
Then your curl command will works as expected.
const got = require('got')
got.get('http://localhost:3000/', {
json: { hello: 'world' },
allowGetBody: true
}).then(res => {
console.log('Returned = ' + res.body)
})

Related

Imgix Purge Post Request fails for unknown reason

I wanna purge an image from the imgix cache, they have a API for that (https://docs.imgix.com/setup/purging-images)
I use axios to make the request from my nodejs backend:
const imgixKey = functions.config().imgix.key;
const headers = {
Authorization: `Bearer ${imgixKey}`,
'Content-Type': 'application/json',
};
const data = JSON.stringify({
type: 'purges',
attributes: {
url: href,
source_id: 'SOsourceId',
},
});
try {
await axios.post('https://api.imgix.com/api/v1/purge', data, { headers });
functions.logger.log('Purged Image successfully' + href);
} catch (e) {
functions.logger.error('Error removing image from cache ' + href + ' -> ' + e);
}
Error removing image from cache {stackoverflowimgpath.png} -> Error: Request failed with status code 400
The problem is other than the status code 400 there is nothing else specified, I checked the image paths and tried different Content-Type headers like in their example but that also did not work.
Since I cannot get any more information out of the response I ask for help here since I do not know how to continue.
Checking imgix documentation, the body of your request should have a data property:
curl -X POST 'https://api.imgix.com/api/v1/purge' \
--header 'Authorization: Bearer <api-key>' \
--header 'Content-Type: application/vnd.api+json' \
--data-raw '{ "data": { "attributes": { "url": "<url-to-purge>" }, "type": "purges" } }'
So, just modify your message to (adding the data property to your json object):
const data = JSON.stringify({
data: {
type: 'purges',
attributes: {
url: href,
source_id: 'SOsourceId',
},
}
});

Axios Basic Auth with API key Example in Node

There is a curl request like this:
curl -X GET --header 'Accept: application/json' --header 'Authorization: Basic [==APIKEYHERE==]' 'https://apipath.com/path?verbose=true'
I removed the APIKEY and the API path for privacy.
The curl request is working fine, I can't figure out how to convert this into an Axios request since it only needs an API key and not a username and password.
Here is the example I found:
axios.get('https://apipath.com/path?verbose=true', {}, {auth: {username: 'username', password: 'password'}})
.then(function(response) {
console.log(response.data, 'api response');
})
I'm not sure how to get this to work for my case?
The short answer to adding an X-Api-Key to an http request with axios can be summed up with the following example:
const url =
"https://someweirdawssubdomain.execute-api.us-east-9.amazonaws.com/prod/custom-endpoint";
const config = {
headers: {
"Content-Type": "application/json",
},
};
// Add Your Key Here!!!
axios.defaults.headers.common = {
"X-API-Key": "******this_is_a_secret_api_key**********",
};
const smsD = await axios({
method: "post",
url: url,
data: {
message: "Some message to a lonely_server",
},
config,
});
I was stuck for 8 hours trying to figure this out as the errors lined up in the queue, adding the key to the default headers was the only way I could get this to work.
Given the cURL command including --header 'Authorization: Basic [==APIKEYHERE==]', you know that the server wants a header sent using the Basic authentication scheme. That means that your API key is both the username and password joined by a : and encoded with Base64. So, you can decode what the username and password should be by decoding your API key with Base64 and seeing the values joined by the colon.
Consider the spec detailed on MDN: Authorization Header
So if your API key is Ym9iOnBhc3N3b3JkMQ==, and you decode it with Buffer.from("API_KEY", "base64").toString(), you would get the value bob:password1 meaning your username is bob and your password is password1 making your request:
const [username, password] = Buffer.from("YOUR_API_KEY", "base64").toString().split(":");
axios.get('https://apipath.com/path?verbose=true', {}, {
auth: {
username,
password
}
})
.then(function(response) {
console.log(response.data, 'api response');
})
You can define a function like this, then you can pass the token to header after login success.
import axios from "axios";
const setAuthToken = token => {
if (token) {
// Apply to every request
axios.defaults.headers.common["Authorization"] = token;
} else {
// Delete auth header
delete axios.defaults.headers.common["Authorization"];
}
};
axios.get('https://apipath.com/path?verbose=true', {}, {auth: {username: 'username', password: 'password'}})
.then(() => setAuthToken(response.token));

How to check for plain text response from a POST request?

I'm trying to use frisby.js to specify an API test for an endpoint that returns a plain text response to a valid POST request. However I'm having problems getting frysby.js to accept non-JSON response documents. Whenever a response returns non-JSON content, throw a TypeError due to 'Unexpected token b in JSON at position 0'.
As an example, I'm sending a HTTP POST request with the JSON document shown below is expected to return a response with a plaintext document with the string bar.
{
"foo":{
"name":"bar"
}
}
Here's the unit test that I've wrote to verify the response:
it('should create a foo resource', function () {
return frisby.post('http://localhost:8080/',
{
"foo":{
"name":"bar"
}
})
.expect('status',201);
});
Unfortunately, the following error is thrown by frisby.js when I run the test:
FAIL ./test.js
✕ should create a foo resource (17ms)
● should create a foo resource
TypeError: Invalid json response body: 'bar' at http://localhost:8080/ reason: 'Unexpected token b in JSON at position 0'
Does anyone know if it's possible to configure each test to expect some data format other than JSON?
If you getting JSON + something then break jsonTypes in two format like one for JSON object and one for other, like it having array in JSON objects.
and then put expect conditions on them.
This might helps you:
const frisby = require('frisby');
const Joi = frisby.Joi;
frisby.globalSetup({
headers : {
"Accept": "application/json",
"content-type" : "application/json",
}
});
it("should create a foo resource", function () {
frisby.post("http://localhost:8080/")
.expect("status", 200)
.expect("header", "content-type", "application/json; charset=utf-8")
.expect("jsonTypes", "data.foo", {
"name": Joi.string()
})
.then(function(res) { // res = FrisbyResponse object
var body = res.body;
body = JSON.parse(body);
expect(body.data.foo.name).toBeDefined();
})
});

Post request with Node fails but works with Python

I'm trying to use a sentiment analysis API for some tweets I've streamed. The API in question is this: http://sentiment.vivekn.com/docs/api/. I've done this before in Python before and it worked as expected. I made a post request using the requests library and sent a JSON object with my content. The JSON object looked something like this:
{
"txt": "The content of the tweet."
}
In Python, sending the post request looked something like this:
url = "http://sentiment.vivekn.com/api/text/"
data_dict = {
"txt": "hi"
}
r = requests.post(url,json.loads(json.dumps(data_dict)))
print(r.text)
Now I'll admit I'm new to Javascript and web based programming in general, but I assume the logic should be similar in both languages. I tried using the XMLHttpRequest method but it always returned an internal server error with status code: 500.
The website works, it takes post requests and responds with the analysis, but I can't get it to work with Node. This is what I'm working with in Javascript:
const rp = require('request-promise');
var options = {
method: 'POST',
uri: 'http://sentiment.vivekn.com/api/text/',
body: {
"txt": "This is a very negative sentence, so we should get a negative analysis!"
},
json: true // Automatically stringifies the body to JSON
};
rp(options)
.then(function (parsedBody) {
console.log("Request received");
console.log(parsedBody);
})
.catch(function (err) {
console.log("Something went wrong\n" + err);
});
It always catches an error with status code 500. I've tried several other methods including making the request with XMLHttpRequest. Nothing seems to work. It would be great if someone could point out where I'm going wrong.
This isn't an answer, but I thought it useful to show some code that evokes a different response, which may be a clue that will help debug the problem.
I get the same response with curl:
jim-macbookpro:~/development/node/so$ curl -X POST 'http://sentiment.vivekn.com/api/text/' -H "Content-Type: application/json" -d '{"txt": "hi"}'
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in theapplication.</p>
I changed the example to use 'node-fetch', and I don't get 500, rather I get 405 - METHOD NOT ALLOWED.
My suspicion is that this is a problem with the server being somehow very particular about the format of the request.
I hope this helps.
const fetch = require('node-fetch');
fetch('http://sentiment.vivekn.com/api/text', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
txt:
'This is a very negative sentence, so we should get a negative analysis!'
})
})
.then(function(parsedBody) {
console.log('Request received');
console.log(parsedBody);
})
.catch(function(err) {
console.log('Something went wrong\n' + err);
});

Slack Webhook - Getting Invalid_Payload

I am attempting to set up a webhook to Slack, but am getting an Error message of "Invalid_Payload"
I've looked through Stack, Slack, and Github... but cant' find the answer I seek.
"CustomLink" in there for privacy, actual link is begin used.
CODE:
var request = require('request')
var webhook = "https://hooks.slack.com/services/CUSTOMLINK"
var payload={"text":"This is via an integration from Me - It is a test"}
request.post({url: webhook, payload: payload}, function(err, res){
if(err){console.log(err)}
if(res){console.log(res.body)}
})
ERROR:
invalid_payload
var payload= {"text":"This is via an integration from Me - It is a test"}
payload = JSON.stringify(payload)
I had forgot to stringify the JSON I was creating. Stupid Me.
This worked for me
var payload = {"text":"Message to be sent"}
payload = JSON.stringify(payload);
request.post({url: url, body: payload},function(err,data){
console.log(data.body);
})
My guess is that you are missing the Content-type: application/json header. Then it doesn't recognize the json you are sending as json correctly.
You could try:
var request = require('request')
var webhook = "https://hooks.slack.com/services/CUSTOMLINK"
var payload={"text":"This is via an integration from Me - It is a test"}
var headers = {"Content-type": "application/json"}
request.post({url: webhook, payload: payload, headers: headers}, function(err, res){
if(err){console.log(err)}
if(res){console.log(res.body)}
})
Check the "Send it directly in JSON" here for reference
var request = require('request');
var apiurl = webhookurl;
var payload= {
username:'myusername',
text:'test'
}
payload = JSON.stringify(payload);
request.post(
{
url:apiurl,
form:payload
}, function (err, result, body) {
if(err) {
return err;
} else {
console.log(body);
}
});
Try with postman for sending the post request by using your webhook as URL and under body use raw and use { "text":"hello" } and follow the following image:
or use this curl command:
curl --location --request POST 'https://hooks.slack.com/services/o1GLCDvsanqNDqMHCBQAd7F3' \
--header 'Content-Type: application/json' \
--data-raw '{
"text": "hello"
}'

Resources