NodeJS - Send JSON object parameters with node-fetch - javascript

I'm trying to create a webhook via the GitHub API. The docs say that I need to provide a config parameter, which should be an object, but I'm not sure how I can send a JSON in the URL parameters. Here's what I've tried:
fetch(`https://api.github.com/repos/${repo.full_name}/hooks?config={"url": "https://webhooks.example.com", "content_type": "json"}`, {
method: "POST",
headers: {
Accept: "application/vnd.github.v3+json",
Authorization: `token ${account.accessToken}`
}
});
and
fetch(`https://api.github.com/repos/${repo.full_name}/hooks?config.url=https://webhooks.example.com&config.content_type=json`, {
method: "POST",
headers: {
Accept: "application/vnd.github.v3+json",
Authorization: `token ${account.accessToken}`
}
});
They both result in the following error:
{
"message": "Validation Failed",
"errors": [
{
"resource": "Hook",
"code": "custom",
"message": "Config must contain URL for webhooks"
}
],
"documentation_url": "https://developer.github.com/v3/repos/hooks/#create-a-hook"
}
How do I properly send a JSON object? I'm looking for a solution using node-fetch

When you are doing a post request, it's implied that there will be a payload and the lib you are using will be expecting a body property containing your payload.
So just add
fetch('https://api.github.com/repos/${repo.full_name}/hooks', {
method: "POST",
headers: {
Accept: "application/vnd.github.v3+json",
Authorization: `token ${account.accessToken}`
},
body:JSON.stringify(yourJSON) //here this is how you send your datas
});
And node-fetch will send your body with your request.
If you want more details on that i'll expand my answer
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods here for a quick description of different http request type (verb)

Related

AppSync HTTP Resolver IAM Authorization Error

I am trying to use http resolvers with AWS AppSync so that we can support using graphQL and our REST APIs simultaneously. I got the AppSync http resolver working when the API Gateway did not have any authorization setup on it. However, I've now locked down the gateway with IAM and I am trying to call it with the http resolver.
Using Axios, I am able to call the API Gateway with and I get a good 200 response with these params.
Request Params
{
"body": "{\"id\":1234}",
"data": "{\"id\":1234}",
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"x-amz-date": "20190209T101242Z",
"X-Amz-Security-Token": "AgoGb3JpZ2luEF4aCXVzLWVhc3QtMSKAAh9+SISFQH3bbHNLD47h5yCUsPmQhQ4Td74A1HmI/2jSu/Mg8mvK5IiMAMAMXokFQF8hZfzqsjfNWs+GcYkDRqhJbk7uaEaZFpjn5urgDAKVP/m5gywvnLnMWUXSOxTKe0kX+wTwHgnrV1wKR4+Fo97ykZPDasOPddw7HzSr9i2xKlKWEFB5iliZ08zvvA1OKUQ9gNdv6i+Cfwph/XGt0J7xvFtuYfOyZ5QRlyzggjS9cYbdaQ05A5vd+vAuDsdM7WXrU4OFN1ykRyw29VJU6eGFZTmBDX1AH7qI44ggjvwPOVUC/syAktuHgqqrADjleGdkRj0jZ+VoCybxAQYJEAQqpgUIcxAAGgw0OTc5OTY0NTMyNDgiDM9ufuhpC5ebbAUHHiqDBQ8P5DRX/leNqZEVIfcGahfFH6QfK9GZYDyW7iAVxHTEAL0ebMKi4Xo+vfatiISGgbTJuSB/csXvECTFkkuU1TNK21knO/WD5dWIIcKTSdQjZITMMtvTWk5JQWCFPrJ6ya6WENME3aYhfxXdCMuyL0EyFhx7A2J+GfukovfLRIU/CJl6GsyxSz0twNdBB71m7izPQ3rjN0ihNNayLWAfLhcU93Zq38BSavIesLYvqCpSYFH0fXrzhYaS+PRgKpvhgyR0r495OIIJfmSrMUZ2JZ/ct6YXanZCbEcFEwk91KPQDuG/NZhZcLpSPafU/HqkvaZ6gHSUpAR3jAi6XpLpaXHKS0vQnWV1ORnuIS/j9piDKe3HD42PsII9vgB69fZJK7wHImrqWwo9iKgHpiAYpJhs9K7lcznZ440NpjcA7VMBGBrvpFnLLv/VhTLVsYdNAeVfXMBshhEVsFVHvQstE/PHVvPTNMbk1eQwObKpQ/nprABPc4xWSKeF8w9TggwBrxemkDv+P0LhWqGso6WRssLH3GoKRE9znEawhvlxIbtDGJI38/j++zRTcreuduwbD29t+1pEk/5KJAnyxcQZmzTPlPTCA/TgRkeCEcOn7Xx/OZnG5137yK65xvHb2n1tPJsIDOlsD0AFP6me21sNkl5R4me746CR3ki0XUdIh4hPocKvlW+g32uWGBd6PMe+YwrCq8mD0NMxK3kgNMBtzX5IAyw51VTOIr01xCWrSegRbBtflYRtyHee2js3gu9N3ZfGHX13MDwvZi1WCfTDx3eP6wuPM4qcnJF/WBbkRU16PH8/Agkgxt5fQ4yaOOPv38GD1TRkGvWyshE2DJCilw27Qm8wms/64gU=",
"Authorization": "AWS4-HMAC-SHA256 Credential=ASIAXH4XG2WACM4YOUAC/20190209/us-east-1/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token, Signature=3b72f69aa94fe41026a7d8806cccfe50dd24b247df6681065435f7eba135d02e"
},
"method": "POST",
"path": "/Prod/test",
"url": "https://q1gyu9a0he.execute-api.us-east-1.amazonaws.com/Prod/test"
}
Response
{
"data": "Hello from Lambda!",
"status": 200,
"statusText": "OK",
"headers": {
"content-type": "application/json"
},
"config": {
"transformRequest": {},
"transformResponse": {},
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json; charset=UTF-8",
"x-amz-date": "20190209T101418Z",
"X-Amz-Security-Token": "AgoGb3JpZ2luEF4aCXVzLWVhc3QtMSKAAoEkajE677gfDz3UMEhI27lvIHgikCQIVivGmUBKwcIjfz+JH9z4ILd/HBp2i/fFwtOjUNpo0fFnJeN73QkY18BRdtuTwtbBmS0B+kcOIvkaZnNMVEinUFIANxRxvhLET7koVenwtsGY+Tppv5NaUPNw5RERr1pzCO7HgeiQixG2rToTrqsiYCNLvTHTuojHSHZpISXdpV7vusWzjFJTQgR+sSvo9kjNYUBzbLCCBxmVv0KFzEf8dzxUEP2N92aExKW7cq98wakh440vt3gfpkG7Yg/wkGmABnwSgUlP2IVF7717oN7yoTlFFul1EDUwJs/VvWkueGUnfKRMKXkGg74qpgUIcxAAGgw0OTc5OTY0NTMyNDgiDN9R1UCNsLAVF3x6lyqDBXcq3VNhWLCYe8jpUgM2j9AMzyK6eS7LBAgaAYQiisdcFSVmMDIYL2AeMzgX/76UjaA73MFOKPmfBR4hrzk0wnwOjpz/FlLwU47teaqtjZZoxlTtk8X7xLj7wk5j6XnLRRjpOBXmVytEzTst4yKnFxFR2PDACFZfuPF+VPWPEttJ3eGuDAPITQPXvRUnpc+kl04BZsb72w31zP7kFl1EQqabJpz2ie41ObQbp4DZ9XhSzWrQvrovnu/mG0m6cWJeXG03Xee7SHmAVMAsvrpZ0OeBFl4nY4HM8L2SHiivwX/NnAkrrKxjO07ARunp4k30jxkZi0xQISp0qowboovVP0uPwQTwDty4FaT2EN+5CqJVqXGLioKo2GG1wjCAwinUcYt8iCq1A1lcTf2boYEjqmZyJ0apQAsNeD/wa0dqfKM5BwBz4G/JyxDo/tvtJ93RlcKg4rhaEf0NvsFvoHve0sUNJXh/LsGK4aZpkNS3Kbgrc8PZ2CsYADRW7b5V8uk8WAQ207SRHi8SUXWlDp9dYLgsQ2AUiUwel5Ph2iyKWxAVZ+h32Wmx6W2PJ8L9jWZsdmH7DYFwpWHpn8GmicXkSdVXnLD6WwaVtvDRjr8CKNrY/HZvyxU7zrRKFX141pEhEyzmyNboUR1XFRXvSnCoRxtBbIGgsTLjEpcdpCKWrwxplPVMY1MI/oD4waFJrJaO78VOy/2h0FylwaI4PVONgSkw2VWk4dD0Okr71Jx9A2h1P4zC3PnyUc6rfj5sk8ZabYShuY3WTIjW+j4j8ApEdjEAv8uguEoF9t4F4/3gt0g/0WAU1wX5kNGfpphpmeE6Do0rPCdlW3JDqNiZ7arsrAFgRSIw+s/64gU=",
"Authorization": "AWS4-HMAC-SHA256 Credential=ASIAXH4XG2WAC2MDEECX/20190209/us-east-1/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token, Signature=664af118dadc082a7fa72a7e51266c2e42fcd3a4a83813032087898490a3eeca"
},
"method": "post",
"body": "{\"id\":1234}",
"data": "{\"id\":1234}",
"path": "/Prod/test",
"url": "https://q1gyu9a0he.execute-api.us-east-1.amazonaws.com/Prod/test"
},
"request": {}
}
Using AppSync with the following http resolver request mapping template, I am able to call the API Gateway as long as it is not configured to authorize with IAM.
HTTP Resolver Request Mapping Template
{
"version": "2018-05-29",
"method": "POST",
## E.G. if full path is https://api.xxxxxxxxx.com/posts then resourcePath would be /posts **
"resourcePath": "/Prod/test",
"params":{
"body":$util.toJson($ctx.args)
}
}
Working Response
{
"data": {
"test": "Hello from Lambda!"
}
}
Now I'm trying to call the API Gateway with the http resolver after I lock down the gateway with IAM. I use the following request mapping template to try and pass the fields and headers required, but I get an error. Not really sure where to go from here.
Request Mapping Template Trying for IAM
{
"version": "2018-05-29",
"method": "POST",
## E.G. if full path is https://api.xxxxxxxxx.com/posts then resourcePath would be /posts **
"resourcePath": "/Prod/test",
"params":{
"body":$util.toJson($ctx.args),
"headers":{
"Authorization": "$ctx.request.headers.httpAuth",
"Content-Type": "$ctx.request.headers.conType",
"X-Amz-Security-Token": "$ctx.request.headers.secToken",
"x-amz-date": "$ctx.request.headers.newDate"
}
}
}
Error Received
"{message=The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The Canonical String for this request should have been
'POST
/Prod/test
content-type:application/json; charset=UTF-8
host:q1gyu9a0he.execute-api.us-east-1.amazonaws.com
x-amz-date:20190209T103353Z
x-amz-security-token:AgoGb3JpZ2luEF4aCXVzLWVhc3QtMSKAAi+vyglsAoh1DSzupAqx2f+vbwUM9PicHyM3p8IHX5VG3rZqH4sGlAu8SsAWtnmHeqYdjoQ7CESKAr9qjL7Vg07ooYnGNeuoHA4hiZghN9Y6iFOVcM2zA7bTGTN2RCmxYsJZ965dX1N0BpvvUcN6fDr8PP7Zoo1crt0e4DD3N/4yjZNYcor1sv58fkicTRTwQp5CYtVn5nQ9vsLg+4QW1btsKIhjsbgRYXGhD2kmJc8nhQvPJp9wq0AlL4FjECToWE7Gpo/C358sQvOHBqbxrFqduAIi4eCW8yrJQ9Az17BB0FlyvUpPAwDsWDprB3AvIZnFIDnZAjNv1bjY+OxCyqkqpgUIdBAAGgw0OTc5OTY0NTMyNDgiDE7sXyPsvDNEdskDXiqDBYgF4RTqVkYl5HJv+W8hk3VPMaMPkiEgpOvfryaDgN94rfr2RjNDnQA/r9QrL1TLn8SYG5v0IMnpW1jEUUN4PVxZUL/LB/8UpaMUCbviMy0Mz8e3PdOPpMShCbkL/iMS8jxOWXNgN3Y0Pjr2sivkndTpuIV44JvMG2UON57Vxxjl55KS7FT2jQMIBx7FAGe8nwYY/hYdl6dbzudHIjZuofOWjr5KPaAS38FTyXQGcqo+SaQHHDd9gUnYhRwtHy9pepPFwPY9BGJzW2hnS54jYixaZnwf+wewyALkXi3t749jPVDk0jyXMHgO57lK8lqqL3GL9GxQEMq0Ebga3nUuL8tuOLlOU5qrvS6l0fiTUkOZuwX2/Tkr6dc3cn12m9L3aNfg0UlAO2cR1ginMux6HIwmaeh2ycbmbR2zWd6ObRjDTc573zzX5x/sXkMWkOunR7B7NtAnMlbcNzQmf7KlAVzaP2f42V2e1HGjyJLHhCqGV9alf8Nj+BKi4njIZQHb/KxnmnZ+ZJcyn0DVtvFM+h/0eylAVXFwQh8TP7rVNsI72gtxiC39mWdJ7xKoqbX1jSjfjE8JBej2SEbYrXI/m2043Mv02sfgzHcOWDl7NFw+7zGScwVSBjkEYL8f55U1HbRrP1CuJYo7OlL8Y/0KxttfK6vPK7BLUAe9UpT0Yzh7Fz/5OXDs7n9s94iHRhOFj038akBB/Ye2v5fBEkPBbmGelD+7CGVNmMKgpnqHlzNpm3q3Gu2tcElSuF/3kUm4Eg0ElJbsRDEnsy5qhWt1fpeBrscpsfyifnZZOHL7enen0cK/iJY8SeJFnImj6eNhL/ymOrV1Sls90JF89F3tZfUvAGkwkdn64gU=
content-type;host;x-amz-date;x-amz-security-token
583ff6a2cabb532c16553f12958ec329caf1fe48d171d529b5e144f7a2c3f8f5'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20190209T103353Z
20190209/us-east-1/execute-api/aws4_request
2dcd7c552c2fec47b88e6f7d711b9a61879d8a12fc327a1a3f327287405ca0e5'
}"
AppSync can also compute the sigv4 signature required by Api Gateway on your behalf if you are using HTTP resolvers.
The configuration changes to your HTTP data source are not available through the console but using the AWS CLI you can pass the following paramaters:
aws appsync update-data-source --api-id yojcj4cdzzhizkscqocnr5xhem --name ApiGatewayTest --type HTTP --service-role-arn arn:aws:iam::769682826941:role/ApiGatewayRole --http-config file:///home/yourdir/apigateway.json
and the json file containing:
{
"endpoint": "https://apigateway.us-east-1.amazonaws.com/",
"authorizationConfig": {
"authorizationType": "AWS_IAM",
"awsIamConfig": {
"signingRegion": "us-east-1",
"signingServiceName": "apigateway"
}
}
}
AppSync does assume role on the role you provide, so it needs to allow AppSync to assume the role and call your API Gateway API.
You can find more info about the headers API Gateway expects in their documentation, here:
https://docs.aws.amazon.com/apigateway/api-reference/signing-requests/

When sending POST request to backend API via fetch(), the body has only key and no value

When I'm sending a POST request to my backend express server, the req.body contains only the key part where the entire body is the key and the value part is empty
This is the frontend fetch request
let data = {
videoUrl: "dummy text"
}
fetch("/api/getinfo", {
method:"POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: JSON.stringify(data)
})
This is how I handle it in backend (NOTE: I'm using body-parser)
app.post("/api/getinfo", (req,res) => {
console.log(req.body);
}
I expect the output to be
'{ "videoUrl":"dummy text" }'
But what I get is
{ '{"videoUrl":"dummy text"}': '' }
The entire requests body is the key, and the value is empty.
What am I doing wrong?
You are using the wrong Content-Type to send json
Try
"Content-Type": "application/json;charset=UTF-8"
I noticed an issue in your header;
fetch("/api/getinfo", {
method:"POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" //this very line
},
I guess what you meant is
fetch("/api/getinfo", {
method:"POST",
headers: {
'Content-type': 'application/json; charset=utf-8'
},
Note: Your header denotes what the content is encoded in. It is not necessarily possible to deduce the type of the content from the content itself, i.e. you can't necessarily just look at the content and know what to do with it. So you need to be sure of what you're writing in your header else you will end up with an error.
I will suggest you get to read more about What does “Content-type: application/json; charset=utf-8” really mean?
The problem is that you are stringifying the data:
body: JSON.stringify(data)
should be
body: data
That should fix it

Posting data to django rest framework using javascript fetch

I'm trying to post data to my django rest framework using javascript fetch. I've already set up and liked the DRF to my model and got everything set up from the backend. I used the postman app to ensure "get", "post" etc are all working as interned. However, now I'm having problem posting data using javascript to post the data using fetch. I want to add data to my article model which has a "headline", "tag", "content", "background_image" and the user that posted the article.
This is how my code looks like
data = JSON.stringify({
headline: "Testing",
tag: "Testing",
background_image: "Testing",
content: "Testing",
user: 1
})
fetch(
"http://127.0.0.1:8000/api/v1/articlesapi/",
{
method: "post",
headers: {"Authorization":"Token ed73db9bf18f3c3067be926d5ab64cec9bcb9c5e"},
body: data
}
).then(function(response) {
return response.json();
}).then(function(data) {
console.log("Data is ok", data);
}).catch(function(ex) {
console.log("parsing failed", ex);
})
However, I keep getting the error parsing failed TypeError: Failed to fetch. Does anybody know what I'm doing wrong ?
Please add "Content Type" and "Accept" properties in your header, I think it could be a reason of your error. Let me know if it works :-)
fetch('"http://127.0.0.1:8000/api/v1/articlesapi/', {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'Authorization':'Token ed73db9bf18f3c3067be926d5ab64cec9bcb9c5e'
},
body: JSON.stringify({data: "your data"})
}).then(res=>res.json())
.then(res => console.log(res));

Instagram authentication API not returning access token

The instagram "server side workflow" for authenticating a user and giving them a session access token doesn't work. First part works in that I can get a code back from here:
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code
However, when posting this code to
https://api.instagram.com/oauth/access_token
in order to obtain the access token, it just response with "YOU MUST PROVIDE A CLIENT ID", even though I have provided this as part of the form data - the same client id I used to get the code in the first place!
Here is the code I am using:
getIgToken: function (igCode) {
let data = {
client_id: config.imported.instagram.client_id,
client_secret: config.imported.instagram.client_secret,
grant_type: 'authorization_code',
redirect_uri: 'http://localhost:5000/app/scrape',
code: igCode
}
return $http({
method: 'POST',
url: 'https://api.instagram.com/oauth/access_token',
data: data,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
})
}
Apparently others have reported problems with posting the data as json, which have then been resolved by using "application/x-www-form-urlencoded" - however this doesn't seem to work either now.
Here is the exact error message returned:
{error_type: "OAuthException", code: 400, error_message: "You must provide a
client_id"}
code:400
error_message:"You must provide a client_id"
error_type:"OAuthException"
grant_type should be 'authorization_code'
convert the data object to json format , try
data: JSON.stringify(data),
your code will look like this
getIgToken: function (igCode) {
let data = {
client_id: config.imported.instagram.client_id,
client_secret: config.imported.instagram.client_secret,
grant_type: 'authorisation_code',
redirect_uri: 'http://localhost:5000/app/scrape',
code: igCode
}
var jsonData= JSON.stringify(data)
return $http({
method: 'POST',
url: 'https://api.instagram.com/oauth/access_token',
data: jsonData,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
})
}

Angular $HTTP response SyntaxError: Unexpected token E

Making a simple POST call using Angular $HTTP service:
authService.login = function(username, password){
var credentials = 'username=' + username + '&' + 'password=' + password;
return $http({
method: 'POST',
url: href,
headers: {'accept': acceptValue, 'content-type': contentType},
data: credentials
}).then(onSuccess, onError);
};
Can't get the error status, instead I get SyntaxError: Unexpected token E.
the console first show the status 401 and immediately after the parse error.
wonder what it does under the hood, what is it trying to parse, and why I'm not able to get error.status to work.
The problem could be with how you are serializing your data. Rather than build the string yourself, you might try passing them directly into data as an object:
data: {username: username, password: password}
Angular should serialize the info in the data object by itself.
If that doesn't work, Angular also has a built-in alternative to its default serializer that mimics the one found in jQuery. Docs on it are here. Your request with this method would look something like:
$http({
url: "/auth/login",
method: "POST",
headers: {"Content-Type": "application/x-www-form-urlencoded"},
data: $httpParamSerializerJQLike({
email: email,
password: password
})
})
If you go with this option, don't forget to inject $httpParamSerializerJQLike as a dependency.
It seems that you request is correctly sent and you receive the response.
I made a try with a RESTful service that returns an 401 status code. Here is my JavaScript code:
var href = 'https://contactsapi.apispark.net/v1/contacts/';
var acceptValue = 'application/json';
var contentType = 'application/json';
var credentials = {}; //'something';
function onSuccess(data, status, headers, config) {
}
function onError(data, status, headers, config) {
console.log('data = '+JSON.stringify(response, null, 2));
}
$http({
method: 'POST',
url: href,
headers: {'accept': acceptValue, 'content-type': contentType},
data: credentials
}).then(onSuccess, onError);
The response object contains in my case the following:
{
"data": {
"code": 401,
"contactEmail": null,
"description": "The request requires user authentication",
"homeRef": "/",
"reasonPhrase": "Unauthorized",
"uri": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2"
},
"status": 401,
"config": {
"method": "POST",
"transformRequest": [
null
],
"transformResponse": [
null
],
"url": "http://localhost:8182/contacts/",
"headers": {
"accept": "application/json",
"content-type": "application/json"
},
"data": {}
},
"statusText": "Unauthorized"
}
What could help you is to have a look at the response content (headers / payload). For example, if the payload is a JSON one, the value of the Content-Type header. Perhaps there is a gap between the Content-Type of the response and the actual content. For example, you received from plain text content with content type value application/json.
I made a test to simulate such case (XML content with a content type application/json) and I have the following error:
SyntaxError: Unexpected token <
at Object.parse (native)
at vc (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:15:480)
at Zb (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:82:229)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:83:143
at m (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:7:322)
at dd (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:83:125)
at d (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:84:380)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:119:113
at n.$eval (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:133:221)
at n.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js:130:233)
Angular tries to parse JSON content but since it's malformed, it can't and throws an error.
It seems to be similar to your error. So I think the problem isn't in your Angular application but in the server...
Hope it helps you,
Thierry

Categories

Resources