Restangular, is it possible to do a Post without a previous reading? - restangular

In the documentation's examples, each POST is preceded by a reading, is it possible to do a Post without this previous step?
Bye,
Hervé

Restangular need to know to which resource you are going to post, this is a required step, otherwise it won't be able to generate the url.
To not get data, you just need to not use get() or getList() methods.
So any of those should work :
var account = Restangular.service("accounts");
account.post({data});
var account Restangular.oneUrl('googlers', 'http://www.google.com/1');
account.post({data});
// the 'one()' method will allow you to use 'account.save()' later which will decide to POST or PUT accordingly
var account = Restangular.one("accounts");
account.post({data});

Related

RESTfully change operation behaviour

The Situation:
Via POST operation, users can create a new resource based on given parameters. If there already exists a resource created from these same parameters, the existing resource is returned instead.
Users are able to GET this resource if they know the resource ID (generated on creation, and is effectively random). I would like to provide users a way to check existence only knowing the creation parameters and without creating a new resource.
The Question:
Would it be RESTful to take some kind of "just-checking" property in the POST body to prevent a new resource from being created?
An Example:
POST vehicle
{
colour: 'red',
wheels: 4
}
201: {
vehicleId: '314-159',
colour: 'red',
wheels: 4
}
GET vehicle/314-159
200: {
vehicleId: '314-159',
colour: 'red',
wheels: 4
}
POST vehicle
{
colour: 'red',
wheels: 4,
check: true
}
200: {
vehicleId: '314-159',
colour: 'red',
wheels: 4
}
POST vehicle
{
colour: 'blue',
wheels: 8,
check: true
}
404: Not Found
Edit
Much of the discussion has been around whether the POST operation should be idempotent, which, while valid, does not address my question.
I would like to provide my users with a way to validate the existence of a resource based only on the properties that would be used to create the resource.
The idempotency of the POST method is irrelevant. What suffers from the absence of this check is subsequent GET requests which will contain a number of resources that are never intended to be used, and make it more difficult to find useful information.
A POST request containing a "do-not-create" flag would fill this need, but may not feel RESTful.
How about implementing an idempotent post? In doing so you could avoid the “check” body param.
2 ideas:
Use PUT and natural keys
One option (not sure if this works for you) is to not use some database-id in the url but use something that's a bit more like a natural key.
So instead of POSTing on some collection, you just PUT the item:
PUT /vehicles/colour/blue/wheels/8
PUT can also be used for creation just fine. And you could use a header such as this to prevent overwriting existing values:
If-None-Match: *
Don't put it on the client to do this
What if a POST for creating an item is identical to updating it? Or, what if you call POST on an existing item, it just doesn't actually do anything.
Maybe the client doesn't need to know if it just created a new item, or if the server already had that item.
Just make sure that for those 2 cases the server behaves the same, and you should be good.
Users are able to GET this resource if they know the resource ID (generated on creation, and is effectively random). I would like to provide users a way to check existence only knowing the creation parameters and without creating a new resource.
How would you do it with a web site?
Probably, with a form, that would accept as inputs the same creation parameters. The user is in effect performing a search, which is a semantically safe operation, so the form would likely use the GET method and have the arguments from the form encoded into the query string.
The endpoint, on receiving that request, could redirect it to the appropriate resource (if one already exists) or to another resource to handle the case when it doesn't.
Would it be RESTful to take some kind of "just-checking" property in the POST body to prevent a new resource from being created?
Sure - again, how would you do this on a web site? The form would have an extra checkbox, set to the correct default behavior, but giving the user the option to change it before submitting the form.
Because switching the check box changes the semantics from a safe operation to an unsafe operation, you might want to change the method on the form during submission -- HTML by itself doesn't do that, but you can do it with javascript aka code on demand.
Using POST for safe operations isn't ideal, because generic components can't tell that the operation is safe. This means that they can't know to automatically retry the request if the response is lost, they don't have the correct default cache behaviors, and so on.
For the record, the solution chosen was to add options for a special case on the GET method.
As touched on in this answer, it is not quite in the spirit of the POST method to perform this type of operation, and it muddies the model being presented to the users.

Linkedin API oAuth 2.0 REST Query parameters

I'm running into a problem with adding a query to the callback URL. I'm getting an invalid URI scheme error attempting to authorize the following string:
https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=75df1ocpxohk88&scope=rw_groups%20w_messages%20r_basicprofile%20r_contactinfo%20r_network&state=7a6c697d357e4921aeb1ba3793d7af5a&redirect_uri=http://marktest.clubexpress.com/basic_modules/club_admin/website/auth_callback.aspx?type=linkedin
I've read some conflicting information in forum posts here. Some say that it's possible to add query strings to callbacks, and others say that it results in error.
If I remove ?type=linkedin, I can authorize just fine and receive the token. It would make my life so much easier if I could use a query string on the callback url, as I need to do some additional processing in the callback.
In short, can I append a query string to the end of the callback url?
For fun, I tried encoding the callback url in the request (obviously this is a no-no according to their documentation):
https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=75df1ocpxohk88&scope=rw_groups%20w_messages%20r_basicprofile%20r_contactinfo%20r_network&state=5cabef71d89149d48df523558bd12121&redirect_uri=http%3a%2f%2fmarktest.clubexpress.com%2fbasic_modules%2fclub_admin%2fwebsite%2fauth_callback.aspx%3ftype%3dlinkedin
This also resulted in an error but was worth a shot.
The documetation here: https://developer.linkedin.com/forum/oauth-20-redirect-url-faq-invalid-redirecturi-error indicates that you CAN use query parameters. And in the first request, it appears that I'm doing it correctly. Post #25 on this page - https://developer.linkedin.com/forum/error-while-getting-access-token indicates that you have to remove the query parameters to make it work
Anyone have experience with successfully passing additional query paramaters in the callback url for the linkedin API using oAuth2.0? If so, what am I doing wrong?
I couldn't wait around for the Linkedin rep's to respond. After much experimentation, I can only surmise that the use of additional query parameters in the callback is not allowed (thanks for making my application more complicated). As it's been suggested in post #25 from the question, I've tucked away the things I need in the "state=" parameter of the request so that it's returned to my callback.
In my situation, I'm processing multiple API's from my callback and requests from multiple users, so I need to know the type and user number. As a solution, I'm attaching a random string to a prefix, so that I can extract the query parameter in my callback and process it. Each state= will therefore be unique as well as giving me a unique key to cache/get object from cache..
so state="Linkedin-5hnx5322d3-543"
so, on my callback page (for you c# folks)
_stateString=Request["state"];
_receivedUserId = _stateString.Split('-')[2];
_receivedCacheKeyPrefix = _stateString.Split('-')[0];
if(_receivedCacheKeyPrefix == "Linkedin") {
getUserDomain(_receivedUserId);
oLinkedIn.AccessTOkenGet(Request["code"],_userDomain);
if (oLinkedin.Token.Length > 0) {
_linkedinToken = oLinkedin.Token;
//now cache token using the entire _statestring and user id (removed for brevity)
}
You not allowed to do that.
Refer to the doc: https://developer.linkedin.com/docs/oauth2
Please note that:
We strongly recommend using HTTPS whenever possible
URLs must be absolute (e.g. "https://example.com/auth/callback", not "/auth/callback")
URL arguments are ignored (i.e. https://example.com/?id=1 is the same as https://example.com/)
URLs cannot include #'s (i.e. "https://example.com/auth/callback#linkedin" is invalid)

Sail.js - routing to methods, custom policies & PATCH method

I have a few questions that I couldn't find answers anywhere online.
Does sails.js framework support HTTP PATCH method? If not - does anyone know if there is a planned feature in the future?
By default if I create method in a controller it is accessible with GET request is it the routes.js file where I need to specify that method is accessible only via POST or other type of methods?
How would you create a policy that would allow to change protected fields on entity only for specific rights having users. I.e: user that created entity can change "name", "description" fields but would not be able to change "comments" array unless user is ADMIN?
How would you add a custom header to "find" method which specifies how many items there are in database? I.e.: I have /api/posts/ and I do query for finding specific items {skip: 20; limit: 20} I would like to get response with those items and total count of items that would match query without SKIP and LIMIT modifiers. One thing that comes to my mind is that a policy that adds that that custom header would be a good choice but maybe there is a better one.
Is there any way to write a middle-ware that would be executed just before sending response to the client. I.e.: I just want to filter output JSON not to containt some values or add my own without touching the controller method.
Thank you in advance
I can help with 2 and 5. In my own experience, here is what I have done:
2) I usually just check req.method in the controller. If it's not a method I want to support, I respond with a 404 page. For example:
module.exports = {
myAction: function(req, res){
if (req.method != 'POST')
return res.notFound();
// Desired controller action logic here
}
}
5) I create services in api/services when I want to do this. You define functions in a service that accept callbacks as arguments so that you can then send your response from the controller after the service function finishes executing. You can access any service by the name of the file. For example, if I had MyService.js in api/services, and I needed it to work with the request body, I would add a function to it like this:
exports.myServiceFunction = function(requestBody, callback){
// Work with the request body and data access here to create
// data to give back to the controller
callback(data);
};
Then, I can use this service from the controller like so:
module.exports = {
myAction: function(req, res){
MyService.myServiceFunction(req.body, function(data){
res.json(data);
});
}
}
In your case, the data that the service sends back to the controller through the callback would be the filtered JSON.
I'm sorry I can't answer your other questions, but I hope this helps a bit. I'm still new to Sails.js and am constantly learning new things, so others might have better suggestions. Still, I hope I have answered two of your questions.

How to do role-based authorization with Apache Shiro depending on HTTP request method

I'm struggling to figure out how I can do role-based authorization depending on what HTTP method a request is using. I use HTTP basic auth and depending on the users role and the HTTP method used a request should succeed or fail.
Example:
a GET request to http://localhost/rest/ should always be allowed, even to non-authenticated users (anon access)
a PUT request to http://localhost/rest/ (same resource!) should only be allowed if user is authenticated
a DELETE request to http://localhost/rest/ (same resource!) should only be allowed if user is authenticated and has the role ADMINISTRATOR
My current (non-working) attempt of configuring shiro.ini looks like this:
/rest = authcBasic[PUT], roles[SERVICE_PROVIDER]
/rest = authcBasic[POST], roles[EXPERIMENTER]
/rest = authcBasic[DELETE], roles[ADMINISTRATOR]
/rest = authcBasic
Update
I've just found https://issues.apache.org/jira/browse/SHIRO-107 and updated my shiro.ini to be
/rest/**:put = authcBasic, roles[SERVICE_PROVIDER]
/rest/**:post = authcBasic, roles[EXPERIMENTER]
/rest/**:delete = authcBasic, roles[ADMINISTRATOR]
/rest/** = authcBasic
but it still doesn't work. It seems that only the last rule matches. Also, the commit comment also seems to indicate that this only works with permission-based authorization. Is there no equivalent implementation for role-based authz?
I think HttpMethodPermissionFilter is the one you need to configure: http://shiro.apache.org/static/1.2.2/apidocs/org/apache/shiro/web/filter/authz/HttpMethodPermissionFilter.html This should enable you to map the HTTP method to Shiro's "create,read,update,delete" permissions as outlined in the javadoc for the class.
I had a similar situation with Shiro and my REST application. While there may be a better way (I hadn't seen SHIRO-107), my solution was to create a custom filter extending the Authc filter (org.apache.shiro.web.filter.authc.FormAuthenticationFilter). You could do something similar extending the authcBasic filter or the Roles filter (although I think authcBasic would be better as it is probably more complicated).
The method you want to override is "protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)". Your argument (e.g. "ADMINISTRATOR") will come in on the mappedValue as String[] where the arguments were split by commas.
Since I needed the possibility of both a method and a role, I ended up have my arguements looks like "-". For example:
/rest/** = customFilter[DELETE-ADMINISTRATOR]
That let me split out the role required to perform a delete from the role required for a POST by doing something like:
/rest/** = customFilter[DELETE-ADMINISTRATOR,POST-EXPERIMENTER]
I think if you play with this, you'll be able to get the functionality you need.
BTW, I hadn't seen SHIRO-107, so I've not tried that technique and probably won't since I've already invented my own custom filter. However that may provide a cleaner solution than what I did.
Hope that helps!

Tastypie build_filters access tp request.user

Is there any way to access the user that initiated the request in build_filters override in tastypie.
I want to use the logged in user to give context to one of the filters for example filter contains the word Home and i want to use this as a lookup to the requesting users locations to find their home address.
If build filters took the request as an argument this would be easy as i could simply call
request.user.get_profile().userlocation_set.get(name_iexact=filters['location'])
Is there anyway to force the user into the list of filters or alternatively enrich get parameters before they are passed to build_filters.
There still isn't a great method for this. I'm currently overriding obj_get_list like so, so that I can manually pass the bundle object to build_filters:
def obj_get_list(self, bundle, **kwargs):
filters = {}
if hasattr(bundle.request, 'GET'):
filters = bundle.request.GET.copy()
filters.update(kwargs)
applicable_filters = self.build_filters(filters=filters, bundle=bundle)
try:
objects = self.apply_filters(bundle.request, applicable_filters)
return self.authorized_read_list(objects, bundle)
except ValueError:
raise BadRequest("Invalid resource lookup data provided (mismatched type).")
There is currently an open pull request for this change:
https://github.com/toastdriven/django-tastypie/pull/901
I haven't found a way to do that. I generally 'cheat' by adding the code into apply_authorization_limits where the session is available.