I am trying to make a REST API with CakePHP but I'm not sure how to approach resources that are more than one level down. For example, I want to make my API so that when a client sends a get request to /users/1/friends.json, a JSON representation of that user's friends is returned. What would be the preferred way to approach this? Should I create a Friendships controller and model and reroute as necessary or perhaps keep everything in the users controller? Just want to know what the standard way of doing this is.
If you want to expose a lot of features like: creating/updating/deleting a user, getting a user, getting all users, etc. you end with a lot of methods in your controller.
I would suggest to use different controllers:
a UserController which owns CRUD methods related to a user, and a method to fetch all users. That would mean 5 methods in this controller;
a FriendController which owns all methods related to a friendship relation: getting user's friends but also creating/removing relations between two users.
I don't know CakePHP but I wrote something about Symfony2 REST APIs and my use case was a User API. You could pick ideas like how to manage friendship relations between users.
Related
I have an application where each resource has multiple "sites". A user can have permission to access this resource for a number of these sites or none at all.
I have middleware set up that reads a user from a jwt and adds that user to the context. I then have an authorize attribute that simply checks for the existence of a user.
This is where I could use some help. I am not sure of the best way to conditionally restrict access to the resource (the condition being which site the end-user is specifically requesting the resource from).
I could break the resource into separate action methods and use an attribute that requires a specific role, but that feels a bit too much like duplication, I'd rather not deal with 7 endpoints that basically do the same thing, and adding new sites in the future will require adding a ton of new action methods.
Another solution I had in mind is to create an attribute/filter that compares the end-users permissions to the specific site that they are requesting. This sounds better but I'm not sure how to access specific arguments on the action method from the attribute. Also not sure of the best way to store all of a users "Roles" on an entity class...
Any insight is appreciated.
When an authenticated user wishes to access a resource which he exclusively owns, it seems redundant to specify the user id in the URL path.
Thus, in the following examples, which is the more appropriate way to name my API endpoint?
Example 1
User wants to change profile pic
PUT /users/{id}/profile-pic
or
PUT /profile/profile-pic
Example 2
User wants to add a hobby to his profile
POST /users/{id}/hobbies
or
POST /profile/hobbies
It's a joy to see people paying attention to their API design in terms of URI and responses. An API that is not well designed is going to quickly die since people will avoid using them.
Even if it's not going to be public and no one will use it aside from yourself or your team, think of your colleagues and your future self and take some time to think about how your URIs will look like.
Back to your question my friend, according to the hands-on restful API design patterns and best practices book, that I invite you to read,the REST API is composed of four unique archetypes, as
follows:
Document: The document is the base for a resource representation with a field and link-based structure.
https://api-test.lufthansa.com/v1/profiles
https://api-test.lufthansa.com/v1/profiles/customers
Collection: A collection is also a resource, and it is a directory of resources managed by the API providers or servers.
https://api-test.lufthansa.com/v1/profiles/customers/accountbalance
https://api-test.lufthansa.com/v1/profiles/customers/memberstatus
Stores: A store is a resource repository managed by the client. The store allows the API client to put resources in, choose URIs for the resources that get added, get them out, and delete them when it decides.
http://api.example.com/cart-management/users/{id}/carts
http://api.example.com/song-management/users/{id}/playlists
Controller: Controller resources are similar to executable methods, with parameters and return values. REST API relies on controller resources to perform application-specific actions that do not come under any of the CRUD methods.
POST /alerts/245245/resend
So, in your case, you can follow the API design of GitHub API. Look how they are retrieving the projects of an organisation. Yours would look this way:
PUT /users/{id}/profile-pic
POST /users/{id}/hobbies
I'm sorry for making it long, I wanted to base my perspective on something concrete.
When an authenticated user wishes to access a resource which he exclusively owns, it seems redundant to specify the user id in the URL path.
It shouldn't; the semantics of a resource identifier and the semantics of an Authorization header are different.
The fact that only Bob can get a copy of /profile/Bob is a matter of access policy, not message semantics.
Review Fielding's definition of resource. "Bob's profile" and "Alice's profile" are distinct nameable information (assuming for the moment that Bob and Alice are themselves distinct) and therefore should have different identifiers.
That's the "RESTful" answer.
In practice, HTTP has special rules about authentication, and the handling of authenticated requests means that you'll probably "get away with" treating the Authorization header as part of the identifier of the resource (particularly in the case where an authorized user is only allowed to access their own resource hierarchy).
I'm trying to implement WSO2IS for authorization. My understanding is that in the WSO2 realm, the concept of a permission broadly restricts a user's access to an action, or a resource. So, for instance, if my app is a bookstore, I could configure whether a user has "read" access to authors at large, and toggle their access to the GetAuthors() endpoint. However, I need to configure a user's access to certain authors. Is there a way I can store a whitelist of authors on a per-user basis? What I'd like to accomplish is to have a user call a GetBooks() endpoint and return only the books written by the authors that the user can access.
It sounds like one possibility is to store this information in an external datastore, and implement a custom PIP to read from that datastore.
Another possible option would be to create a custom attribute on the User type and store the whitelist of author IDs in an array on each user.
Is there a better way to do this? I'd prefer not to implement a custom external datastore just to store relationships between users and entity ids. Is it possible to do this with XACML and policies? Is it possible to have WSO2IS stick this information on a claim that is returned to my controller so that I can limit my underlying query based on the user's whitelist of allowed entity IDs?
AFAIU you need to maintain a claim to track the accessibility for reading. You can easily create a custom claim to track it by following the article[1]. In this way, you can refer to the custom claim at the controller to make further decisions.
You have to update this claim value for each user. For this, you can use SCIM API[2] by following doc[3] to extend the SCIM endpoint for custom claims.
[1]https://medium.com/#inthiraj1994/lets-add-a-custom-claim-to-oidc-in-wso2-is-d871e418d6b0
[2]https://is.docs.wso2.com/en/latest/develop/scim2-rest-apis/#/scim-20-api-definition
[3]https://is.docs.wso2.com/en/latest/develop/extending-scim2-user-schemas/#extending-scim-20-user-schemas
This might be very simple; I don't know Rails very well.
I have a match myController/myAction/myID in my routes.rb that will direct hyperlinks to the proper page (using link_to). But here's the problem: I don't want people to be able to freely modify the id parameter, passing in via the URL whatever they like.
Is there a way to perhaps restrict access to routes to the link_to method only? Or maybe there's another way to go about this, using a passed in hidden variable param or something?
Users access you site via urls like: /controller/action/:id right? A user can change an id and must not view another non authorized resource. How to achieve this?, on your controller, return only those resources that user is allowed to access.
For example, suppose that you are using devise:
class AController < ApplicationController
def index
#resouces = current_user.find_all_by_id params[:id]
end
end
This way if the user tries to access something he does not have access to, he will get an error.
Hope this helps, if not please let me know and I'll try to elaborate.
About current_user, yes it is supposed to be the current logged in user, it doesn't have to be devise, you can implement your own session handling logic and then create a helper method to retrieve the currently logged in user.
About using devise, if you don't want to implement your own session handling logic, plus if you want features like:
remember me
already created views that you can fully customize
authentication
authorization
password encryption
many more (please look at the docs for further information)
Then devise is a good way to go.
Also, it is always a great idea, if possible and as a learning exercise, implement your own authentication and authorization layers, you won't regret.
Best regards
Emmanuel Delgado
I want to link a model Tasks to a User properly, to make sure that only an authenticated user can access only the Tasks and dependent models that belong_to User and Task
My user model was generated using nifty authentication from Railscasts' Ryan B
I'm having a lot of trouble finding a guide on how to set up these views to be secure.
Any suggestions SO?
I think you are looking for an authorization solution. If this is a simple app, you should set up your controllers to return only tasks belong to the user like so:
#tasks = current_user.tasks
Presumably you have a has_many association set up on your User model. If you do this for all your controllers, they will be scoped to your user, so you don't have to worry about authorization.
If you are looking for a more complex solution, look towards something like cancan.