Graph API - get JSON data without "paging" key - facebook

I'm getting facebook data using graph api, adding fields in string and get JSON result.
Example:
https://graph.facebook.com/me?fields=music
But JSON returned contains a "paging" key and I do not I want this key.
{ "music":{
"data":[
{
"name":"",
"category":"",
"id":"",
"created_time":""
},
{
"name":"",
"category":"",
"id":"",
"created_time":""
}
],
"paging":{
"next":"https://graph.facebook.com/me?fields=music&method=GET&metadata=true&format=json&callback=___GraphExplorerAsyncCallback___&access_token=...&limit=5000&offset=5000&__after_id=..."
}}}
EDITED:
I'm using Java API (restfb.com) to get JSON.
The command in java is:
FacebookClient client = new DefaultFacebookClient("ACCESS_TOKEN_HERE");
JsonObject rMusic = client.fetchObject("ID_HERE", JsonObject.class, Parameter.with("fields", "id,name,religion,birthday,music"));
How do I avoid it or remove it?

When you have your Javascript object built from the JSON, just pay attention to the array of data: result.music.data
And forget about the paging property: result.music.paging
Remember, there's no law in coding that you have to look at every property in your scripts.

Based upon the edit to the question above, here's a new answer.
The Rest API is deprecated. You should upgrade your app to use the Graph API as this is the one being supported.
Also, if you see a property you don't like, you don't have to access it. Remember, there's no law in coding that you have to look at every property in your scripts.

Related

Salesforce REST API how to avoid leaking sensitive data in query parameter

I'm trying to do query using REST API, and ran into the following problem:
Using GET request on the query endpoint exposes the entire query string, which may contain sensitive data such as SSN, phone number, etc...
https://[instance-url].my.salesforce.com/services/data/v48.0/query/?q=SELECT Id FROM Contact WHERE SSN__c = '123456789'
How can I do such a query using rest api securely?
IS there an equivalent request I can make using at least POST request with post body being the query? since that part is encrypted over https.
Thank you for help
You have two options.
Parameterized Search API. This option is available out of the box with POST as the method. The API is a RESTful interface to Salesforce's text-based search engine. Normally, text-based search uses SOSL as the query language. Parameterized Search API skips SOSL and gives you an easier option to work with.
If you POST the following body to /services/data/v48.0/parameterizedSearch
{
"q": "123456789",
"sobjects": [
{
"name": "Contact",
"where": "SSN__c = '123456789'"
}
],
"fields": ["id"]
}
you should see something like this as the response, assuming single record is returned by search (ID is redacted):
{
"searchRecords" : [ {
"attributes" : {
"type" : "Contact",
"url" : "/services/data/v48.0/sobjects/Contact/003..."
},
"Id" : "003..."
} ]
}
The value of q key in the JSON payload must be the same as the value in the where key/clause. You're doing a full-text search on 123456789 across all objects and all fields in the search index. This could return many records..but you're filtering the search down in a structured way to guarantee that you'll only see Contact records where SSN__c = '123456789'. As long as the objects + fields you're trying to retrieve are present in the index the results you'll see via Parameterized Search in this specific example are going to be the same as that of a SOQL query via /query
Custom REST API (aka Apex REST / Apex web service). This is a typical implementation option for cases like yours. You can send whatever payload via POST and then process it however you like.
Apex class:
#RestResource(urlMapping='/findcontactbyssn')
global class ContactResource {
#HttpPost
global static void findContactBySSN() {
SearchRequest input = (SearchRequest)JSON.deserialize(RestContext.request.requestBody.toString(),SearchRequest.class);
Contact c = [SELECT Id FROM Contact WHERE SSN__c = :input.ssn];
SearchResponse output = new SearchResponse();
output.id = c.id;
RestContext.response.responseBody = Blob.valueOf(JSON.serialize(output));
RestContext.response.statusCode = 200;
}
class SearchRequest {
public String ssn {get;set;}
}
class SearchResponse {
public String id {get;set;}
}
}
POST to /services/apexrest/findcontactbyssn with
{
"ssn": "12345678"
}
and you should see this response:
{
"id": "003..."
}
AFAIK, salesforce only provides a GET method for executing SOQL queries. One can write their own REST endpoint in their org that accepts a query in body and execute it, but thats a waste of time in my opinion.
Query string parameters are secured over https. Its a common misconception, where people think whole url is open in plain text in transmission. When a request is made to an https url, first it establishes a Secure Tunnel to [instance-url].my.salesforce.com then transmits the rest of the url and any other data over the secure tunnel.
If you're worried about some man in the middle attack sniffing out the SSN from your query string, don't. One downside is, if you are accessing this url from a browser instead of a programmatic call, then there is a chance for browser to stored/cache for history or auto complete, then it won't be so good.
But I doubt if you would be able to do this via browser, as salesforce requires a bearer token set in Authorization header and there is no easy way that I know of to set headers while typing the url in the browser or clicking a link.
To know more about how query string is secure over https please refer to this stackoverflow question

Obtain specific data from Google Firestore using Rest API calls (HTTP-GET)

Problem
I want to retrieve specific data from Google Firestore.
It's only possible to get all of the 'Fields' data. But no specific data within fields
Example of the GET-Request:
https://firestore.googleapis.com/v1beta1/projects/edubox-49528/databases/(default)/documents/nodes/EduBox-1234567?key=[My_API_KEY]&fields=fields
As you can see, It is possible to obtain all the items in the object 'Fields'. But it is not possible to get any further into detail to obtain more specific data (test, message, nodeID, ...)
Tryouts
I have already tried:
fields=fields/test
fields=fields.test
fields=fields(test)
fields=fields/test/integerValue
...
Expected Results
I want to obtain specific data like the String / integer value of my objects in 'Fields'.
This example should return the integerValue with 30
https://firestore.googleapis.com/v1beta1/projects/edubox-49528/databases/(default)/documents/nodes/EduBox-1234567?key=[My_API_KEY]&fields=fields/test
This example should return 30
https://firestore.googleapis.com/v1beta1/projects/edubox-49528/databases/(default)/documents/nodes/EduBox-1234567?key=[My_API_KEY]&fields=fields/test/integerValue
Solution
While browsing the web, I came across Google Api Explorer:
https://developers.google.com/apis-explorer/#search/firestore/firestore/v1beta1/
When trying out some possibilities, I came across this:
https://firestore.googleapis.com/v1/projects/edubox-49528/databases/(default)/documents/nodes/EduBox-1234567?mask.fieldPaths=nodeID&fields=fields&key={YOUR_API_KEY}
This gives me the right information
but I still need a more detailed form of this answer like only the 'EduBox-1234567'
The way to retrieve a specific field is to use mask.fieldPaths. For example the following GET method:
https://firestore.googleapis.com/v1beta1/projects/edubox-49528/databases/(default)/documents/nodes/EduBox-1234567?key=[My_API_KEY]&fields=fields&mask.fieldPaths=nodeID
is going do return:
{
"fields": {
"nodeID": {
"stringValue": "EduBox-1234567"
}
}
Documentation references here and here.

Add a subpanel record to a SugarCRM account through REST API

Question: How do I create a subpanel record through the SugarCRM rest api endpoint for accounts?
Steps taken so far:
I've added a new package called, "transactionHistory" with a module named, "InvoiceHistory" using the SugarCRM studio.
I added a One to Many relationship to the Accounts module using studio.
I'm using NetSuite to push new invoices to the new module's record via the subpanel "create" option. Here's the code I'm using:
function createSugarTransaction(transaction, token) {
var url = 'https://crm.techsoft3d.com/rest/v10/Accounts/' + transaction.customer;
var headers = {
"Content-Type": "application/json",
"OAuth-Token": token
};
var now = (new Date()).toISOString();
var body = {transactionHistory_InvoiceHistory:
{
create: [{
name: transaction.docId,
transaction_date_c: transaction.date,
invoice_status_c: transaction.status,
due_date_c: transaction.duedate,
total_amount_c: transaction.total,
amount_due_c: transaction.remaining,
start_date_c: transaction.startdate,
end_date_c: transaction.enddate
}]
}
};
var response = nlapiRequestURL(url, JSON.stringify(body), headers, 'PUT');
return response;
}
The transaction object has been validated and the json object within the create: [] array has matching sugar fields (key) with the corresponding transaction object values.
When making the API call to sugar I'm successfully authenticated and have access to the custom module and accounts - so no problem there. However, when the call is returned to response it's showing the following error:
{"error":"no_method","error_message":"Could not find a route with 1 elements"}
I'm unsure of what else is needed in order for the record to be created. According to sugar's help documentation and developer community this should work. I'm using the basic information provided by sugarcrm support portal:
http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.6/API/Web_Services/Examples/v10/module_POST/
According to other blog posts within the developer community, it should be as simple as adding the subpanel name, followed by an array of fields under the "create" object... similar to this:
var requestBody = { package_module:create[{name:value}]};
My initial thinking of what's wrong is:
1. my package_module name isn't correct, but I'm unable to find it anywhere within the applicaiton or help documentation.
2. the request body isn't formatted properly, even though it's structure was copied from this article https://developer.sugarcrm.com/2014/02/28/sugarcrm-cookbook2/
Any help would be appreciated.
try the createRelatedRecord api endpoint
type {sugarurl}/rest/v10/help to see a list of endpoints to look through, most of which have documentation and examples
https://crm.techsoft3d.com/rest/v10/help
your API url should have the name of the link (relationship) you want, in addition to the values in the POST payload
https://crm.techsoft3d.com/rest/v10/Accounts/{transaction.customer}/link/accounts_transactionhistory (or whatever your link's name is)
per the documentation for this endpoint, you just specify the field values in the payload
{
"first_name":"Bill",
"last_name":"Edwards"
}

Angular JS: Full example of GET/POST/DELETE/PUT client for a REST/CRUD backend?

I've implemented a REST/CRUD backend by following this article as an example: http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/ . I have MongoDB running locally, I'm not using MongoLabs.
I've followed the Google tutorial that uses ngResource and a Factory pattern and I have query (GET all items), get an item (GET), create an item (POST), and delete an item (DELETE) working. I'm having difficulty implementing PUT the way the backend API wants it -- a PUT to a URL that includes the id (.../foo/) and also includes the updated data.
I have this bit of code to define my services:
angular.module('realmenServices', ['ngResource']).
factory('RealMen', function($resource){
return $resource('http://localhost\\:3000/realmen/:entryId', {}, {
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method:'PUT'},
remove: {method:'DELETE'}
});
I call the method from this controller code:
$scope.change = function() {
RealMen.update({entryId: $scope.entryId}, function() {
$location.path('/');
});
}
but when I call the update function, the URL does not include the ID value: it's only "/realmen", not "/realmen/ID".
I've tried various solutions involving adding a "RealMen.prototype.update", but still cannot get the entryId to show up on the URL. (It also looks like I'll have to build the JSON holding just the DB field values myself -- the POST operation does it for me automatically when creating a new entry, but there doesn't seem to be a data structure that only contains the field values when I'm viewing/editing a single entry).
Is there an example client app that uses all four verbs in the expected RESTful way?
I've also seen references to Restangular and another solution that overrides $save so that it can issue either a POST or PUT (http://kirkbushell.me/angular-js-using-ng-resource-in-a-more-restful-manner/). This technology seems to be changing so rapidly that there doesn't seem to be a good reference solution that folks can use as an example.
I'm the creator of Restangular.
You can take a look at this CRUD example to see how you can PUT/POST/GET elements without all that URL configuration and $resource configuration that you need to do. Besides it, you can then use nested resources without any configuration :).
Check out this plunkr example:
http://plnkr.co/edit/d6yDka?p=preview
You could also see the README and check the documentation here https://github.com/mgonto/restangular
If you need some feature that's not there, just create an issue. I usually add features asked within a week, as I also use this library for all my AngularJS projects :)
Hope it helps!
Because your update uses PUT method, {entryId: $scope.entryId} is considered as data, to tell angular generate from the PUT data, you need to add params: {entryId: '#entryId'} when you define your update, which means
return $resource('http://localhost\\:3000/realmen/:entryId', {}, {
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method:'PUT', params: {entryId: '#entryId'}},
remove: {method:'DELETE'}
});
Fix: Was missing a closing curly brace on the update line.
You can implement this way
$resource('http://localhost\\:3000/realmen/:entryId', {entryId: '#entryId'}, {
UPDATE: {method: 'PUT', url: 'http://localhost\\:3000/realmen/:entryId' },
ACTION: {method: 'PUT', url: 'http://localhost\\:3000/realmen/:entryId/action' }
})
RealMen.query() //GET /realmen/
RealMen.save({entryId: 1},{post data}) // POST /realmen/1
RealMen.delete({entryId: 1}) //DELETE /realmen/1
//any optional method
RealMen.UPDATE({entryId:1}, {post data}) // PUT /realmen/1
//query string
RealMen.query({name:'john'}) //GET /realmen?name=john
Documentation:
https://docs.angularjs.org/api/ngResource/service/$resource
Hope it helps

HATEOAS client with AngularJS

I was wondering if there were any features hidden in Angular or exposed by some 3rd-party libraries to easily create HATEOAS-compliant Restful clients.
On backend side, I am using Spring Data/REST to produce an HATEOAS JSON API.
Consuming it, though, is quite another story.
For instance, I've got those 3 entities:
Company {name, address}
Employee {firstName, lastName, employer[Company]}
Activity {rate, day, employee[Employee], client[Company]}
and requesting an activity (the most complex entity of the model) produces something like this:
{
links: [],
content: [{
rate: 456,
day: 1366754400000,
links: [{
rel: "self",
href: "http://localhost:8080/api/activities/1"
},
{
rel: "activities.activity.client",
href: "http://localhost:8080/api/activities/1/client"
},
{
rel: "activities.activity.employee",
href: "http://localhost:8080/api/activities/1/employee"
}]
}]
}
My API talks in terms of REST (resources identified by links).
An Activity has an Employee for instance. What I really want to use is : {rate: 456, day: 1366754400000, employee: {firstName:"xxx", lastName:"xxx" ...}}.
However, as you can see in the first output, my Activity only contains a link to the employee, not its data. Is there anything in Angular or in a 3rd-party library to resolve those links and embed the resulting data instead?
Any input on this?
Thanks in advance!
Checkout angular-hateoas. ITs an AngularJS module for using $resource with a HATEOAS-enabled REST API.
You could write a Response Transformation that would inspect your returned object, check for links, and resolve them before returning the response. See the section "Transforming Requests and Responses" in the $http service documentation.
Something like this:
transformResponse: function(rawData) {
var json = JSON.parse( rawData );
forEach( json.content.links, function(link) {
// resolve link...
});
return json;
}
Since the "resolve link" step is itself an $http call, sub-references would also be resolved. HOWEVER, since these are asynchronous, you would likely return a promise instead of the real value; I don't know if the transform function is allowed to do this.
As #charlietfl pointed out, however, please note that this will result in several HTTP calls to return a single entity. Even though I like the concept of HATEOAS, this will likely result in sluggishness if too many calls are made. I'd suggest that your server return the data, or some of it, directly, PLUS the link for details.
Based on your comment about wanting to work with data as against links on the client, I think Restangular would be a good fit.
I've been using angular-hal for one of my projects. It was a Spring HATEOAS backend. And I didn't run into any issues. It handles parametrized resources. I suspect it only supports HAL so since you're using Spring Data Rest you probably have to configure it to generate HAL compliant responses.
I think the confusion may be that you are asking for an Angular solution, when what you really want to do is have Spring Data send a more complete JSON response. I.e, you really just want the server to return the employee data as part of the response JSON, rather than having the client perform extra steps to look it up. I don't know what data store you are using in Spring Data, but the general solution would be to add public getEmployee() method to your Activity class and then annotate the method with #RelatedTo and #Fetch (this would be the setup for Neo4J -- may be different annotations for your flavor of Spring Data). This should cause Spring HATEOAS to include the Employee record within the response for /activity. Hope this helps.