How to make Facebook API batch request into async - facebook-graph-api

This works fine as a batch request posting to https://graph.facebook.com, with the following as the 'batch=' parameter, but how do I make it an async request?
[{
"method": "GET",
"relative_url": "v11.0/act_xxxxxx/insights?fields=account_id%2Caccount_name..."
},
{
"method": "GET",
"relative_url": "v11.0/act_yyyyyy/insights?fields=account_id%2Caccount_name..."
}]
I have tried posting to https://graph.facebook.com/v11.0/act_xxxxxx/async_batch_requests, but results are not asynchronous, and results are returned synchronously in the request result.

I haven't tried it, but the doc here: https://developers.facebook.com/docs/marketing-api/insights/best-practices#asynchronous suggest that you make:
A POST call to /insights to get a report_run_id
GET calls to /:report_run_id until you get a result with async_status: "Job Completed" and async_percent_completion: 100
A GET call to /:report_run_id/insights to get your results

Related

Running and Testing AWS API Gateway via Browser instead of postman or curl

Could anyone please share how to run and test AWS API Gateway and Lambda via Browser and not via Postman or curl.
I am trying to create a simple demo app using HTML + JavaScript (with ajax call to API), and calling the AWS API.
I did tried with postman and curl both are working fine, however when calling from browser (ajax call) it is failing.
Any pointer will be a great.
code snippet :
$.ajax({
type: "POST",
url : URL,
dataType: "json",
mode: 'no-cors',
crossDomain: "true",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data),
success: function () {
// clear form and show a success message
alert("Your entry is saved Successfuly");
document.getElementById("my-form").requestFullscreen();
location.reload();
},
error: function() {
// show an error message
alert("Seems some issue with the entry, try again.")
}
});
This is a simple demo as of now to get the User Name and other details and save it into DynamoDB via AWS Lambda (Python).
AWS Lambda function is being called but in the Response it fails.
Sample code is https://codepen.io/mayanktripathi4u/pen/QWdrPOG
Tried with various options using JS Fetch; ajax; XMLHttpResponse etc.. non worked.

Slack Modal and AWS Lambda: Returning response_action after wrong user input throws an error in modal

I´m currently building an Slack app with a modal. I´m using a serverless AWS Stack containing a Lambda function that handles the user interactions. Those interactions are verified in that Lambda.
If the user input is correct, the modal is closed successfully (Lambda returns a 200 response). However, if I return the following as the body when user input is wrong and user submits the modal (as per Slack´s documentation):
{
"response_action" : "errors",
"errors": {
"startDate": "Start date is incorrect.",
},
}
The full response I'm returning at the end of the Lambda function is:
response = {
statusCode: 200,
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
response_action : "errors",
errors: {
"endDate": "Start date is incorrect.",
}
})
};
I receive the error in the next screenshot:
Am I missing something? Thanks a lot.
So I found the problem and here´s the solution in my case (might be helpful to you reader):
The right block type
The modal I built is made of interactive components, like a date picker. These components are blocks of type "section". For better comprehension, they look like this:
However, it seems that´s not compatible with the the feature to display input errors. For that, you have to choose blocks of type "input". Again, for understanding, they look like this:
And that type of block is compatible with displaying error messages as per Slack documentation.
The response from AWS Lambda
When you validate a user input, in the AWS Lambda function, Slack expects you to return the following structure in the response if you want to warn about an error:
{ "response_action": "errors", "errors": { "ticket-due-date": "You may not select a due date in the past" } }
However, it looks like you need to indicate the time of content by adding a header defining content is of JSON type without a statusCode. In my case, response that works is:
response = {
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
response_action : "errors",
errors: {
"test": "That date is invalid. Please, select a future date.",
}
})
And that way, the custom error message appears:

Is it theoretically possible to use `putRecord` in Kinesis via singular http POST request?

I've been experiencing some issues with AWS Kinesis inasmuch as I have a stream set up and I want to use a standard http POST request to invoke a Kinesis PutRecord call on my stream. I'm doing this because bundle-size of my resultant javascript application matters and I'd rather not import the aws-sdk to accomplish something that should (on paper) be possible.
Just so you know, I've looked at this other stack overflow question about the same thing and It was... sort of informational.
Now, I already have a method to sigv4 sign a request using an access key, secret token, and session token. but when I finally get the result of signing the request and send it using the in-browser fetch api, the service tanks with (or with a json object citing the same thing, depending on my Content-Type header, I guess) as the result.
Here's the code I'm working with
// There is a global function "sign" that does sigv4 signing
// ...
var payload = {
Data: { task: "Get something working in kinesis" },
PartitionKey: "1",
StreamName: "MyKinesisStream"
}
var credentials = {
"accessKeyId": "<access.key>",
"secretAccessKey": "<secret.key>",
"sessionToken": "<session.token>",
"expiration": 1528922673000
}
function signer({ url, method, data }) {
// Wrapping with URL for piecemeal picking of parsed pieces
const parsed = new URL(url);
const [ service, region ] = parsed.host.split(".");
const signed = sign({
method,
service,
region,
url,
// Hardcoded
headers : {
Host : parsed.host,
"Content-Type" : "application/json; charset=UTF-8",
"X-Amz-Target" : "Kinesis_20131202.PutRecord"
},
body : JSON.stringify(data),
}, credentials);
return signed;
}
// Specify method, url, data body
var signed = signer({
method: "POST",
url: "https://kinesis.us-west-2.amazonaws.com",
data : JSON.stringify(payload)
});
var request = fetch(signed.url, signed);
When I look at the result of request, I get this:
{
Output: {
__type: "com.amazon.coral.service#InternalFailure"},
Version: "1.0"
}
Now I'm unsure as to whether Kinesis is actually failing here, or if my input is malformed?
here's what the signed request looks like
{
"method": "POST",
"service": "kinesis",
"region": "us-west-2",
"url": "https://kinesis.us-west-2.amazonaws.com",
"headers": {
"Host": "kinesis.us-west-2.amazonaws.com",
"Content-Type": "application/json; charset=UTF-8",
"X-Amz-Target": "Kinesis_20131202.PutRecord",
"X-Amz-Date": "20180613T203123Z",
"X-Amz-Security-Token": "<session.token>",
"Authorization": "AWS4-HMAC-SHA256 Credential=<access.key>/20180613/us-west-2/kinesis/aws4_request, SignedHeaders=content-type;host;x-amz-target, Signature=ba20abb21763e5c8e913527c95a0c7efba590cf5ff1df3b770d4d9b945a10481"
},
"body": "\"{\\\"Data\\\":{\\\"task\\\":\\\"Get something working in kinesis\\\"},\\\"PartitionKey\\\":\\\"1\\\",\\\"StreamName\\\":\\\"MyKinesisStream\\\"}\"",
"test": {
"canonical": "POST\n/\n\ncontent-type:application/json; charset=UTF-8\nhost:kinesis.us-west-2.amazonaws.com\nx-amz-target:Kinesis_20131202.PutRecord\n\ncontent-type;host;x-amz-target\n508d2454044bffc25250f554c7b4c8f2e0c87c2d194676c8787867662633652a",
"sts": "AWS4-HMAC-SHA256\n20180613T203123Z\n20180613/us-west-2/kinesis/aws4_request\n46a252f4eef52991c4a0903ab63bca86ec1aba09d4275dd8f5eb6fcc8d761211",
"auth": "AWS4-HMAC-SHA256 Credential=<access.key>/20180613/us-west-2/kinesis/aws4_request, SignedHeaders=content-type;host;x-amz-target, Signature=ba20abb21763e5c8e913527c95a0c7efba590cf5ff1df3b770d4d9b945a10481"
}
(the test key is used by the library that generates the signature, so ignore that)
(Also there are probably extra slashes in the body because I pretty printed the response object using JSON.stringify).
My question: Is there something I'm missing? Does Kinesis require headers a, b, and c and I'm only generating two of them? Or is this internal error an actual failure. I'm lost because the response suggests nothing I can do on my end.
I appreciate any help!
Edit: As a secondary question, am I using the X-Amz-Target header correctly? This is how you reference calling a service function so long as you're hitting that service endpoint, no?
Update: Followinh Michael's comments, I've gotten somewhere, but I still haven't solved the problem. Here's what I did:
I made sure that in my payload I'm only running JSON.stringify on the Data property.
I also modified the Content-Type header to be "Content-Type" : "application/x-amz-json-1.1" and as such, I'm getting slightly more useful error messages back.
Now, my payload is still mostly the same:
var payload = {
Data: JSON.stringify({ task: "Get something working in kinesis" }),
PartitionKey: "1",
StreamName: "MyKinesisStream"
}
and my signer function body looks like this:
function signer({ url, method, data }) {
// Wrapping with URL for piecemeal picking of parsed pieces
const parsed = new URL(url);
const [ service, region ] = parsed.host.split(".");
const signed = sign({
method,
service,
region,
url,
// Hardcoded
headers : {
Host : parsed.host,
"Content-Type" : "application/json; charset=UTF-8",
"X-Amz-Target" : "Kinesis_20131202.PutRecord"
},
body : data,
}, credentials);
return signed;
}
So I'm passing in an object that is partially serialized (at least Data is) and when I send this to the service, I get a response of:
{"__type":"SerializationException"}
which is at least marginally helpful because it tells me that my input is technically incorrect. However, I've done a few things in an attempt to correct this:
I've run JSON.stringify on the entire payload
I've changed my Data key to just be a string value to see if it would go through
I've tried running JSON.stringify on Data and then running btoa because I read on another post that that worked for someone.
But I'm still getting the same error. I feel like I'm so close. Can you spot anything I might be missing or something I haven't tried? I've gotten sporadic unknownoperationexceptions but I think right now this Serialization has me stumped.
Edit 2:
As it turns out, Kinesis will only accept a base64 encoded string. This is probably a nicety that the aws-sdk provides, but essentially all it took was Data: btoa(JSON.stringify({ task: "data"})) in the payload to get it working
While I'm not certain this is the only issue, it seems like you are sending a request body that contains an incorrectly serialized (double-encoded) payload.
var obj = { foo: 'bar'};
JSON.stringify(obj) returns a string...
'{"foo": "bar"}' // the ' are not part of the string, I'm using them to illustrate that this is a thing of type string.
...and when parsed with a JSON parser, this returns an object.
{ foo: 'bar' }
However, JSON.stringify(JSON.stringify(obj)) returns a different string...
'"{\"foo\": \"bar\"}"'
...but when parsed, this returns a string.
'{"foo": "bar"}'
The service endpoint expects to parse the body and get an object, not a string... so, parsing the request body (from the service's perspective) doesn't return the correct type. The error seems to be a failure of the service to parse your request at a very low level.
In your code, body: JSON.stringify(data) should just be body: data because earlier, you already created a JSON object with data: JSON.stringify(payload).
As written, you are effectively setting body to JSON.stringify(JSON.stringify(payload)).
Not sure if you ever figured this out, but this question pops up on Google when searching for how to do this. The one piece I think you are missing is that the Record Data field must be base64 encoded. Here's a chunk of NodeJS code that will do this (using PutRecords).
And for anyone asking, why not just use the SDK? I currently must stream data from a cluster that cannot be updated to a NodeJS version that the SDK requires due to other dependencies. Yay.
const https = require('https')
const aws4 = require('aws4')
const request = function(o) { https.request(o, function(res) { res.pipe(process.stdout) }).end(o.body || '') }
const _publish_kinesis = function(logs) {
const kin_logs = logs.map(function (l) {
let blob = JSON.stringify(l) + '\n'
let buff = Buffer.from(blob, 'binary');
let base64data = buff.toString('base64');
return {
Data: base64data,
PartitionKey: '0000'
}
})
while(kin_logs.length > 0) {
let data = JSON.stringify({
Records: kin_logs.splice(0,250),
StreamName: 'your-streamname'
})
let _request = aws4.sign({
hostname: 'kinesis.us-west-2.amazonaws.com',
method: 'POST',
body: data,
path: '/?Action=PutRecords',
headers: {
'Content-Type': 'application/x-amz-json-1.1',
'X-Amz-Target': 'Kinesis_20131202.PutRecords'
},
}, {
secretAccessKey: "****",
accessKeyId: "****"
// sessionToken: "<your-session-token>"
})
request(_request)
}
}
var logs = [{
'timeStamp': new Date().toISOString(),
'value': 'test02',
},{
'timeStamp': new Date().toISOString(),
'value': 'test01',
}]
_publish_kinesis(logs)

Ember Data + JSONAPI - Error: The adapter rejected the commit because it was invalid

I am attempting to submit invalid data via a POST request to a JSONAPI-based API with Ember Data 2.10.
The API responds correctly with a 422 code and this payload in the response (note that these are error objects, not a "normal" JSONAPI payload response):
{
"errors": [{
"title": "Title can't be blank",
"id": "title",
"code": "100",
"source": {
"pointer": "/data/attributes/title"
},
"status": "422"
}, {
"title": "Layout can't be blank",
"id": "layout",
"code": "100",
"source": {
"pointer": "/data/relationships/layout"
},
"status": "422"
}, {
"title": "Page type can't be blank",
"id": "page-type",
"code": "100",
"source": {
"pointer": "/data/attributes/page-type"
},
"status": "422"
}]
}
The errors seem to be loading mostly OK into the model, but I get this error in the console:
ember.debug.js:19160 Error: The adapter rejected the commit because it was invalid
at ErrorClass.EmberError (ember.debug.js:19083)
at ErrorClass.AdapterError (errors.js:23)
at ErrorClass (errors.js:49)
at Class.handleResponse (rest.js:821)
at Class.handleResponse (data-adapter-mixin.js:100)
at Class.superWrapper [as handleResponse] (ember.debug.js:24805)
at ajaxError (rest.js:1342)
at Class.hash.error (rest.js:916)
at fire (jquery.js:3305)
at Object.fireWith [as rejectWith] (jquery.js:3435)
What is causing this error? Is there something wrong in the JSON payload being returned by the server? One thing that changed recently was the introduction of a pointer to /data/relationships/layout; is Ember Data choking on that?
I may also note that submitting similar bad data via a PATCH request does not trigger this error in the console.
The main problem is that this is causing an acceptance test to fail, and I can't seem to find a way around it. It would be nice to be able to test this behavior in the application, but I'll just need to leave it commented out for now.
I've also tried this on Ember Data 2.7 before updating to 2.10 to see if that would fix it. Getting the same error with both versions.
since your app uses the default adapter, make sure JSON:API conventions are followed for building the response
Handful of guide is provided over here

facebook unsupported post request

I have logged in a user to my app from FB.login now I want to post to the user timeline on the behalf of user. I want to upload a video to the user timeline. I am doing something like:
FB.api(
`/${user_id}/videos`,
"POST",
{
"file_url": video,
"description": description,
"thumb": video_thumbnail,
"title": title,
},
function (response) {
console.log("fb response")
console.log(response)
if (response && !response.error) {
/* handle the result */
console.log("video upload response")
console.log(response)
}
}, {scope: ['user_videos', 'user_actions.video']});
When I do this it is giving me error saying code: 100
fbtrace_id: "F1BDJWtcTXl"
message: "Unsupported post request. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api"
type: "GraphMethodException"
Why I am getting this error ??
Help is appriciated ..
Thank you
Use /me/videos instead of /${user_id}/videos and use single (or double) quotes instead of "`".
Also, you need publish_actions only, and you need to use the scope parameter with FB.login. FB.api is just an API call.
Here´s an example for the login: http://www.devils-heaven.com/facebook-javascript-sdk-login/
And here´s the link to the docs for uploading videos: https://developers.facebook.com/docs/graph-api/reference/user/videos/#Creating
Someone suggested that the App may be in sandbox/dev mode, no sure why this should be a problem but here´s the thread: How to fix "Unsupported post request" when posting to FB fan page?