How can i set 'personFields' query parameter in Google People API get request? - google-people-api

var xhttp = new XMLHttpRequest();
var theUrl = "https://people.googleapis.com/v1/people/c3591871730916654475?personFields='names,photos,coverPhotos'";
xhttp.open("GET", theUrl, true);
xhttp.setRequestHeader('Authorization', 'Bearer ' + currentSessionAccessToken)
xhttp.onload = function(){
if(xhttp.status == 200){
var profileJson = JSON.parse(xhttp.response);
resolve(profileJson);
}
else{
if(xhttp.status == 404){
resolve('No_RESULT_FOUND');
}
else{
reject(xhttp.statusText);
}
}
};
xhttp.onerror = function(){
reject(xhttp.statusText);
};
xhttp.send();
Above is my XMLHttpRequest. After the request i get an error below:
"{
"error": {
"code": 400,
"message": "Invalid personFields mask path: \"\"names\". Valid paths are documented at https://developers.google.com/people/api/rest/v1/people/get.",
"status": "INVALID_ARGUMENT"
}
}
"
Can some one suggest me a valid path? I did not find in the documentation.

Change personFields='names,photos,coverPhotos' to personFields=names,photos,coverPhotos without the '.

Related

How can I build a custom request workflow in Postman, based on the last request's response?

I have a request that needs some time to be processed in Logic Apps, so I established an async pattern. Then, in the response (a 202 status type) there is a "location" header value that has a URL value like the following:
https://example.com/checkJobId/218764
The server returns a response with the "location" and "retry-after" header values, and I want Postman to go into that location with the same credentials until it comes back with a 200 response. Is there a way to do this?
I checked in the documentation that you can chain different requests by name or ID; maybe the only solution is to separate the Job ID as a "job-id" value at the response's header and pass it to a new request under my collections in Postman, but I want to know if I can do it directly without having to change my server's response.
Done. This is my tested and working postman code:
// VARIABLES
var jobUrl = "https://example.com/api/async-task";
var retries = 5;
var delayInSecondsBetweenRetries = 20;
// Send initial request and get response
pm.sendRequest({
url: jobUrl,
method: "POST",
header: {
"APIKey": "MYAPIKEY"
},
}, function(err, res) {
var location = res.headers.get("location");
console.log("Job started. Checking status at: " + location);
// If status code 202 is received, get the "location" header URL
if (res.status == "Accepted") {
console.log("Entering in retry loop");
// Start retry loop
for (var i = 0; i < retries; i++) {
(function(i) {
var delay = delayInSecondsBetweenRetries * 1000 * i;
var friendlyStatus = "Still Working";
setTimeout(function() {
// Send request to "location" header URL and get response
pm.sendRequest({
url: location,
method: "GET",
header: {
"APIKey": "MYAPIKEY"
},
}, function(err, res) {
if (res.status == "Accepted") {
friendlyStatus = "Still Working";
} else if (res.status == "Bad Request") {
friendlyStatus = "Job ID not found or some error happened in the server!";
} else if (res.status == "OK") {
friendlyStatus = "||||||| Job Done! ||||||||";
} else {
throw new Error("An unknown response was recieved. Check the console for details.");
}
console.log("Location checked. Response: " + friendlyStatus);
// If status code 200 is received, exit loop
if (res.status == "OK") {
var response = res.json();
console.log("Response: " + response.ResponseText + "\n" + "Full Response Data: " + response.FullResponseData);
}
// If status code is not 200, wait 10 seconds and retry
else if (res.status == "Accepted") {
var messageComplement = "Retrying in " + delayInSecondsBetweenRetries + " seconds";
if (i == 9) {
messageComplement = "Achieved retries limit. No more retries.";
}
console.log(messageComplement);
}
else if (res.status == "Accepted") {
var messageComplement = "Retrying in " + delayInSecondsBetweenRetries + " seconds";
if (i == 9) {
messageComplement = "Achieved retries limit. No more retries.";
}
console.log(messageComplement);
}
});
}, delay);
})(i)
}
}
});

Load testing an API which uses oauth token for authorization using loadimpact k6

I'm trying to load test an API (GET method) using loadimpact k6 which requires oauth token for authorization to get the successful response. I already have a postman collection file which does this by running pre-request script. The pre-request script will request token from the authorization server and then populates the token in the environment variable. I used the "Postman to LoadImpact converter" to generate the k6 script but it isn't doing any help. The script fails to get the access token.
The generated script from the converter is given below:
// Auto-generated by the Load Impact converter
import "./libs/shim/core.js";
export let options = { maxRedirects: 4 };
const Request = Symbol.for("request");
postman[Symbol.for("initial")]({
options,
collection: {
currentAccessToken: "",
"Client-Id": "",
"Client-Secret": "",
"Token-Scope": "",
"Grant-Type": "client_credentials",
"Access-Token-URL": "",
accessTokenExpiry: ""
}
});
export default function() {
postman[Request]({
name: "Collection Mock",
id: "",
method: "GET",
address:
"",
headers: {
Authorization: "Bearer {{currentAccessToken}}"
},
pre() {
const echoPostRequest = {
url: pm.environment.get("Access-Token-URL"),
method: "POST",
header: "Content-Type:x-www-form-urlencoded",
body: {
mode: "urlencoded",
urlencoded: [
{ key: "client_id", value: pm.environment.get("Client-Id") },
{
key: "client_secret",
value: pm.environment.get("Client-Secret")
},
{ key: "grant_type", value: pm.environment.get("Grant-Type") },
{ key: "scope", value: pm.environment.get("Token-Scope") }
]
}
};
var getToken = true;
if (
!pm.environment.get("accessTokenExpiry") ||
!pm.environment.get("currentAccessToken")
) {
console.log("Token or expiry date are missing");
} else if (
pm.environment.get("accessTokenExpiry") <= new Date().getTime()
) {
console.log("Token is expired");
} else {
getToken = false;
console.log("Token and expiry date are all good");
}
if (getToken === true) {
pm.sendRequest(echoPostRequest, function(err, res) {
console.log(err ? err : res.json());
if (err === null) {
console.log("Saving the token and expiry date");
var responseJson = res.json();
pm.environment.set("currentAccessToken", responseJson.access_token);
var expiryDate = new Date();
expiryDate.setSeconds(
expiryDate.getSeconds() + responseJson.expires_in
);
pm.environment.set("accessTokenExpiry", expiryDate.getTime());
}
});
}
}
});
}
The issue is with pm.sendRequest which is not supported by the converter and I'm not sure what the alternative is. So, I'm looking for ways to dynamically request access token from the authorization server and use that token to make a request to the API for load testing in k6 script.
As you have seen sendRequest is not supported ...
This is primarily because of the fact pm.sendRequest is asynchronous but k6 at this point doesn't have a event loop so ... no asynchronous http calls :( (except with http.batch but ... not
I find it unlikely that you want this to be asynchronous or ... well you can't do it with k6 at this point either way ... you can just rewrite it to use k6's http.post
As far as I can see this should look like
pre() {
var getToken = true;
if (
!pm.environment.get("accessTokenExpiry") ||
!pm.environment.get("currentAccessToken")
) {
console.log("Token or expiry date are missing");
} else if (
pm.environment.get("accessTokenExpiry") <= new Date().getTime()
) {
console.log("Token is expired");
} else {
getToken = false;
console.log("Token and expiry date are all good");
}
if (getToken === true) {
let res = http.post(pm.environment.get("Access-Token-URL"), {
"client_id": pm.environment.get("Client-Id") ,
"client_secret": pm.environment.get("Client-Secret"),
"grant_type": pm.environment.get("Grant-Type"),
"scope": pm.environment.get("Token-Scope")
});
console.log(err ? err : res.json());
if (err === null) {
console.log("Saving the token and expiry date");
var responseJson = res.json();
pm.environment.set("currentAccessToken", responseJson.access_token);
var expiryDate = new Date();
expiryDate.setSeconds(
expiryDate.getSeconds() + responseJson.expires_in
);
pm.environment.set("accessTokenExpiry", expiryDate.getTime());
}
}
Disclaimer: I have never used postman and the code above was written/copy-pasted by hand and not tested :)
I ended up using below code snippet to make a successful call for my purpose:
// Auto-generated by the Load Impact converter
import "./libs/shim/core.js";
import http from "k6/http";
import { check, sleep } from "k6";
export let options = {
max_vus: 10,
vus: 10,
stages: [
{ duration: "1m", target: 10 }
]
}
const Request = Symbol.for("request");
pm.environment.set("currentAccessToken", "");
pm.environment.set("accessTokenExpiry", "");
pm.environment.set("clientId", "");
pm.environment.set("clientSecret", "");
pm.environment.set("tokenScope", "");
pm.environment.set("grantType", "");
pm.environment.set("accesstokenUrl", "");
pm.environment.set("apiUrl", "");
pm.environment.set("subscriptionKeys", "");
export default function() {
var getToken = true;
if (!pm.environment.get("accessTokenExpiry") || !pm.environment.get("currentAccessToken")) {
//console.log("Token or expiry date are missing");
} else if (pm.environment.get("accessTokenExpiry") <= new Date().getTime()) {
//console.log("Token is expired");
} else {
getToken = false;
//console.log("Token and expiry date are all good");
}
if (getToken === true) {
//get the access token first
let res = http.post(pm.environment.get("accesstokenUrl"), {
"client_id": pm.environment.get("clientId"),
"client_secret": pm.environment.get("clientSecret"),
"grant_type": pm.environment.get("grantType"),
"scope": pm.environment.get("tokenScope")
});
var checkRes = check(res, {
"Token Request status is 200": (r) => r.status === 200,
});
if (checkRes) {
var responseJson = res.json();
pm.environment.set("currentAccessToken", responseJson.access_token);
var expiryDate = new Date();
expiryDate.setSeconds(
expiryDate.getSeconds() + responseJson.expires_in
);
pm.environment.set("accessTokenExpiry", expiryDate.getTime());
}
sleep(1);
//make the api request using the access token and subscription keys (if required)
let apiRes = http.get(pm.environment.get("apiUrl"),
{
headers: { "Authorization": "Bearer " + pm.environment.get("currentAccessToken"),
"Subscription-Key" : pm.environment.get("subscriptionKeys")
}
});
check(apiRes, {
"API Request status is 200": (res) => res.status === 200
});
sleep(3);
}
}

Loopback - How to extend api using loopback

I want to extend my api using loopback . I have read the documentation
'use strict';
module.exports = function(Meetups,pusher) {
Meetups.status = function(cb) {
var currentDate = new Date();
var currentHour = currentDate.getHours();
var OPEN_HOUR = 6;
var CLOSE_HOUR = 20;
console.log('Current hour is %d', currentHour);
var response;
if (currentHour >= OPEN_HOUR && currentHour < CLOSE_HOUR) {
response = 'We are open yeah!!! for business.';
} else {
response = 'Sorry, we are closed. Open daily from 6am to 8pm.';
}
cb(null, response);
};
Meetups.remoteMethod(
'status', {
http: {
path: '/status',
verb: 'get'
},
returns: {
arg: 'status',
type: 'string'
}
}
);
Meetups.pusher = function(cb) {
if (2>1) {
response = 'sending something';
} else {
response = 'mont blanc';
}
cb(null, response);
};
Meetups.remoteMethod(
'pusher', {
http: {
path: '/pusher',
verb: 'get'
},
returns: {
arg: 'pusher',
type: 'string'
}
}
);
};
First, I added /status route and it worked fine. But, when i tried to add /pusher . It just didnt work. I am getting an error
{
"error": {
"statusCode": 500,
"name": "ReferenceError",
"message": "response is not defined",
"stack": "ReferenceError: response is not defined\n at Function.Meetups.pusher (/Users/ankursharma/Documents/projects/meetupz/common/models/meetups.js:34:20)\n at SharedMethod.invoke (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/lib/shared-method.js:270:25)\n at HttpContext.invoke (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/lib/http-context.js:297:12)\n at phaseInvoke (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/lib/remote-objects.js:677:9)\n at runHandler (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/lib/phase.js:135:5)\n at iterate (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:146:13)\n at Object.async.eachSeries (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:162:9)\n at runHandlers (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/lib/phase.js:144:13)\n at iterate (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:146:13)\n at /Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:157:25\n at /Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:154:25\n at execStack (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/lib/remote-objects.js:522:7)\n at RemoteObjects.execHooks (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/lib/remote-objects.js:526:10)\n at phaseBeforeInvoke (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/lib/remote-objects.js:673:10)\n at runHandler (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/lib/phase.js:135:5)\n at iterate (/Users/ankursharma/Documents/projects/meetupz/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:146:13)"
}
}
I am pretty sure, its a very small mistake. I am beginner in loopback and trying to implement loopback in my project.
In the example they define response as a local variable to that remote method, you did not. Secondly, (Meetups,pusher) you do not need to export pusher here. You are adding to Meetups.
You have to declare response in your pusher remote method.
An alternative way without declaring response is, Simply returning the value.
Example:
Meetups.pusher = function(cb) {
if (2>1) {
return 'sending something';
} else {
return 'mont blanc';
}
};
Define the variable and return the variable or you can directly call the cb in if and else like
Meetups.pusher = function(cb) {
if (2>1) {
cb(null,'sending something');
} else {
cb(null, 'mont blanc');
}
};

How to set content-length-range for s3 browser upload via boto

The Issue
I'm trying to upload images directly to S3 from the browser and am getting stuck applying the content-length-range permission via boto's S3Connection.generate_url method.
There's plenty of information about signing POST forms, setting policies in general and even a heroku method for doing a similar submission. What I can't figure out for the life of me is how to add the "content-length-range" to the signed url.
With boto's generate_url method (example below), I can specify policy headers and have got it working for normal uploads. What I can't seem to add is a policy restriction on max file size.
Server Signing Code
## django request handler
from boto.s3.connection import S3Connection
from django.conf import settings
from django.http import HttpResponse
import mimetypes
import json
conn = S3Connection(settings.S3_ACCESS_KEY, settings.S3_SECRET_KEY)
object_name = request.GET['objectName']
content_type = mimetypes.guess_type(object_name)[0]
signed_url = conn.generate_url(
expires_in = 300,
method = "PUT",
bucket = settings.BUCKET_NAME,
key = object_name,
headers = {'Content-Type': content_type, 'x-amz-acl':'public-read'})
return HttpResponse(json.dumps({'signedUrl': signed_url}))
On the client, I'm using the ReactS3Uploader which is based on tadruj's s3upload.js script. It shouldn't be affecting anything as it seems to just pass along whatever the signedUrls covers, but copied below for simplicity.
ReactS3Uploader JS Code (simplified)
uploadFile: function() {
new S3Upload({
fileElement: this.getDOMNode(),
signingUrl: /api/get_signing_url/,
onProgress: this.props.onProgress,
onFinishS3Put: this.props.onFinish,
onError: this.props.onError
});
},
render: function() {
return this.transferPropsTo(
React.DOM.input({type: 'file', onChange: this.uploadFile})
);
}
S3upload.js
S3Upload.prototype.signingUrl = '/sign-s3';
S3Upload.prototype.fileElement = null;
S3Upload.prototype.onFinishS3Put = function(signResult) {
return console.log('base.onFinishS3Put()', signResult.publicUrl);
};
S3Upload.prototype.onProgress = function(percent, status) {
return console.log('base.onProgress()', percent, status);
};
S3Upload.prototype.onError = function(status) {
return console.log('base.onError()', status);
};
function S3Upload(options) {
if (options == null) {
options = {};
}
for (option in options) {
if (options.hasOwnProperty(option)) {
this[option] = options[option];
}
}
this.handleFileSelect(this.fileElement);
}
S3Upload.prototype.handleFileSelect = function(fileElement) {
this.onProgress(0, 'Upload started.');
var files = fileElement.files;
var result = [];
for (var i=0; i < files.length; i++) {
var f = files[i];
result.push(this.uploadFile(f));
}
return result;
};
S3Upload.prototype.createCORSRequest = function(method, url) {
var xhr = new XMLHttpRequest();
if (xhr.withCredentials != null) {
xhr.open(method, url, true);
}
else if (typeof XDomainRequest !== "undefined") {
xhr = new XDomainRequest();
xhr.open(method, url);
}
else {
xhr = null;
}
return xhr;
};
S3Upload.prototype.executeOnSignedUrl = function(file, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', this.signingUrl + '&objectName=' + file.name, true);
xhr.overrideMimeType && xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var result;
try {
result = JSON.parse(xhr.responseText);
} catch (error) {
this.onError('Invalid signing server response JSON: ' + xhr.responseText);
return false;
}
return callback(result);
} else if (xhr.readyState === 4 && xhr.status !== 200) {
return this.onError('Could not contact request signing server. Status = ' + xhr.status);
}
}.bind(this);
return xhr.send();
};
S3Upload.prototype.uploadToS3 = function(file, signResult) {
var xhr = this.createCORSRequest('PUT', signResult.signedUrl);
if (!xhr) {
this.onError('CORS not supported');
} else {
xhr.onload = function() {
if (xhr.status === 200) {
this.onProgress(100, 'Upload completed.');
return this.onFinishS3Put(signResult);
} else {
return this.onError('Upload error: ' + xhr.status);
}
}.bind(this);
xhr.onerror = function() {
return this.onError('XHR error.');
}.bind(this);
xhr.upload.onprogress = function(e) {
var percentLoaded;
if (e.lengthComputable) {
percentLoaded = Math.round((e.loaded / e.total) * 100);
return this.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.');
}
}.bind(this);
}
xhr.setRequestHeader('Content-Type', file.type);
xhr.setRequestHeader('x-amz-acl', 'public-read');
return xhr.send(file);
};
S3Upload.prototype.uploadFile = function(file) {
return this.executeOnSignedUrl(file, function(signResult) {
return this.uploadToS3(file, signResult);
}.bind(this));
};
module.exports = S3Upload;
Any help would be greatly appreciated here as I've been banging my head against the wall for quite a few hours now.
You can't add it to a signed PUT URL. This only works with the signed policy that goes along with a POST because the two mechanisms are very different.
Signing a URL is a lossy (for lack of a better term) process. You generate the string to sign, then sign it. You send the signature with the request, but you discard and do not send the string to sign. S3 then reconstructs what the string to sign should have been, for the request it receives, and generates the signature you should have sent with that request. There's only one correct answer, and S3 doesn't know what string you actually signed. The signature matches, or doesn't, either because you built the string to sign incorrectly, or your credentials don't match, and it doesn't know which of these possibilities is the case. It only knows, based on the request you sent, the string you should have signed and what the signature should have been.
With that in mind, for content-length-range to work with a signed URL, the client would need to actually send such a header with the request... which doesn't make a lot of sense.
Conversely, with POST uploads, there is more information communicated to S3. It's not only going on whether your signature is valid, it also has your policy document... so it's possible to include directives -- policies -- with the request. They are protected from alteration by the signature, but they aren't encrypted or hashed -- the entire policy is readable by S3 (so, by contrast, we'll call this the opposite, "lossless.")
This difference is why you can't do what you are trying to do with PUT while you can with POST.

Upload an image to Drupal 7 / Services 3 from Titanium?

This must be close but I can't figure out what's causing the error.
In my Titanium app, I have a Webview with a canvas element and this code:
function getImageData() {
return canvas.toDataURL('image/png');
}
I am moving that data to the Titanium app like this:
var imageBase64data = webview.evalJS('getImageData()')
The data looks good starting with "data:image/png;base64,"...
Then in Titanium, I have a logged-in drupal session and call this function:
function uploadImage(imageBase64data, callback) {
var url = REST_PATH + "file.json";
var file = {
filename: utils.createRandomString() + ".png",
file: imageBase64data
// uid: Titanium.App.Properties.getString("userUid"),
// filesize: ""+Titanium.Utils.base64decode(imageBase64data).length,
};
var xhr = Titanium.Network.createHTTPClient({timeout: 30000});
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
var authString = Titanium.App.Properties.getString("userSessionName")+'='+Titanium.App.Properties.getString("userSessionId");
xhr.setRequestHeader("Cookie", authString);
xhr.onload = function() {
if(xhr.status == 200) {
var response = xhr.responseText;
callback(response);
}
};
xhr.onerror = function(e) {
alert("There was an error: " + e.error);
Ti.API.info(JSON.stringify(this));
};
xhr.open("POST", url);
xhr.send(file);
}
xhr.onerror is being called with e.error = "undefined"
The trace looks like this:
{
"responseData":{},
"readyState":4,
"connected":true,"UNSENT":0,"DONE":4,"HEADERS_RECEIVED":2,"OPENED":1,"LOADING":3,
"responseText":null,"status":406
}
I think authentication is working because I was previously getting a "need authentication" error until I added the Cookie header.
That was with the installation provided by Drupanium. I just did a fresh Drupal and fresh Services 3 install and my file is uploading nicely.