Sencha Touch: How to build a restful proxy url syntax? - rest

Defined as a model and its associations, I wish the http calls to follow best practices of restful. For example, if I make the call
user.posts();
I wish to run a call http defined as
users/1/posts
If a call is then put on post with id 32 then the url of reference must be
users/1/posts/32
So I want to avoid using the filter property as is the default for a get
/posts.php?filter=[{"property":"user_id","value":1}]
This is because the api rest are already defined and I can not change them.
I would like to build a minimally invasive solution and reading on various forums the best way is to do an ovveride the method buildURL the proxy rest but was not able to retrieve all the data needed to build the final URL. Can anyone give me an example?
thanks

Try the following:
window.serverUrl = "192.168.1.XX"
var service = "login.php"
var dataTosend: {
username:"xx",
password: "yy"
}
var methode:"POST" / "GET"
this.service(service,methode,dataTosend,onSucessFunction,onFailureFunction);
onSucessFunction: function(res) {
alert("onSucessFunction"):
},
onFailureFunction: function(res) {
alert("onFailureFunction"):
},
service: function(svc, callingMethod, data, successFunc, failureFunc) {
Ext.Ajax.request({
scope: this,
useDefaultXhrHeader: false,
method: callingMethod,
url: window.serverUrl + svc,
params: data,
reader: {
type: 'json'
},
failure: failureFunc,
success: successFunc
});
I hope this will solve your problem...

Related

Sailsjs - Cloud SDK - Blueprint API auto generated routes?

I wonder if it is possible to have the Blueprint API support in Cloud SDK.
But apparently, the generated cloud.setup.js file does not contain blueprint APIs. Just normal routes beginning with /api
It is written in the Cloud.js file :
* ### Basic Usage
*
* var user = await Cloud.findOneUser(3);
*
* var user = await Cloud.findOneUser.with({ id: 3 });
It lets think that it's possible to have auto generated routes to the blueprint APIs like actionModel -> findOneUser, createServer, addToGame, and so on...
Do you know if that is possible ? I don't find a documentation about this.
Thanks
I took original code in rebuild-cloud-sdk.js and created a rcsdk.js with the code below before the actual for (let address in sails.config.routes):
_.each(_.keys(sails.models), model => {
let action = sails.config.blueprints.prefix + sails.config.blueprints.restPrefix + '/' + model;
_.each([['GET', 'find'], ['POST', 'create']], pair => {
endpointsByMethodName[`${pair[1]}${model}`] = {
verb: pair[0],
url: action,
}
});
_.each([['GET', 'findOne'], ['PUT', 'update'], ['DELETE', 'delete']], pair => {
endpointsByMethodName[`${pair[1]}${model}`] = {
verb: pair[0],
url: action,
args: ['id'],
}
});
});
I also asked this question the other day. It is not possible. We need to be explicit here. Blueprint routes is only for quick integration testing with postman. I don't recommend this though. You should not be using postman or auto routes. You should write tests in files so they are permanent.

how to get query parameter in action2 in sails

I dont know how to set up route according to REST for the search request url like this
localhost:1337/system?id=10
After that, how can we get parameter from the above request in action 2 like this
action2(inputs,exits)
I want to follow best practice for web api in sails. Please hint me to solve and recommend any handy documents.
Thanks in advance
For the Actions2 format, you'd use inputs.id, after properly defining the inputs, of course. For more information, consult the documentation on Actions and Controllers. This would need more finishing, but it gets your input and a function. You'd want to add in your exits, and some real logic, of course, and probably some decent descriptions.
module.exports = {
inputs: {
id: {
type: 'number',
required: true
}
},
exits: {
success: { ... },
error: { ... }
},
fn: async function (inputs, exits) {
var myId = inputs.id;
return exits.success(myId);
}
}

HttpClient append parameter object to GET request

I'm quite the noob using Ionic or Angular for that matter. So as a cheat sheet I'm using the ionic-super-starter template (link below).
I am trying to make a get request to my API and it works just find if I'm doing it like this:
this.api.get('user/'+this.user.userId+'/entries?include=stuff&access_token=TOKEN');
but when I put the url params into an object it stops working:
let options = {
'include':'stuff',
'access_token':'TOKEN'
}
this.api.get('user/'+this.user.userId+'/entries', options);
The only error I get is "Unauthorized Request" since the options object including the access token was not appended to the url.
In the ionic-super-starter template the providers/api/api.ts calls .set() for each key in my params object:
if (params) {
reqOpts.params = new HttpParams();
for (let k in params) {
reqOpts.params.set(k, params[k]);
}
}
but according to Angular University this is not possible since "HTTPParams is immutable".
If it really was wrong to do this, I don't believe it would be in the ionic template. Nor would I believe that I would be the first person to come across this issue.
However, I am stuck here so any help would be appreciated.
Link to Angular University:
https://blog.angular-university.io/angular-http/#httprequestparameters
Link to ionic-super-starter:
https://github.com/ionic-team/starters/tree/master/ionic-angular/official/super
I think I figured it out myself:
if I write (in my src/providers/api/api.ts)
reqOpts.params = reqOpts.params.append(k, params[k]);
instead of
reqOpts.params.set(k, params[k]);
it works.
if you are using a loopback API as I am you might have nested objects like:
let options = {
"filter": {
"order": "date DESC"
},
"access_token":this.user._accessToken
};
this won’t work. try instead:
let options = {
"filter": '{"order":"date DESC"}',
"access_token":this.user._accessToken
};

Why the port number is cut when angular app call rest service

I have rest service:
http://localhost:3000/api/brands
When I test it from web browser it works well.
I use it in angular service:
var motoAdsServices = angular.module('motoAdsServices', ['ngResource']);
motoAdsServices.factory('Brand', ['$resource', function($resource) {
return $resource('http://localhost:3000/api/:id', {}, {
query: {
method: 'GET',
params: {
id: 'brands'
},
isArray: true
}
});
}]);
When it is call I have error because in reqest URL I don't have port number:
Request URL: http://localhost/api/brands
Why the port numer is is cut? Angular cut it?
In Angular doc is written:
A parametrized URL template with parameters prefixed by : as in /user/:username. If you are using a URL with a port number (e.g. http://example.com:8080/api), it will be respected.
UPDATE
I use angular version 1.0.8 (thank #KayakDave for your attention) but Angular doc applies to version 1.2.
It has a colon and therefore gets stripped, kind of like :id. If you escape it, you should be ok. Try http://localhost\:3000/api/:id instead. You may run into this again in routes or other places.
There is an issue regarding this behavior in case something changes.
Updated: http://localhost\\:3000/api/:id
Because angular intercept the url and consider the :any as a parameter that you should pass to it.
An easy way to hack this is to put \:3000 in your url.
motoAdsServices.factory('Brand', ['$resource', function($resource) {
return $resource('http://localhost:3000\:3000/api/:id', {}, {
query: {
method: 'GET',
params: {
id: 'brands'
},
isArray: true
}
});
}]);
Quick fix for the resource plugin issue:
var fixedTargetUrl = TARGET_URL.replace(/(:\d{4})/, "\\$1");

How to construct a REST API that takes an array of id's for the resources

I am building a REST API for my project. The API for getting a given user's INFO is:
api.com/users/[USER-ID]
I would like to also allow the client to pass in a list of user IDs. How can I construct the API so that it is RESTful and takes in a list of user ID's?
If you are passing all your parameters on the URL, then probably comma separated values would be the best choice. Then you would have an URL template like the following:
api.com/users?id=id1,id2,id3,id4,id5
api.com/users?id=id1,id2,id3,id4,id5
api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5
IMO, above calls does not looks RESTful, however these are quick and efficient workaround (y). But length of the URL is limited by webserver, eg tomcat.
RESTful attempt:
POST http://example.com/api/batchtask
[
{
method : "GET",
headers : [..],
url : "/users/id1"
},
{
method : "GET",
headers : [..],
url : "/users/id2"
}
]
Server will reply URI of newly created batchtask resource.
201 Created
Location: "http://example.com/api/batchtask/1254"
Now client can fetch batch response or task progress by polling
GET http://example.com/api/batchtask/1254
This is how others attempted to solve this issue:
Google Drive
Facebook
Microsoft
Subbu Allamaraju
I find another way of doing the same thing by using #PathParam. Here is the code sample.
#GET
#Path("data/xml/{Ids}")
#Produces("application/xml")
public Object getData(#PathParam("zrssIds") String Ids)
{
System.out.println("zrssIds = " + Ids);
//Here you need to use String tokenizer to make the array from the string.
}
Call the service by using following url.
http://localhost:8080/MyServices/resources/cm/data/xml/12,13,56,76
where
http://localhost:8080/[War File Name]/[Servlet Mapping]/[Class Path]/data/xml/12,13,56,76
As much as I prefer this approach:-
api.com/users?id=id1,id2,id3,id4,id5
The correct way is
api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5
or
api.com/users?ids=id1&ids=id2&ids=id3&ids=id4&ids=id5
This is how rack does it. This is how php does it. This is how node does it as well...
There seems to be a few ways to achieve this. I'd like to offer how I solve it:
GET /users/<id>[,id,...]
It does have limitation on the amount of ids that can be specified because of URI-length limits - which I find a good thing as to avoid abuse of the endpoint.
I prefer to use path parameters for IDs and keep querystring params dedicated to filters. It maintains RESTful-ness by ensuring the document responding at the URI can still be considered a resource and could still be cached (although there are some hoops to jump to cache it effectively).
I'm interested in comments in my hunt for the ideal solution to this form :)
You can build a Rest API or a restful project using ASP.NET MVC and return data as a JSON.
An example controller function would be:
public JsonpResult GetUsers(string userIds)
{
var values = JsonConvert.DeserializeObject<List<int>>(userIds);
var users = _userRepository.GetAllUsersByIds(userIds);
var collection = users.Select(user => new { id = user.Id, fullname = user.FirstName +" "+ user.LastName });
var result = new { users = collection };
return this.Jsonp(result);
}
public IQueryable<User> GetAllUsersByIds(List<int> ids)
{
return _db.Users.Where(c=> ids.Contains(c.Id));
}
Then you just call the GetUsers function via a regular AJAX function supplying the array of Ids(in this case I am using jQuery stringify to send the array as string and dematerialize it back in the controller but you can just send the array of ints and receive it as an array of int's in the controller). I've build an entire Restful API using ASP.NET MVC that returns the data as cross domain json and that can be used from any app. That of course if you can use ASP.NET MVC.
function GetUsers()
{
var link = '<%= ResolveUrl("~")%>users?callback=?';
var userIds = [];
$('#multiselect :selected').each(function (i, selected) {
userIds[i] = $(selected).val();
});
$.ajax({
url: link,
traditional: true,
data: { 'userIds': JSON.stringify(userIds) },
dataType: "jsonp",
jsonpCallback: "refreshUsers"
});
}