I'm trying to follow JSON API. I need to expose CRUD access to a nested resource: product reviews.
Prior to using JSON API, I'd expect a REST interface like this:
GET /products/:product_id/reviews - list reviews for a product
POST /products/:product_id/reviews - add a review for a product
PATCH /products/:product_id/reviews/:id - update a review for a product
DELETE /products/:product_id/reviews/:id - delete a review for a product
I see some mention of a nested structure like this in the spec:
For example, the URL for a photo’s comments will be:
/photos/1/comments
But I'm not sure whether this structure is intended for all actions.
On the one hand, POST /products/:product_id/reviews for creation seems redundant if I'm going to specify the product in the POST body, under the review data's relationships.
On the other hand, if it's useful to specify a product id when deleting a review (maybe it isn't), DELETE /products/:product_id/reviews/:id seems like the only sane way to do it; people argue about whether a request body is even allowed for DELETE requests.
I could nest for some requests and not others:
GET /products/:product_id/reviews - list reviews for a product
POST /products/:product_id/reviews - add a review for a product
PATCH /reviews/:id - update a review
DELETE /reviews/:id - delete a review
But that seems weirdly inconsistent.
I could never nest:
GET /reviews - list reviews for the product specified in params
POST /reviews - add a review for the product specified in params
PATCH /reviews/:id - update a review
DELETE /reviews/:id - delete a review
But that seems awkward, and doesn't seem to match the first quote I made from the docs.
Should nested resource relationships be reflected in the URL when using JSON API?
I really like your question, since I have been having the same thoughts. I'm puzzled that no one has left an answer yet.
I have been using JSON API a little over a year on a production system and I would like to give my two cents.
At first when I started the project that was going to use JSON API, I was in doubt of nested vs non-nested resources. I then ran into issues with nested resources that would have been avoided with non-nested resources.
To take the same paths as in your example, consider the GET /products/:product_id/reviews endpoint.
When this is made it make very much sense to nest a review under a product because we are initially showing reviews in context of a product. Everything is good.
We then later want to build a page in the frontend that shows a user and all the reviews that user has authored.
Although we already have an endpoint for getting reviews, we will have to build a new one, e.g. GET /users/:id/reviews.
If we hade just put the first endpoint on GET /reviews with a filter of ?filter[product_id]=:id, we could just add a new filter to that endpoint, which makes much sense IMO.
I do use nested resources, but only for singleton resources like GET /users/:id/email_settings and a few other special cases where it makes sense.
In my experience, it makes it easier in the future if each resource is thought of as independent from other resources. There exists resources and relationships between resources. No resource "owns" another resource in the context of the API (in context of business-logic it's another story).
I have worked with this strategy and it still surprises me how well it works when adding new functionality to existing endpoints and when adding new endpoints.
If you coming from CQRS camp, you will understand why design Restful API sometimes awkward. It is awkward because naturally Query actions (GET) and Mutation actions (POST, PATCH, DELETE) should talk in two different languages.
Query actions naturally relationship-oriented and data rich; while Mutation actions not. So it feel easy to use nested URL to traversal between relationship entities.
But Mutation you should provide just enough information for tasks. Sometimes it is redundant like your Post example. Sometimes missing like your DELETE example. Sometimes you have a task involve many resources; you don't know where to put in.
You should check Facebook Graph API or Azure Graph API, they met same problems and have some good solutions. It's important that you should follow consistent design.
Some rules are:
DELETE, UPDATE always to direct resource.
POST use with nested resource if you want create both object and main relationship. Secondary relationships should put in BODY. If you have two equal relationships, consider have both nested APIs.
Use POST against fake resource to for tasks involve with many resources.
POST /transferfund
Use POST against fake relationship for tasks could not fit with any HTTP verbs. For example, you want have body for delete action, use
POST /resource/id/deleteItForMe
{ reason: "I hate it"}
Related
As per REST framework, we can access resources using GET method, which is fine, if i know key my resource. For example, for getting transaction, if i pass transaction_id then i can get my resource for that transaction. But when i want to access all transactions between two dates, then how should i write my REST method using GET.
For getting transaciton of transaction_id : GET/transaction/id
For getting transaction between two dates ???
Also if there are other conditions, i need to put like latest 10 transactions, oldest 10 transaction, then how should i write my URL, which is main key in REST.
I tried to look on google but not able to find a way which is completely RESTful and solve my queries, so posting my question here. I have clear understanding of POST and DELETE, but if i want to do same update using PUT for some resource based on condition, then how to do it?
There are collection and item resources in REST.
If you want to get a representation of an item, you usually use an unique identifier:
/books/123
/books/isbn:32t4gf3e45e67 (not a valid isbn)
or with template
`/books/{id}
/books/isbn:{isbn}
If you want to get a representation of a collection, or a reduced collection you use the unique identifier of the collection and add some filters to it:
/books/since:{fromDate}/to:{toDate}/
/books/?since="{fromDate}"&to="{toDate}"
the filters can go into the path or into the queryString part of the url.
In the response you should add links with these URLs (aka HATEOAS), which the REST clients can follow. You should use link relations, for example IANA link relations to describe those links, and linked data, for example schema.org or to describe the data in your representation. There are other vocabs as well, for example GoodRelations, and ofc. you can write your own vocab as well for your application.
When representing data models through a RESTful interface it is understood to create top level endpoints that associate to a type/group of objects:
/users
/cars
We can re-use HTTP verbs to enable actions upon these groups (GET to list, POST to create, etc). And when representing a model with a "dependency" (being that it can't exist without a "parent"), we can create deeper endpoints to represent that dependency relationship:
/users/[:id]/tokens
In this case, it makes sense to not have a top-level endpoint of /tokens, as they shouldn't be able to exist without the user.
Many-to-many relationships get a bit more tricky. If two models can have a many-to-many relationship but can also truly exist on their own, it makes sense to give both objects a top-level endpoint and a deeper endpoint for defining that relationship:
/users
/cars
/users/[:id]/cars
/cars/[:id]/users
We can then use PUT and DELETE methods to define those relationships through an HTTP interface: PUT /users/[:user_id]/cars/[:car_id]. It makes sense that running that PUT operation would create a data-model that somehow links the two objects (like a join table in a relational DB).
The tricky part, then, becomes deciding on where to limit the interface to combat redundancy.
Do you allow a GET request to the second-level deep endpoints (GET /users/[:user_id]/cars/[:car_id])? Or do you require that they access the "car" from the top level GET /cars/[:id]?
Now, what if the many-to-many relationship contains meta information? How do you represent that and where do you return it?
For example, what if we wanted to keep track of how many times a user drove a certain car? Where would we return that information? If we return it at the nested endpoint, are we violating REST or being inconsistent if we return the meta information and not the resource? Do we embed the meta information in the requested resource through an attribute of some kind?
Pls advise. :P (but really, thanks)
This is really more of a personal design preference at this point IMHO.
I would personally opt for stopping at /users/[:user_id]/cars/ and then requiring a call to /cars/[:car_id] to get the car information.
If you are including relation specific metadata though, like "how many times a user drove a certain car?" it would make sense to keep that under a deeper relationship like /users/[:user_id]/cars/[:car_id].
Truthfully it's not an exact science. You have to do what is simplest, most expressive, yet still powerful enough for your data model.
You could create a new resource. Something like users/[:user_id]/cars/[:car_id]/stats, whose response includes {drivings_count: 123}. You'd probably only allow a GET of this resource.
For a while I was (wrongly) thinking that a RESTful API just exposed CRUD operation to persisted entities for a web application. When you code something up in "the real world" you soon find out that this is not enough. For example, a bank account transfer doesn't have to be a persisted entity. It could be a transient resource where you POST to /transfers/ and in the payload you specify the details:
{"accountToCredit":1234, "accountToDebit":5678, "amount":10}
Using POST here makes sense because it changes the state on the server ($10 moves from one account to another every time this POST occurs).
What should happen in the case where it doesn't affect the server? The simple first answer would be to use GET. For example, you want to get a list of savings and checking accounts that have less than $100. You would then call something like GET to /accounts/searchResults?minBalance=0&maxBalance=100. What happens though if your search parameter need to use complex objects that wouldn't fit in the maximum length of a GET request.
My first thought was to use POST, but after thinking about it some more it should probably be a PUT since it isn't changing the state of the server, but from my (limited) understanding I always though of PUT as updating a resource and POST as creating a resource (like creating this search results). So which should be used in this case?
I found the following links which provide some information but it wasn't clear to me what should be used in the different cases:
Transient REST Representations
How to design RESTful search/filtering?
RESTful URL design for search
I would agree with your approach, it seems reasonable to me to use GET when searching for resources, and as said in one of your provided links, the whole point of query strings is for doing things like search. I also agree that PUT fits better when you want to update some resource in an idempotent way (no matter how many times you hit the request, the result will be the same).
So generally, I would do it as you propose. Now, if you are limited by the maximum length of GET request, then you could use POST or PUT, passing your parameters in a JSON, in a URI like:
PUT /api/search
You could see this as a "search resource" where you send new parameters. I know it seems like a workaround and you may be worried that REST is about avoiding verbs in the URIs. Well, there are few cases that it's still acceptable and RESTful to use verbs, e.g. in cases where calculation or conversion is involved to generate the result (for more about this, check this reference).
PS. I think this workaround is still RESTful, but even if it wasn't, REST isn't an obsession and an ultimate goal. Being pragmatic and keeping a clean API design might be a better approach, even if in few cases you are not RESTful.
I am working on an Adobe Flex front-end with a Java back-end using JPA for persistence. The protocol I am using is remote objects (AMF) implemented with BlazeDS.
I started out with a service-facade and entity DAOs, but without any specific DTOs. The same POJOs, the domain objects, were passed in the service-facade as those used as DTOs passed to the Hibernate DAOs.
However, the latest few days I have been thinking whether this is a good approach or not. The latest article on the subject I read was this one:
Interesting JPA Pattern blog
The situation:
Say I have POJO Book with a unidirection ManyToOne relation with the POJO Category (i.e. each book may only be associated with one category, but the same category may be associated with many books). I see some alternatives:
Alternative 1:
I expose a method/operation addUpdateBook(Book book). In the implementation of this operation I add/update both the book and the referenced category. I mean, if the client submits a book having a category that doesn't exist from before, this would mean that the client implicitly may edit categories using the addUpdateBook operation.
the client is working directly with the domain model!
the entire category information will be sent when a new book is added
even though a reference to the category would be sufficient
Alternative 2:
I expose a method/operation addUpdateBook(Book book,Long categoryId). In the implementation I retrieve the category for the given categoryId and replace the category given in the book POJO and then I persist the book. In other words, I ignore any category in the book object, I just look at the categoryId. This means that the client would need to use another operation in order to modify the category.
pro: the client can still work more or less on the domain model, but ...
con: ... it is confusing for the client that the category of the book
object will be ignored
con: the entire category information of the book will be sent, even
if the server never will read it
pro: it may be more clear when a separate operation should be used
for category modifications
con: I need to retrieve the category before persisting the book. I
guess this means some overhead.
Alternative 3:
I expose a method/operation addUpdateBook(BookDTO bookDto). The POJO BookDTO looks as the POJO Book, but instead of a field Category category it has a field Long categoryId. In the implementation I retrieve the Category for the given categoryId before I persist the Book.
pro: not confusing for the client
con(?): what should the method getBook(Long bookId) return? should it
return only the BookDTO? Then it would be required to invoke also the
operation getCategory(Long categoryId) in order to have "the entire
book information". Then the client would need to set together the
different parts to a local domain representation of the book.
Compared to alternative 1 this would be more complex on the client
side?
con: I need to retrieve the category before persisting the book. I
guess this means some overhead.
con: being forced to use the DTOs in the client makes it deal with physical details thereby and makes it somewhat distant from the actual domain model. It seems like I am missing the point with having an domain model and using JPA in the business layer.
I guess (!) alternative 3 is the way you would design the operations in a SOA context. However, for me, it is not that important to be loosely-coupled between the client and server. My focus is not to provide multiple client-platform support.
Which alternative would you propose? Are there other better alternatives? Do you know any nice resources, such as code examples, which could help me?
I'm using something related to "Alternative 3". In the beginning I've started to use domain objects (probably also because of my experience with dataservices), after a while I found too many problems and I've switched to DTO's. All the publing services are exposing only DTO's (both for input/output parameters).
Some of the problems that I've met during working directly with the domain objects and BlazeDS:
a)you need to break the domain objects encapsulation (like exposing properties, or exposing private constructors) in order to use them for data transfer. Otherwise you will have to write your own serialization/deserialization.
b)you need to use tricks in order to allow data conversion between client/server. For example, using strings instead of dates in order to prevent timezone difference. Or using strings instead of int/double. You can solve some of these issues by writing custom proxies, but I still think that it's easier to use strings instead of other data types.
c)most of the time you don't need all the data from the domain objects, and in order to deal with that you need to use various frameworks with support for data pagination/lazy instantiation on the client. This frameworks are introducing complexity, and I try to stay away from that.
The main disadvantage of using DTO is the amount of boiler code in order to do the conversion between the domain objects-DTOs...but I still prefer using them.
I have a resource that has a counter. For the sake of example, let's call the resource profile, and the counter is the number of views for that profile.
Per the REST wiki, PUT requests should be used for resource creation or modification, and should be idempotent. That combination is fine if I'm updating, say, the profile's name, because I can issue a PUT request which sets the name to something 1000 times and the result does not change.
For these standard PUT requests, I have browsers do something like:
PUT /profiles/123?property=value&property2=value2
For incrementing a counter, one calls the url like so:
PUT /profiles/123/?counter=views
Each call will result in the counter being incremented. Technically it's an update operation but it violates idempotency.
I'm looking for guidance/best practice. Are you just doing this as a POST?
I think the right answer is to use PATCH. I didn't see anyone else recommending it should be used to atomically increment a counter, but I believe RFC 2068 says it all very well:
The PATCH method is similar to PUT except that the entity contains a
list of differences between the original version of the resource
identified by the Request-URI and the desired content of the resource
after the PATCH action has been applied. The list of differences is
in a format defined by the media type of the entity (e.g.,
"application/diff") and MUST include sufficient information to allow
the server to recreate the changes necessary to convert the original
version of the resource to the desired version.
So, to update profile 123's view count, I would:
PATCH /profiles/123 HTTP/1.1
Host: www.example.com
Content-Type: application/x-counters
views + 1
Where the x-counters media type (which I just made up) is made of multiple lines of field operator scalar tuples. views = 500 or views - 1 or views + 3 are all valid syntactically (but may be forbidden semantically).
I can understand some frowning-upon making up yet another media type, but I humbly suggest it's more correct than the POST / PUT alternative. Making up a resource for a field, complete with its own URI and especially its own details (which I don't really keep, all I have is an integer) sounds wrong and cumbersome to me. What if I have 23 different counters to maintain?
An alternative might be to add another resource to the system to track the viewings of a profile. You might call it "Viewing".
To see all Viewings of a profile:
GET /profiles/123/viewings
To add a viewing to a profile:
POST /profiles/123/viewings #here, you'd submit the details using a custom media type in the request body.
To update an existing Viewing:
PUT /viewings/815 # submit revised attributes of the Viewing in the request body using the custom media type you created.
To drill down into the details of a viewing:
GET /viewings/815
To delete a Viewing:
DELETE /viewings/815
Also, because you're asking for best-practice, be sure your RESTful system is hypertext-driven.
For the most part, there's nothing wrong with using query parameters in URIs - just don't give your clients the idea that they can manipulate them.
Instead, create a media type that embodies the concepts the parameters are trying to model. Give this media type a concise, unambiguous, and descriptive name. Then document this media type. The real problem of exposing query parameters in REST is that the practice often leads out-of-band communication, and therefore increased coupling between client and server.
Then give your system a uniform interface. For example, adding a new resource is always a POST. Updating a resource is always a PUT. Deleting is DELETE, and getiing is GET.
The hardest part about REST is understanding how media types figure into system design (it's also the part that Fielding left out of his dissertation because he ran out of time). If you want a specific example of a hypertext-driven system that uses and doucuments media types, see the Sun Cloud API.
After evaluating the previous answers I decided PATCH was inappropriate and, for my purposes, fiddling around with Content-Type for a trivial task was a violation of the KISS principle. I only needed to increment n+1 so I just did this:
PUT /profiles/123$views
++
Where ++ is the message body and is interpreted by the controller as an instruction to increment the resource by one.
I chose $ to deliminate the field/property of the resource as it is a legal sub-delimiter and, for my purposes, seemed more intuitive than / which, in my opinion, has the vibe of traversability.
I think both approaches of Yanic and Rich are interresting. A PATCH does not need to be safe or indempotent but can be in order to be more robust against concurrency. Rich's solution is certainly easier to use in a "standard" REST API.
See RFC5789:
PATCH is neither safe nor idempotent as defined by [RFC2616], Section
9.1.
A PATCH request can be issued in such a way as to be idempotent,
which also helps prevent bad outcomes from collisions between two
PATCH requests on the same resource in a similar time frame.
Collisions from multiple PATCH requests may be more dangerous than
PUT collisions because some patch formats need to operate from a
known base-point or else they will corrupt the resource.