I'm trying to access the facebook api with parse cloud code using javascript.
I want to do something very simple, return the events from a given locationId.
So I have this so far:
Parse.Cloud.define("hello", function(request, response) {
console.log("Logging this");
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/217733628398158/events' ,
success: function(httpResponse) {
console.log("Not logging this");
console.log(httpResponse.data);
},
error:function(httpResponse){
console.log("Not logging this");
console.error(httpResponse.data);
}
});
response.success("result");
});
When running this it seems that Parse.Cloud.httpRequest function is failling since is not reaching any log call.
Any idea?
Dehli's comment is correct. Parse's Cloud Code will not log anything related to alternate threads once response.success has been hit. Since it is located right after the call for the http request, it will actually occur before the request returns, ending the function prematurely.
I would suggest altering your code as such:
Parse.Cloud.define("hello", function(request, response) {
console.log("Logging this");
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/217733628398158/events',
success: function(httpResponse) {
//console.log("Not logging this");
console.log(httpResponse.data);
response.success("result");
},
error:function(httpResponse){
//console.log("Not logging this");
console.error(httpResponse.message);
response.error("Failed to login");
}
});
});
Related
I am trying to run a few automated testing using the Postman tool. For regular scenarios, I understand how to write pre-test and test scripts. What I do not know (and trying to understand) is, how to write scripts for checking 409 error (let us call it duplicate resource check).
I want to run a create resource api like below, then run it again and ensure that the 2nd invocation really returns 409 error.
POST /myservice/books
Is there a way to run the same api twice and check the return value for 2nd invocation. If yes, how do I do that. One crude way of achieving this could be to create a dependency between two tests, where the first one creates a resource, and the second one uses the same payload once again to create the same resource. I am looking for a single test to do an end-to-end testing.
Postman doesn't really provide a standard way, but is still flexible. I realized that we have to write javascript code in the pre-request tab, to do our own http request (using sendRequest method) and store the resulting data into env vars for use by the main api call.
Here is a sample:
var phone = pm.variables.replaceIn("{{$randomPhoneNumber}}");
console.log("phone:", phone)
var baseURL = pm.variables.replaceIn("{{ROG_SERVER}}:{{ROG_PORT}}{{ROG_BASE_URL}}")
var usersURL = pm.variables.replaceIn("{{ROG_SERVICE}}/users")
var otpURL = `${baseURL}/${phone}/_otp_x`
// Payload for partner creation
const payload = {
"name": pm.variables.replaceIn("{{username}}"),
"phone":phone,
"password": pm.variables.replaceIn("{{$randomPassword}}"),
}
console.log("user payload:", payload)
function getOTP (a, callback) {
// Get an OTP
pm.sendRequest(otpURL, function(err, response) {
if (err) throw err
var jsonDaata = response.json()
pm.expect(jsonDaata).to.haveOwnProperty('otp')
pm.environment.set("otp", jsonDaata.otp)
pm.environment.set("phone", phone);
pm.environment.set("username", "{{$randomUserName}}")
if (callback) callback(jsonDaata.otp)
})
}
// Get an OTP
getOTP("a", otp => {
console.log("OTP received:", otp)
payload.partnerRef = pm.variables.replaceIn("{{$randomPassword}}")
payload.otp = otp
//create a partner user with the otp.
let reqOpts = {
url: usersURL,
method: 'POST',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify(payload)
}
pm.sendRequest(reqOpts, (err, response) => {
console.log("response?", response)
pm.expect(response).to.have.property('code', 201)
})
// Get a new OTP for the main request to be executed.
getOTP()
})
I did it in my test block. Create your normal request as you would send it, then in your tests, validate the original works, and then you can send the second command and validate the response.
You can also use the pre and post scripting to do something similar, or have one test after the other in the file (they run sequentially) to do the same testing.
For instance, I sent an API call here to create records. As I need the Key_ to delete them, I can make a call to GET /foo at my API
pm.test("Response should be 200", function () {
pm.response.to.be.ok;
pm.response.to.have.status(200);
});
pm.test("Parse Key_ values and send DELETE from original request response", function () {
var jsonData = JSON.parse(responseBody);
jsonData.forEach(function (TimeEntryRecord) {
console.log(TimeEntryRecord.Key_);
const DeleteURL = pm.variables.get('APIHost') + '/bar/' + TimeEntryRecord.Key_;
pm.sendRequest({
url: DeleteURL,
method: 'DELETE',
header: { 'Content-Type': 'application/json' },
body: { TimeEntryRecord }
}, function (err, res) {
console.log("Sent Delete: " + DeleteURL );
});
});
});
I got some troubles configuring an Hasura auth hook using a Lambda. I need such a function as I am storing my JWT token in an HTTP-only cookie, for security reasons.
I'm using a serverless function which returns a correct response (either when testing a curl request directly, or even when logging lambda):
{
"statusCode":200,
"body":"{\"X-Hasura-User-Id\":\"74d3bfa9-0983-4f09-be02-6a36888b382e\",\"X-Hasura-Role\":\"user\"}"
}
Yet, Hasura hook doesn't seem to recognize the response:
{
"type": "webhook-log",
"timestamp": "2020-02-07T10:27:34.844+0000",
"level": "info",
"detail": {
"response": null,
"url": "http://serverless:3000/auth",
"method": "GET",
"http_error": null,
"status_code": 200
}
}
These two lines of logs are adjacent in my logs. I just reformatted them a little bit to ease reading.
My lambda code looks like:
export const handler = async (event) => {
const cookies = getCookiesFromHeader(event.headers);
const { access_token: accessToken } = cookies;
let decodedToken = null;
try {
const cert = fs.readFileSync("./src/pem/dev.pem");
decodedToken = jwt.verify(accessToken, cert);
} catch (err) {
console.error(err);
return {
statusCode: 401,
};
}
const hasuraClaims = decodedToken['https://hasura.io/jwt/claims'];
return {
statusCode: 200,
body: JSON.stringify({
"X-Hasura-User-Id": hasuraClaims['x-hasura-user-id'],
"X-Hasura-Role": hasuraClaims['x-hasura-default-role']
})
}
}
Any idea on what is going on? Note that I'm using serverless offline, in case of. :)
In AWS Lambda, the spec requires the response body to be stringified and the actual response will be a parsed JSON object which is what Hasura will receive from the auth webhook.
When you are using serverless-offline, the response body is returned as a String (since JSON.stringify is used) without getting parsed. A simple curl will give you the difference.
The above code will work on Lambda but not on local development using serverless-offline. You will have to use the event object to see if isOffline is true and return JSON directly and if not return the stringified version.
Example code:
if(event.isOffline) {
// make it work with serverless-offline
return { "x-hasura-role": "user" ....};
} else {
// make it work with lambda
return { statusCode: 200, body: JSON.stringify({"x-hasura-role": "user"}) };
}
Official example in the serverless-offline repo along with error handling.
Related issues:
https://github.com/dherault/serverless-offline/issues/530
https://github.com/dherault/serverless-offline/issues/488
Following the documentation from https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html after successfully retrieving an authentication code.
As far as I can tell this is exactly how the request is supposed to be setup:
import request from 'request'
function fetchToken(code: any, clientId: string, clientSecret: string) {
try {
let tokenEndpoint = `https://example.auth.us-east-1.amazoncognito.com/oauth2/token`
const clientIdEncoded = Buffer.from(`${clientId}:${clientSecret}`).toString('base64')
request.post({
url:tokenEndpoint,
headers: {
'Content-Type':'application/x-www-form-urlencoded',
'Authorization':`Basic ${clientIdEncoded}`
},
form: {
code,
'grant_type':'authorization_code',
'client_id':clientId,
'redirect_uri':'http://localhost:3000'
}},
function(err,httpResponse,body){
console.log(httpResponse.statusCode)
//400
console.log(httpResponse.statusMessage)
//Bad Request
if(err) {
console.error(err)
}
console.log(body)
//{"error":"unauthorized_client"}
})
} catch (error) {
console.error(error)
}
}
Why would be getting unauthorized_client? Is there an easier way to debug this?
Edit: tested this in Postman with the same request and getting the same error
Headers
Body
Please check if the Cognito User Pool App is using secret key. If you have created with secret key option, that must be included in the Authorization header of the request.
I have created a page on locahost:8080/kar, i am sending an ajax POST request to different Url(same domain) i.e. locahost:8080/kar/create_post there i am returning an HTML response but its not showing on the browser as the URL is still on locahost:8080/kar, the data is stored in the database.Where as in the developer console i can see the response in the network tab .When i redirect it is also showing the same thing in the developer console
Why i am not able to change the URl and see the response ?
It's a client side thing, that means the desired behaviour needs to be implemented with javascript. Django is functioning normally here.
When you're sending Requests via AJAX, that is a non blocking request with the XMLHttpRequestheader set, your browser won't trigger the chain of events that occurs when a server side script evaluates your form and returns something, which may be data, or a redirect, depending on whether the form validated or not.
A typical AJAX call in jQuery looks like this:
$.ajax({
type: "POST",
url: url,
data: data,
success: success,
dataType: dataType
});
If you would like to perform some actions when the request you sent by XMLHttpRequest returns, you could attach that to the appropriate success handler:
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.post( "example.php", function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
});
// Perform other work here ...
// Set another completion function for the request above
jqxhr.always(function() {
alert( "second finished" );
});
If you need to redirect to the URI that is returned as a redirect from your server you can get the redirect URI from the response in the success handler:
$.ajax({
type: "POST",
url: reqUrl,
data: reqBody,
dataType: "json",
success: function(data, textStatus) {
if (data.redirect) {
// data.redirect contains the string URL to redirect to
window.location.href = data.redirect;
}
else {
// data.form contains the HTML for the replacement form
$("#myform").replaceWith(data.form);
}
}
});
If you would like to modify the URL in the users bar without reloading the page you could have a look at this question.
I want to get a location Id from facebook API (that is already in my DB) and than use this to get the events from that location.
So, i'm first running a query to get this info and than adding this result as a parameter in my url. The fact is that the query is returning the result properly but when calling the httpRequest this is failling. Its important to say that my httpRequest works when I use the locationId hard coded.
I guess this problem is occuring because of the response calls but i cant figure out how to fix it. I'm also looking on a better way to design this code. Any ideas?
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
locationId = results[0].get("locationFbId");
console.log(locationId);
},
error: function() {
response.error("Failed on getting locationId");
}
});
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
response.success("result");
},
error:function(httpResponse){
console.error(httpResponse.message);
response.error("Failed to get events");
}
});
});
Adolfosrs, your problem here is that your two requests are running asynchronously on different threads. Therefore, your first request isn't returning until after your second request has been called. I would suggest chaining the requests as below so that your second request will be initialized with the data retrieved from the first request.
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
locationId = results[0].get("locationFbId");
console.log(locationId);
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
response.success("result");
},
error:function(httpResponse){
console.error(httpResponse.message);
response.error("Failed to get events");
}
});
},
error: function() {
response.error("Failed on getting locationId");
}
});
});