I have a webserver with some configuration properties and I want to be able to change them using a REST API.
Example
{
"maxUsers" : 10,
"refreshPeriodInMin" : 5
}
I would like to represent this with a "configuration" object. According to REST principle I believe the best way to do it is :
GET/PUT/POST/DELETE /configurations/{id}
But in my case I have only one configuration object and I do not like the idea of have to query
GET /configurations
just for one object.
Because there is only one object the easiest solution I found is to use id=default
Would give something like
GET /configurations/default
Is there a better way to represent a "unique" resource ? As mentionned by djmorton in the comments would /configuration be correct in a REST world ?
Another solution I though about would be to have one object per property. This would give
GET /properties/maxUsers
Problem with that solution is that you need to know the name of property to be able to query it. PLus you will make several queries if you have multiple changes to make.
Keep the resource singular if it truly represents a singular thing. If you will only have one, there is no reason not to simply PUT to that resource when you want to create or update it, and GET from that resource when you want to retrieve it.
If it can not be deleted, return a 405 METHOD NOT ALLOWED on DELETE requests. If it can be deleted, a DELETE request to that resource is acceptable, after which GET requests can return a 404 NOT FOUND.
In many ways, adding an id element to the path like /configuration/default would probably confuse users because they might expect that they would be able to POST new configurations to /configuration in addition to the default one.
The key is to do something that is sensible and intuitive to consumers of the API.
Related
I'm rewriting an API to be more RESTful, but I'm struggling with a design issue. I'll explain the situation first and then my question.
SITUATION:
I have two sets resources users and items. Each user has a list of item, so the resource path would like something like this:
api/v1/users/{userId}/items
Also each user has an isPrimary property, but only one user can be primary at a time. This means that if I want to get the primary user you'd do something like this:
api/v1/users?isPrimary=true
This should return a single "primary" user.
I have client of my API that wants to get the items of the primary user, but can't make two API calls (one to get the primary user and the second to get the items of the user, using the userId). Instead the client would like to make a single API call.
QUESTION:
How should I got about designing an API that fetches the items of a single user in only one API call when all the client has is the isPrimary query parameter for the user?
MY THOUGHTS:
I think I have a some options:
Option 1) api/v1/users?isPrimary=true will return the list of items along with the user data.
I don't like this one, because I have other API clients that call api/v1/users or api/v1/users?isPrimary=true to only get and parse through user data NOT item data. A user can have thousands of items, so returning those items every time would be taxing on both the client and the service.
Option 2) api/v1/users/items?isPrimary=true
I also don't like this because it's ugly and not really RESTful since there is not {userId} in the path and isPrimary isn't a property of items.
Option 3) api/v1/users?isPrimary=true&isShowingItems=true
This is like the first one, but I use another query parameter to flag whether or not to show the items belonging to the user in the response. The problem is that the query parameter is misleading because there is no isShowingItems property associated with a user.
Any help that you all could provide will be greatly appreciated. Thanks in advance.
There's no real standard solution for this, and all of your solutions are in my mind valid. So my answer will be a bit subjective.
Have you looked at HAL for your API format? HAL has a standard way to embed data from one resources into another (using _embedded) and it sounds like a pretty valid use-case for this.
The server can decide whether to embed the items based on a number of criteria, but one cheap solution might be to just add a query parameter like ?embed=items
Even if you don't use HAL, conceptually you could still copy this behavior similarly. Or maybe you only use _embedded. At least it's re-using an existing idea over building something new.
Aside from that practical solution, there is nothing in un-RESTful about exposing data at multiple endpoints. So if you created a resource like:
/v1/primary-user-with-items
Then this might be ugly and inconsistent with the rest of your API, but not inherently
'not RESTful' (sorry for the double negative).
You could include a List<User.Fieldset> parameter called fieldsets, and then include things if they are specified in fieldsets. This has the benefit that you can reuse the pattern by adding fieldsets onto any object in your API that has fields you might wish to include.
api/v1/users?isPrimary=true&fieldsets=items
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}
As from the specification of the project I am working, it is required to expose an API that allows to change the status of a user entity to be one of [ VALID | NOT_VALID | TO_VALIDATE ].
Current API for users have this path
/user/:user_id
my idea was to add a new sub-path for POST with url:
/user/:user_id/status
Since I want to update just a single value which design choice you would find to be the best?
Using the request's body (JSON)
Using the query string e.g. /user/:user_id/status?value=VALID
Creating three endpoints, one for each possible status' value:
/user/:user_id/status/valid
/user/:user_id/status/not_valid
/user/:user_id/status/to_validate
Thanks.
If status is something that is not query-able, then you could even have it as part of the user entity itself like /user/:user_id and do a PATCH (with the JSON payload) to update the status. Generally, people prefer nested paths if the sub-path can be queried as sub-resource on its own or updated independently. So if someone needs the status of a user, would he not expect that to come in the GET result of /user/:user_id? Or is he required to make another GET call to /user/:user_id/status? I think the /status path might not be a great idea.
Also, if you add something like status now, what will happen if you need to update name, address etc. in the future. We don't want to keep adding new sub-paths for every field right? Also having an enum-like sub-path in the URL path (valid/not_valid etc.) doesn't seem to be the right thing to do. If you include it in the JSON payload, it would come under the schema and you could version it nicely in case you make new additions to the enum. Having it as part of the URL means the clients now have to know about the new path as well.
On the other hand, you should also think about usability of the API. One rule of thumb I generally follow in designing REST APIs: I want my clients to integrate with my API in 2 minutes or so and I have to minimise the number of things he needs to know in order to successfully integrate. All standards and norms might come secondary to usability.
While designing a RESTful API we came across the problem of how to access different versions of the "same object". Let us say a page object is identified by a unique key and accessed by GET /api/page/pagekey. It can be updated by sending PUT /api/page/pagekey and an appropriate document in the body.
Now our system keeps track of old versions of the page, that we also want to access via the API. Let us assume that an older version of the document is version 1. There seem to be at least two ways to design the API to access this particular version of the page:
GET /api/page/pagekey/1
GET /api/page/pagekey?version=1
The first variant renders the particular version as its own resource; the second variant gives the existing resource an optional version context.
Is variant (1) or (2) a better solution? Or is there an even better way to do it?
In variant (1) a request for a version number that does not exist e.g. /api/page/pagekey/7 could trigger a HTTP 404 Not Found, which is quit handy. Would this also be a valid status response when considering variant (2), where we only change the context "version" of the existing resource, that would without the version parameter return a HTTP 200 Ok response?
Each resource url should be a permalink to identify that resource.
GET /api/page/{id}/{rev}
That certainly is a permalink to a specific version of the resource. So, that's fine. But note that the permalink does not require the content to be the same over time:
GET /api/page/{id}
That will return the latest revision which is fine and will change contents over time. To expand on that, you can even have temporal resources like this and be RESTful:
GET /api/page/latest
But, /api/page/{id}?version={rev} will also work and doesn't break any RESTful concepts.
I think the /{id}/{rev} is a bit purer since it specifically identifies that resource in the addressable url and feels a little more correct than putting making it a param. The reason is the params should be modifiers on how to retrieve the contents and not necessarily mutate the distinct resource you're retrieving. In your case, since each version is distinct, it seems more appropriate to distinctly address the resource. But, even that one doesn't break any RESTful url rules or concepts and if you asked 10 folks you might get a different answer :)
Either way, you should likely ensure the temporal resource /api/page/{id} returns the latest revision.
Almost by definition, REST will have no notion of "same object". If you need this in your protocol, then you'll need to have some kind of "identifier". As simple as that ;)
A URL parameter is one obvious way to go. "/1" or "?version=1" are certainly two good alternatives - which you choose is just a matter of preference (as well as a question of how much "other stuff" you might also want).
Either way, you're still going to have to cope with "version not found" kinds of errors, and recover gracefully.
IMHO...
Simple question I'm having trouble finding an answer to..
If I have a REST web service, and my design is not using url parameters, how can I specify two different keys to return the same resource by?
Example
I want (and have already implemented)
/Person/{ID}
which returns a person as expected.
Now I also want
/Person/{Name}
which returns a person by name.
Is this the correct RESTful format? Or is it something like:
/Person/Name/{Name}
You should only use one URI to refer to a single resource. Having multiple URIs will only cause confusion. In your example, confusion would arise due to two people having the same name. Which person resource are they referring to then?
That said, you can have multiple URIs refer to a single resource, but for anything other than the "true" URI you should simply redirect the client to the right place using a status code of 301 - Moved Permanently.
Personally, I would never implement a multi-ID scheme or redirection to support it. Pick a single identification scheme and stick with it. The users of your API will thank you.
What you really need to build is a query API, so focus on how you would implement something like a /personFinder resource which could take a name as a parameter and return potentially multiple matching /person/{ID} URIs in the response.
I guess technically you could have both URI's point to the same resource (perhaps with one of them as the canonical resource) but I think you wouldn't want to do this from an implementation perspective. What if there is an overlap between IDs and names?
It sure does seem like a good place to use query parameters, but if you insist on not doing so, perhaps you could do
person/{ID}
and
personByName/{Name}
I generally agree with this answer that for clarity and consistency it'd be best to avoid multiple ids pointing to the same entity.
Sometimes however, such a situation arises naturally. An example I work with is Polish companies, which can be identified by their tax id ('NIP' number) or by their national business registry id ('KRS' number).
In such case, I think one should first add the secondary id as a criterion to the search endpoint. Thus users will be able to "translate" between secondary id and primary id.
However, if users still keep insisting on being able to retrieve an entity directly by the secondary id (as we experienced), one other possibility is to provide a "secret" URL, not described in the documentation, performing such an operation. This can be given to users who made the effort to ask for it, and the potential ambiguity and confusion is then on them, if they decide to use it, not on everyone reading the documentation.
In terms of ambiguity and confusion for the API maintainer, I think this can be kept reasonably minimal with a helper function to immediately detect and translate the secondary id to primary id at the beginning of each relevant API endpoint.
It obviously matters much less than normal what scheme is chosen for the secret URL.