I have Book resources and Author resources. They're connected, because - obviously - an Author wrote a Book, so the GET Book URL is like:
GET: /authors/{author_name}/books/{book-title}
And this is fine.
I'm puzzled however when it comes to creating (POST) the related resources (in this case, a Book), and can't find anything on the subject in the Symfony area. There are two possibilities:
A REST recommended one:
POST: /authors/{author_name}/books/{book_title}
A Symfony pragmatic one - just:
POST: /books
The latter one with additionally sent author and title within the form - which are not needed in the former one.
The usual way how it is done in Symfony is through use of forms, which I'm using. When I take the pragmatic approach, everything's fine. All the data, including author and book's title are NOT a part of the URL - everything is in the sent form.
The problem is when I would like to take on the REST recommended approach. Then data are split: some come into form, and some other are part of URL.
Let's assume I wanted to choose that "elaborative" URL with some key data in it. How do I "merge" form data BEFORE the form is validated?
(Note also that I can't require the "title" and the "author" fields in the form, though they in fact ARE required when saving the Book to database).
A REST recommended one:
POST: /authors/{author_name}/books/{book_title}
First, I totally disagree that this is the "REST recommended" way. Assuming book_title is your resource identifier, the recommend way would be:
POST: /authors/{author_name}/books
With book_title part of the payload of the request.
Second, I also think it's a big mistake to use author_name and book_title as identifier. What if they change? What about books and authors with the same name? What if a book as multiple authors?
So to answer your question, you don't have a problem because the "REST recommended" approach is the "pragmatic" approach.
Examples:
GET /books/{id}
POST /books
GET /authors/{id}
POST /authors
Related
I read following books and links before I post this question and since this question is about best practices, this question might be closed. However i am expecting some expert views.
https://www.restapitutorial.com/resources.html
REST-API-Design-Rulebook book from oreily
other blogpost and stackoverflow question.
For example to get information about employee with id we are using uri as below
http://myapp-name.myorganization.com/employees/employeeid/123456
But all above resources tell me to do this way
http://myapp-name.myorganization.com/employees/123456
Similarly if i want go get information about employee with id 12345, my uri is as below
http://myapp-name.myorganization.com/countries/country/US/employeeid/12345
as opposed to
http://myapp-name.myorganization.com/countries/US/12345
Does that mean my uri are not standard?
They are just guidelines. You can't cover all kinds of possibilities of your business and necessities on a Rest documentation.
Talking about your examples, the
http://myapp-name.myorganization.com/employees/employeeid/123456
And
http://myapp-name.myorganization.com/employees/123456
Are both correct. But could be better (shorter).
Usually I prefer the second one and use the first one for the alternatives. Per example, if I would like to find an employee by id (the "default" method to find employees) or his unique internal company code, I prefer to use respectively:
/employees/123456 # by id
/employees/code/A899123A # by code
Similarly if i want go get information about employee with id 12345,
my uri is as below
http://myapp-name.myorganization.com/countries/country/US/employeeid/12345
This URL means to me that you trying to find an employee with id 12345 on the US country. But could be shorter too if the US term is the default method to find countries on your API:
/countries/US/employees/12345
as opposed to http://myapp-name.myorganization.com/countries/US/12345
This one seems confuse. Are you trying to find what with id 12345? It's hard to answer only looking for the URL. So, the /countries/US/employees/12345 is more consistent.
If the idea is find the employee on some country with some code, the URL can follow the same pattern: /countries/US/employees/code/A899123A
Does that my uri are not standard?
No, your URI are fine. REST doesn't care what spellings you use for your identifiers, so long as they are consistent with RFC 3986. There's also RFC 7320, which describes "Best Practices" -- but you will probably find that those best practices still leave you with a lot of freedom.
Think "variable names" - various communities will have their own conventions for how variable names should be spelled, but there isn't any standard.
The same holds for identifiers in REST -- they are opaque strings that neither the API consumer nor the client actually need to parse. (Example: when's the last time you actually looked at the URI used when you submit a search to Google?)
Some routing frameworks will be easier to use if you adhere to a particular convention, but that's purely an implementation detail on the server, the client doesn't care.
my REST API format:
http://example.com/api/v1.0/products - get all products
http://example.com/api/v1.0/products/3 - get product with id=3
Also, the products can be orginized into a product groups.
What is a proper way to get all product groups according to REST best practices:
http://example.com/api/v1.0/products/groups
or
http://example.com/api/v1.0/productgroups
...
another option ?
I can't agree with Rishabh Soni because http://example.com/api/v1.0/products/groups may lead to ambiguity.
I would put my money on http://example.com/api/v1.0/productgroups or even better http://example.com/api/v1.0/product_groups (better readability).
I've had similar discussion here: Updating RESTful resources against aggregate roots only
Question: About the thing of /products/features or /product-features,
is there any consensus on this? Do you know any good source to ensure
that it's not just a matter of taste?
Answer: I think this is misleading. I would expect to get all features
in all products rather than get all possible features. But, to be
honest, it’s hard to find any source talking directly about this
problem, but there is a bunch of articles where people don’t try to
create nested resources like /products/features, but do this
separately.
So, we can't be sure http://example.com/api/v1.0/products/groups will return all possible groups or just all groups that are connected with all existing products (what about a group that has not been connected with the product yet?).
To avoid this ambiguity, you can add some annotation in documentation. But you can just prepare http://example.com/api/v1.0/product_groups and all is clear.
If you are developing Rest API for your clients than you should not rely on id's. Instead build a meaningful abbreviation and map them to actual id on server side.
If that is not possible, instead of using
http://example.com/api/v1.0/products/3 you can use http://example.com/api/v1.0/products?product_id=3 and then you can provide "product_id" description in the documentation. basically telling the client ways to use product_id.
In short a url must be meaningful and follow a pattern.The variable part must be send by in the url query(part after ? or POST payload)
With this, method to querying the server is also important. If client is trying to get something to the server he should use "GET" http request, similar POST http request if it is uploading new info and "PUT" request if it is updating or creating a new resource.
So by this analogy http://example.com/api/v1.0/products/groups is more appropriate as it is following a pattern(groups in product) while productgroups is more like a keyword with no pattern.
A directory like pattern is more easier to understand. Like in file systems(C:\Program Files\WinRAR), every part gets us to more generalized target.
You can also customize this for specific group- http://example.com/api/v1.0/products/groups?id=3
So I'm building a REST api and need to make some urls. The problem is, I'm running into some conflicting paths. For example:
GET <type>/<id> gets the details of an object of a given type and id
GET <type>/summary gets the summary of objects of a given type
This simplified example shows a problem occurs when an object has id "summary". What is the best way to solve this? From a REST puritan perspective, what should be the solution?
Here's some of my ideas:
Put the <id> in query parameters. From what I understand this is against standards
Put a keyword at the start of the url. Also against standards?
Disallow certain id values. Not something I want to enforce for all my users and use cases and different entrances into my system
I may have an alternative to this. What if we have both book as wel as the plural books. Then you can have:
/book/{id}
and
/books/summary
or
/books/count
The URL structure is not quite right to begin with so it's difficult to solve it in a clean way.
For the sake of discussion, let's assume <type> is a books resource. So the first URL is fine - you get a book of the given ID:
GET /books/<id>
However this is not:
GET /books/summary
Because it's a bespoke URL, which I guess has a use in your application but is not restful. A GET call should return one or more resources. However a "summary" is not a resource, it's a property of a resource and that's why you end up in this situation of having IDs mixed up with book properties.
So your best option would be to change this URL to something like this:
GET /books?fields=summary
By default GET /books would return all the resources, while GET /books?fields=<list_of_fields> will return the books but with only the chosen properties.
That will be similar to your previous URL but without the ID/property conflict, and will also allow you later on to retrieve resources with specific fields (without having to create new custom URLs).
Edit:
Regarding the count of books, it's still useful to reason in terms of resources. /books gives you one or more books, but it should not be used for meta-information about the collection, such as count, but also things like "most read book", or "books that start with the letter 'A'", etc. as that will make the resource more and more complex and difficult to maintain.
Depending on what you want to achieve I think there'd be two solutions:
Create a new resource that manages the collection of books. For example:
GET /bookcase
And that will give you information about the collection, for example:
{
"count": 1234,
"most_read": "<isbn>",
// etc. - any information that might be needed about the book collection
}
Or a search engine. You create a resources such as:
GET /book_search_engine/?query=
which would return a search result such as:
{
"count": 123,
"books": [
// Books that match the query
]
}
then a query like this would give you just the count:
// Search all the books, but provide only the "count" field
GET /book_search/?query=*&fields=count
Obviously that's a more involved solution and maybe not necessary for a simple REST API, however it can be useful as it makes it easier to create queries specific to a client.
This simplified example shows a problem occurs when an object has id "summary". What is the best way to solve this? From a REST puritan perspective, what should be the solution?
As far as REST is concerned, the URI are opaque. Spelling is absolutely irrelevant. You could use URI like
/a575cc90-2878-41fe-9eec-f420a509e1f0
/f871fff6-4c4e-48f7-83a4-26858fdb3096
and as far as REST is concerned, that's spot on. See Stefan Tilkov's talk REST: I Don't Think It Means What You Think It Does.
What you are asking about is URI design, how to adapt conventions/best practices to your particular setting.
One thing that will help is to recognize is that summary is a resource, in the REST/HTTP sense -- it is a document that can be represented as a byte sequence. All you need to do is figure out where that resource belongs (according to your local spelling conventions).
Continuing to borrow the "books" example used by others
# Here's the familiar "URI that identifies a member of the books collection"
/books/<id>
# Here's the summary of the /books collection
/summaries/books
Put the in query parameters. From what I understand this is against standards
Not as much as you might think. REST doesn't care. The URI spec expresses some views about hierarchical vs non hierarchical data. HTTP supports the notion of a redirect, where one resource can reference another.
GET /books?id=12345
302 Found
Location: /books/12345
You also have options for skipping a round trip, by returning the representation you want immediately, taking advantage of Content-Location
GET /books?summary
200 OK
Content-Location: /summaries/books
...
I have the same issue. And all the solutions seem a little off b/c REST best practices seem to suggest none of them are ideal.
You could have just one off-limit id, like all.
GET <type>/<id>
GET <type>/all/summary
It might even be possible to use a single symbol instead, such as ~ or _.
GET <type>/<id>
GET <type>/~/summary
How satisfying this solution seems is of course very subjective.
The singular/plural approach seems more elegant to me but despite most REST best practice guides saying not to do this. Unfortunately some words don't have distinct singular and plural forms.
This isn't perfectly conventional for how some like to define their rest endpoints.
But I would would enforce a pattern where "id" cannot be any string. Instead I would use a uuid and define my routes as such.
GET /books/{id:uuid}
GET /books/{id:uuid}/summary
And if you really want a verb in the URL without an identifier it is still technically possible because we know the {id:uuid} in the path must conform to the uuid pattern.
With that GET /books/summary is still distinct from GET /books/{id:uuid}
Which of the following URLs is more RESTful compliant when it comes to fetch only items that have a certain value for attribute?
GET: /items/attribute/{value}
GET: /items/findByAttribute?attribute={value}
GET: /items?attribute={value}
Having in mind that GET: /items returns all items.
Example
GET: /shirts/color/FF9900
GET: /shirts/findByColor?color=FF9900
GET: /shirts?color=FF9900
I think that the last option is the correct one ;-)
Here are some comments for the others:
Generally the path element right after the one that corresponds to the list resource is the identifier of the element. So if you use something at this level, it could be considered as an identifier...
You can have resource to manage a particular field but the URL would be something like /items/{itemid}/fieldname.
You shouldn't use "action names" within the URL (in your example findByAttribute). The HTTP method should correspond to the "action" itself. See this answer if you want to support several actions for an HTTP method: How to Update a REST Resource Collection.
There is a question about how to design search filter: How to desing RESTful advanced search/filter. I think that your use case if a bit simple and using query parameters matches for you.
Otherwise I wrote a post about the way to design a Web API. This could be useful for you. See this link: https://templth.wordpress.com/2014/12/15/designing-a-web-api/.
Hope it helps you,
Thierry
Most certainly this one
GET: /items?attribute={value}
Why?
GET: /items/attribute/{value} is wrong because with REST, url segments represent resources, attribute is not a resource
GET: /items/findByAttribute?attribute={value} is wrong for the same reason really. findByAttribute is not a resource
Using url queries to filter by attributes is perfectly fine, so go with that.
URI semantics are irrelevant to REST. It doesn't make sense to ask which URI is more RESTful. What makes an URI RESTful or not is how the client obtains it. If he's reading URI patterns in documentation and filling placeholders with values, it's not RESTful. If this is news for you, I recommend reading this.
With that in mind, all three examples can be RESTful if the server provided that URI template to the client as a link to query the collection resource filtering by that value, but 3 is definitely the best option since it follows a more conventional query syntax. I wouldn't use 2 since it implies a method call and it looks too RPC for my taste, and I wouldn't use 1 since it implies for a human that it will return only the attribute as a resource.
I have been pondering the correct method of defining resource collections which have interdependence.
For instance, lets consider "documents" and "comments" which are independently accessible via the URI's:
/documents/{doc-uri}
/comments/{comment-id}
However, we typically want the collection of comments related to a specific document. Which creates a design question around how this should be archetected.
I can see a few main options:
1.) Supply an collection uri after the document uri for comments
GET /documents/{doc-uri}/comments/
2.) Provide a parameter to the comments collection to select by document
GET /comments/{comment-id}?related-doc={doc-uri}
3.) Use content negotiation to request the related comments be returned via the Accept header.
// Get all the comments for a document
GET /documents/{doc-uri} Accept: application/vnd.comments+xml
// Create a new comment
POST /documents/{doc-uri} Content-Type: application/vnd.comment+xml <comment>...</comment>
Method 1 has the advantage of automatically putting the comments in context of the document. Which is also nice when creating,updating and deleting comments using POST/PUT. However it does not provide global access to comments outside the context of a document. So if we wanted to do a search over all comments in the system we would need method #2.
Method 2 offers many of the same benefits as #1, however creating a comment without the context of a document makes no sense. Since comments must explicitly be related to a document.
Method 3 is interesting from a GET and POST/create perspective, but gets kinda hairy with update and delete.
I can see pro's and con's to all these methods so I am looking for some more guidance from someone who may have approached and solved this issue before.
I am considering doing both methods 1 & 2, thus I can provide all the functionality needed, but I am concerned I may be over-complicating/duplicating functionality.
REST API must be hypermedia-driven. See Hypermedia as the Engine of Application State (HATEOAS) constraint. So, don't waste your time on URLPatterns, because they are not RESTful. URLPattern implicates tight-coupling between a client and a server; simply, the client must be aware of how URLs look like and has an ability to construct them.
Consider this REST design for your use-case:
The representation of a document contains a link where the client can POST comments or with using of GET get all comments on the document. e.g.
{
...
"comments" : {
"href": ".. url ..",
"rel": ["create-new-comment", "list-comments"]
}
}
A client just takes this URL and performs GET or POST method on the URL; without a knowledge how the URL is, looks like.
See also this post:
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
The combination of methods 1 and 2 looks good, as you say in method 2, don't have too much sense create comments without a document context since a parent child relationship exists between both, if you delete a document is acceptable to delete all his comments also, you can make your/comments/ uri a read-only resource in order to avoid his creation without a document.
As filip26 says rest apis should be hypermedia driven but that not means that the url patterns aren't important, you could have a resource with one uri or many, if your resources have multiple uris is easier for clients to find them, the downside is that could be confusing because some clients use one uri instead of another, so you can use a canonical uri for a resource, when a client access a resource throught this canonical uri you can send back a 200 OK, when a client request one of the others uri you can send back a 303 "See also" along with the canonical uri.`