API design : Need help for URLs - mongodb

I'm designing a new website. Before i start to code, i'm learning a lot about api and nosql database (as i'm used to sql but i want to try with mongoDB).
In mongoDB, i'll have a 'user' document like that :
{
firstname: 'xxxxxxx',
lastname: 'xxxxxxx',
projects: [
{
name: 'project xxxxxxx',
participants: [], // array of friends into this project
operations: [
{ title: 'Title OP xxxxxxx', contributors: [] },
{ title: 'Title OP xxxxxxx', contributors: [] },
{ title: 'Title OP xxxxxxx', contributors: [] }
]
}
]
}
I was wondering two things :
Should projects.participantsand projects.operations.contributors be references to other users ?
For the API, should i do something like :
GET /users/:id_user
GET /users/:id_user/projects/:id_project
GET /users/:id_user/projects/:id_project/operations/:id_operation
(should my API always start with users ?)
If you ever have a better solution I will be glad to know.
Thanks
EDIT 1 : I'll work on NodeJS with Express and i would like to have a REST API.

yes, projects.participants and projects.operations.contributors can be reference to other documents in the same collection. Each of these should refer to valid _id in the same collection.
can you please put some more light on how exactly are you creating your APIs? I mean which framework you are using as a wrapper to access mongoDB? May be then I can try to help more.

ok great!!!
So, users is your collection name. Its absolutely not necessary to start your API name with users. In node.js you can create a router, which will route your request to a particular js file and you can name it anything you want. Example:
use case: You want to expose 3 API
1. To access all the users. (exposed using url - /getallusers)
2. To access all the participants of the project.(exposed using url - /getparticipantsbyproject)
3. To access all the contributors in the operations.(exposed using url - /getcontributorsbyproject).
You can write all these APIs in your file called myapi and expose them.
Now, you can very well call these APIs from browser using below urls:
http://host:port/myapi/getallusers
http://host:port/myapi/getparticipantsbyproject
http://host:port/myapi/getcontributorsbyproject

Its about RESTful API only. I mentioned 3 urls above which are nothing but RESTful API exposing different functionalities.

Related

Restful web service, partial Read permission

I am designing a restful web service to create and read reports made from an app. When creating a report its possible to add some privacy sensitive information with it like a name, phone number, mail etc. After creating the report its made publicly visible through the same web service.
POST /report
{
"name":"test",
"email":"test#example.com",
"report_contents":....
}
returns 200 OK with:
{
"id":1,
"report_contents":....
}
and a method to get said report:
GET /report/{report_id}
I have another app with which an admin can manage the reports created though the previous web service. In this application I would like to display the privacy sensitive information. It uses the following URL to get a specific report.
GET /report/{report_id}
which returns 200 OK:
{
"id":1,
"name":"test",
"email":"test#example.com",
"report_contents":....
}
Now there is the issue. This is the exact same url. Is it Is it possible/conventional or even a good idea to use the same web service for both calls, but have some kind of CRUD management with it where depending on the role of the user a part of the information is not displayed/blocked? Or would it be better to make a separate web service with restrictions?
Yes, it's OK for different representations of the same resource to be returned at the same URL for different requests. That's how content negotiation works.
If you are concerned about this, I can think of two options:
One option is to include a query parameter to make the choice of views explicit, and access can be controlled for each. E.g.
/report/{report_id}?view=full
/report/{report_id}?view=restricted
Or you could also consider two sub-resources, one called /report/{report_id}/full and one called /report/{report_id}/restricted, and then you can return a 40x code when the user doesn't have correct permission, with a Location header as a hint of where they can look.
If your language of choice supports it, you could return a dynamic object.
here's some pseudo code.
if (loggedInUser != isAdmin(user))
return new { id: 1, contents: "..." }
else
return new { id: 1, name: "test", email: "test#test.com", contents: "..." }
Personally, I would have different areas that do different things. One area that retrieves the model for everyone. In the other it'd be like an admin area.
In the one area, you have

Best approach for updating a relation to another resource in a REST API

Let's say I have a REST API adhering to basic HATEOAS principles. Items belong to a User.
GET /item/13
{
id: 13,
name: 'someItem',
type: 'someType',
_links: [
{
rel: 'user',
href: '/user/42'
}
]
}
Now I need a way to change the user for a given item. Using either a PUT or a PATCH, which is the preferable way of performing that modification?
Establish the new relation by setting the id of the new linked resource as a simple property in the JSON body
PATCH /item/13
{
userId: 43
}
Establish the new relation by having the client pass the link itself as the input
PATCH /item/13
{
_links: [
rel: 'user',
href: '/user/43'
]
}
I usually think of links as read-only representations of relations stored in other formats (such as id:s to other resources), returned from GET calls. It doesn't feel very natural to me to have links as input to POST/PUT/PATCH calls, and the fact that links is an array makes it even stranger (should you be able to update all links? One single link?), but I have seen it suggested in various articles. Is there a best practice? What would be the benefits of using the links approach?
The point of REST is (at least one of them) is to make everything visible through a standard interface. In other words, if the 'relations' are a thing, than it too should have its own resource.
The API should also be more descriptive. This might be subjective, and I don't know all the details of your model/design, but 'items' don't have 'links'. 'Items' might instead have a single 'owner'. If this is the case, it might look something like:
GET /item/123/owner
So POSTing or PUTing an URL of a user (or some simple representation) would 'change' the owner of the item. It might be not allowed to DELETE the owner, depending on if the model allows unowned items.
Note, that the representation under "/item/123" would in this case have to link to "/item/123/owner", since the client only follows links it gets from the server.
So, think about what are important 'things', all of those should have a resource. Also, try to add as much 'meaning'/semantics as you can. The relation should not be called 'user', it should be called 'owner' (or whatever the meaning should be in your model).

RESTful API design - how to handle foreign keys?

I'm designing a RESTful API and I'm trying to figure out how to show and update foreign keys for resources.
Let's I have an object User and it has an id, name and a foreign key (many-to-one relation) to entity: Computer.
What I see in most of the examples online:
GET /users/1
{
id: 1,
name: "Bob",
computer: "<url>/computers/5"
}
Which I can understand, it's a link to another resource. But what do you do when you want to pick another computer for bob?
PUT /users/1
{
name: "Bob",
computer: "<url>/computers/4"
}
This feels really weird.
I'm also thinking about the following case: Say the person that has to implement the API can choose a computer for Bob using a dropdown and the current one should be selected, I'd need the id to do that. Do I have to parse the url myself to chop off the id?
Is there a reason why I should not just do:
GET /users/1
{
id: 1,
name: "Bob",
computerId: 5
}
PUT /users/1
{
name: "Bob",
computerId: 4
}
I would be tempted to formalise the HATEOAS a little here and have:
GET /users/1
{
links: [
{ rel: "computer", href: "/users/1/computers/5" },
],
user: {
id: 1,
name: "Bob",
computer: 5,
}
}
PUT /users/1
{
name: "Bob",
computer: 4,
}
GET /users/1
{
links: [
{ rel: "computer", href: "/users/1/computers/4" },
],
user: {
id: 1,
name: "Bob",
computer: 4,
}
}
The link URLs can obviously be /computers/n if that's your preference.
This allows your representations to consistently be just data, AND the body of GETs to supply the URLs that your application can use. This way, if you change your URL hierarchy (i.e from /computers/n to /users/m/computers/n) you do not need to change any client code that manually constructs URLs.
By GET you have to use the link to meet with the HATEOAS constraint.
{
id: 1,
name: "Bob",
computer: {uri: "<url>/computers/5"}
}
By PUT you can use the id
{
name: "Bob",
computer: {id: 4}
}
The idea about this that the URIs (or URI templates) must be generated by the server. So the client does not have to know how to build an URI, which makes the service+client code DRY, or in other terms it loosens the coupling between the client and the service implementation.
(You can use a standard (or a draft) solution instead of your custom one to describe hyperlinks. For example: ATOM, XLink, RDF+Hydra, HAL, etc..)
If you're really embracing HATEOAS, you should just use the URI. The URI is your identifier, not the id field. I would remove that entirely. Sure, inside your application you'll have to parse the URI in the payload -- and you already have the parser, obviously -- but It's better for you to do that than asking the client to do.
If you or your clients are sending id fields other than URIs in the payload, or if you're asking the client to parse URIs and figure out semantics, you're defeating the purpose of using HATEOAS, as the client implementation will be coupled to that semantics. The best thing is to embrace URIs as the only identifiers you'll use to drive the interaction with clients.

How to deal with a REST API structures redundancy?

I am currently build a REST API for a webservice that, amongst other things, handles user bans.
The current API I designed look like:
URL: GET /user/<user_id>/bans/<session_id>
Description: Get the ban on the specified session for the specified user.
Output:
{
session_id: 1,
banned_until: "..."
}
URL: GET /user/<user_id>/bans
Description: Get all bans for the specified user.
Output:
[
{
session_id: 1,
banned_until: "..."
},
{
session_id: 2,
banned_until: "..."
}
]
URL: PUT /user/<user_id>/bans/<session_id>
Description: Set or update a ban on the specified session for the specified user.
Input:
{
session_id: 1,
banned_until: "..."
}
Output:
{
session_id: 1,
banned_until: "..."
}
Now one of my coworkers believes that the API is wrong because, for instance in the case of the PUT, the user has to specify the session_id twice: once in the URL and once in the content and those two have to match (which means an extra check server-side). He makes the same comment for the GET where the user specifies the session id in the URL to get it back in the response, meaning a waste of bandwidth.
While I understand his concerns, I however think the current design as it is, is simpler for the user (only one data structure to care about) and that the extra check on the server isn't that much work to do compared to the comfort it brings the user.
Is there an official guideline regarding this in the REST best-practices ? What is the usual/recommended way of dealing with this ?
Personally, I think what you are talking about is the different between the PUT and POST methods.
From the RESTful CookBook:
Use PUT when you can update a resource completely through a specific resource. For instance, if you know that an article resides at http://example.org/article/1234, you can PUT a new resource representation of this article directly through a PUT on this URL.
So, in the PUT example you gave, I think it is perfectly valid to specify the sessionID in the URL since you are storing the ban at a specific point.
However you could also create a POST service at URL: POST /user/<user_id>/bans to satisfy your co-worker. :-)

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.