I am supposed to make web services for an app and thought I could do a nice job practicing the good practice. As I found out it's using REST. But there is one thing that makes very little sense in it.
Why use URI to pass any variable?
What we did in our last project is use POST only and pass whatever as raw POST data (which was JSON). That's not very RESTful. But it has some advantages. It was quite simple on the client side - I had a general function that takes URI and data as arguments and then it wraps it up and sends it.
Now, if I used proper REST, I would have to pass some data as part of the URI (user ID, for instance). All the other data (username, email and etc.) would have to go as raw data, like we did, I guess. That means I would have to separate user ID and the other data at some point. That's not so bad but still - why?
EDIT
Here is a more detailed example:
Let's say you want to access (GET) and update (POST) user data. You may have a service accessible under /user but what RESTful service would do is accept user's ID as part of the URI (/user/1234). All the other data (name, email and etc) would go to request content (probably as JSON).
What I pose is that it seems useless to make put user id in the URI. If you wanted to update user data - you would send additional data as content anyway. If you wanted to access it - you could use same generic method to request web service.
I know GET gets cached by a browser but I believe you have to cache it manually anyway if you use AJAX (web) or any HTTP client library (other platforms).
From point of scalability - you can always add more services.
You use the URI to identify the resource (user/document/webpage) you want to work with, and pass the related data inside the request.
It has the advantage that web infrastructure components can find out the location of the resource without having any idea how your content is represented. For example, you can use standard caches and load balancers, all they need to know is the URL and headers (which are always represented the same way) Whether you use JSON, protobuf or WAV audio to communicate with your resource is irrelevant.
This will for example let you keep different resources in totally different places, if you send it all as content you won't have the advantage of being able to place the resources in totally different locations, as for example http://cloud.google.com/resource1 and http://cloud.amazon.com/resource2.
All this will allow you to scale massively, which you won't be able to do if you put it all on http://my.url.com/rest and pass all resource info as content.
Re: Your edit
Passing the user id in the URL is the only way to identify the individual resource (user). Remember, it's the user that's the resource, not the "user store".
For example, a cache that caches http://my.url/user won't be much good, since it would return the same cached page for every user. If the cache can work with http://my.url/user/4711, it can cache every user separately. In the same way, a load balancer could know that users 1-5000 are handled by one machine, 5001-10000 by another etc. and make intelligent decisions based on the URL only.
Imagine a RESTful web service as a database.
To get or modify specific object you need to identify it by providing its primary key.
You identify a user by his ID, not his Name+Nickname+e-mail+mother's maiden name.
The information that identifies an object or selects a set of objects goes to the URL. The information that modifies objects should be POSTed to the corresponding URL.
Related
I'm trying to figure out best or common practices for API design.
My concern is basically this:
PUT /users/:id
In my view this endpoint could by used for a wide array of functions.
I would use it to change the user name or profile, but what about ex, resetting a password?
From a "model" point of view, that could be flag, a property of the user, so it would "work" to send a modification.
But I would expect more something like
POST /users/:id/reset_password
But that means that almost for each modification I could create a different endpoint according to the meaning of the modification, i.e
POST /users/:id/enable
POST /users/:id/birthday
...
or even
GET /user/:id/birthday
compared to simply
GET /users/:id
So basically I don't understand when to stop using a single POST/GET and creating instead different endpoints.
It looks to me as a simple matter of choice, I just want to know if there is some standard way of doing this or some guideline. After reading and looking at example I'm still not really sure.
Disclaimer: In a lot of cases, people ask about REST when what they really want is an HTTP compliant RPC design with pretty URLs. In what follows, I'm answering about REST.
In my view this endpoint could by used for a wide array of functions. I would use it to change the user name or profile, but what about ex, resetting a password?
Sure, why not?
I don't understand when to stop using a single POST/GET and creating instead different endpoints.
A really good starting point is Jim Webber's talk Domain Driven Design for RESTful systems.
First key idea - your resources are not your domain model entities. Your REST API is really a facade in front of your domain model, which supports the illusion that you are just a website.
So your resources are analogous to documents that represent information. The URI identifies the document.
Second key idea - that URI is used by clients to cache representations of the resource, so that we don't need to send requests back to the server all the time. Instead, we have built into HTTP a bunch of standard ways for communicating caching meta data from the server to the client.
Critical to that is the rule for cache invalidation: a successful unsafe request invalidates previously cached representations of the same resource (ie, the same URI).
So the general rule is, if the client is going to do something that will modify a resource they have already cached, then we want the modification request to go to that same URI.
Your REST API is a facade to make your domain model look like a web site. So if we think about how we might build a web site to do the same thing, it can give us insights to how we arrange our resources.
So to borrow your example, we might have a web page representation of the user. If we were going to allow the client to modify that page, then we might think through a bunch of use cases (enable, change birthday, change name, reset password). For each of these supported cases, we would have a link to a task-specific form. Each of those forms would have fields allowing the client to describe the change, and a url in the form action to decide where the form gets submitted.
Since what the client is trying to achieve is to modify the profile page itself, we would have each of those forms submit back to the profile page URI, so that the client would know to invalidate the previously cached representations if the request were successful.
So your resource identifiers might look like:
/users/:id
/users/:id/forms/enable
/users/:id/forms/changeName
/users/:id/forms/changeBirthday
/users/:id/forms/resetPassword
Where each of the forms submits its information to /users/:id.
That does mean, in your implementation, you are probably going to end up with a lot of different requests routed to the same handler, and so you may need to disambiguate them there.
I am creating a RESTful API where “entries” can be added, modified, and deleted. Each entry is automatically assigned an expiration date when it’s created and is automatically deleted unless renewed before that date. When an entry is renewed, it is simply given a later expiration date (by the server, the user cannot choose the expiration date).
My question is, what would be the RESTful way to expose the “renew” functionality?
A few possibilities that I thought of (though none of them really seem right):
DELETE /api/entries/:id/expiration-date
PATCH /api/entries/:id with "expirationDate": null in the (JSON) body
PATCH /api/entries/:id with any or no body
PUT /api/entries/:id (Essentially require the entry to be resubmitted)
Note: Currently the only intended consumers of the API will be my own client applications, but I may choose to make it public in the future.
I would use
PUT /api/entries/id/renew
with the expiration date in the body (or with no expiry to use the default). Reason being that the expiry isn't really pertaining to the object itself; it's metadata associated with how the object is managed by your system.
My question is, what would be the RESTful way to expose the “renew” functionality?
How would you do provide this functionality on a website?
You would presumably start by looking at the web page of the entry, via a GET request, that would load the current representation of the page into your local cache.ou
When the server judged that the entry was eligible for renewal, the web page would include some sort of hypermedia affordance for allowing the client to trigger the renew protocol. In this case, you probably don't want that affordance to have safe semantics, so it would be a form using the POST method. When the user submitted the form, the browser would create an HTTP request with the correct meta data and form data copied into the request body as described by the HTML processing rules; the request would be submitted to the URL specified in the form.action by the server.
Does the spelling of the URL matter to the user? Not really, the user just submits the form, the URL is just opaque data. Indirectly, it matters because of the way that cache invalidation semantics are defined -- if we intend that renewing should evict previously cached representations of the web page, then the post request should have the URL of the page itself.
Similarly, the web form doesn't need to be on the page - you could have a link to a form managed elsewhere, using different caching rules.
Do that, in a machine readable way, and you have yourself a REST API.
PUT and PATCH work the same basic way, except that request body is a description of the page itself. Download the HTML, make edits, then either PUT the new document in its entirety or compute a patch document and send that instead.
PUT and PATCH work really well for anemic domains - like document stores; it's more challenging to work with representations directly when you need to reverse engineer the change in order to work out the intent.
Background:
I have a single page application that pulls data from a REST API. The API is designed such that the only URL necessary is the API root, ie https://example.com/api which provides URLs for other resources so that the client doesn't need to have any knowledge of how they are constructed.
API Design
The API has three main classes of data:
Module: Top level container
Category: A sub-container in a specific module
Resource: An item in a category
SPA Design
The app consuming the API has views for listing modules, viewing a particular module's details, and viewing a particular resource. The way the app works is it keeps all loaded data in a store. This store is persistent until the page is closed/refreshed.
The Problem:
My question is, if the user has navigated to a resource's detail view (example.com/resources/1/) and then they refresh the page, how do I load that particular resource without knowing its URL for the API?
Potential Solutions:
Hardcode URLs
Hardcoding the URLs would be fairly straightforward since I control both the API and the client, but I would really prefer to stick to a self describing API where the client doesn't need to know about the URLs.
Recursive Fetch
I could fetch the data recursively. For example, if the user requests a Resource with a particular ID, I could perform the following steps.
Fetch all the modules.
For each module, fetch its categories
Find the category that contains the requested resource and fetch the requested resource's details.
My concern with this is that I would be making a lot of unnecessary requests. If we have 100 modules but the user is only ever going to view 1 of them, we still make 100 requests to get the categories in each module.
Descriptive URLs
If I nested URLs like example.com/modules/123/categories/456/resources/789/, then I could do 3 simple lookups since I could avoid searching through the received data. The issue with this approach is that the URLs quickly become unwieldy, especially if I also wanted to include a slug for each resource. However, since this approach allows me to avoid hardcoding URLs and avoid making unnecessary network requests, it is currently my preferred option.
Notes:
I control both the client application and the API, so I can make changes in either place.
I am open to redesigning the API if necessary
Any ideas for how to address this issue would by greatly appreciated.
Expanding on my comment in an answer.
I think this is a very common problem and one I've struggled with myself. I don't think Nicholas Shanks's answer truly solves this.
This section in particular I take some issues with:
The user reloading example.com/resources/1/ is simply re-affirming the current application state, and the client does not need to do any API traversal to get back here.
Your client application should know the current URL, but that URL is saved on the client machine (in RAM, or disk cache, or a history file, etc.)
The implication I take from this, is that urls on your application are only valid for the life-time of the history file or disk cache, and cannot be shared with other users.
If that is good enough for your use-case, then this is probably the simplest, but I feel that there's a lot of cases where this is not true. The most obvious one indeed being the ability to share urls from the frontend-application.
To solve this, I would sum the issue up as:
You need to be able to statelessly map a url from a frontend to an API
The simplest, but incorrect way might simply be to map a API url such as:
http://api.example.org/resources/1
Directly to url such as:
http://frontend.example.org/resources/1
The issue I have with this, is that there's an implication that /resource/1 is taken from the frontend url and just added on to the api url. This is not something we're supposed to do, because it means we can't really evolve this api. If the server decides to link to a different server for example, the urls break.
Another option is that you generate uris such as:
http://frontend.example.org/http://api.example.org/resources/1
http://frontend.example.org/?uri=http://api.example.org/resources/1
I personally don't think this is too crazy. It does mean that the frontend needs to be able to load that uri and figure out what 'view' to load for the backend uri.
A third possibility is that you add another api that can:
Generate short strings that the frontend can use as unique ids (http://frontend.example.org/[short-string])
This api would return some document to the frontend that informs what view to load and what the (last known) API uri was.
None of these ideas sound super great to me. I want a better solution to this problem, but these are things I came up with as I was contemplating this.
Super curious if there's better ideas out there!
The current URL that the user is viewing, and the steps it took to get to the current place, are both application state (in the HATEOAS sense).
The user reloading example.com/resources/1/ is simply re-affirming the current application state, and the client does not need to do any API traversal to get back here.
Your client application should know the current URL, but that URL is saved on the client machine (in RAM, or disk cache, or a history file, etc.)
The starting point of the API is (well, can be) compiled-in to your client. Commpiled-in URLs are what couple the client to the server, not URLs that the user has visited during use of the client, including the current URL.
Your question, "For example, if the user requests a Resource with a particular ID", indicates that you have not grasped the decoupling that HATEOAS provides.
The user NEVER asks for a resource with such-and-such an ID. The user can click a link to get a query form, and then the server provides a form that generates requests to /collection/{id}. (In HTML, this is only possible for query strings, not path components, but other hypermedia formats don't have this limitation).
When the user submits the form with the ID number in the field, the client can build the request URL from the data supplied by the server+user.
To access an instance of a User in a restful web-service the url is structured as shown in the curl request below:
curl -v -X GET -s "$BASE_URL/User/${customer_id}.json"
If I wanted to specify all User entities or page through a range of User entities, such as the first 50 Users in my database, how would I structure my request so that it is compliant with REST ???
You should start by trying to de-emphasize the meaning of the characters in a URI. While nice, pretty and readable URIs are a good thing, they have nothing to do with REST -- in fact it's a good exercise to judge the design of a RESTful interface by changing all the URIs to meaningless strings, and add the prettiness afterwards. A client should never have any knowledge of the server's URI structure, for the simple reason that the server won't be able to change it afterwards.
Next, if a list of customers is a meaningful concept to you, you should by all means turn it into a resource of its own right. In its representation, you might want to include some information about each individual customer, along with a link to each individual customer resource.
Paging? Good idea -- turn each page into its own resource, and link them together. Take a look at the way Google presents search results for a hint.
Often that's all you need because it's not necessary for the client to be able to specify the page size. But if it is, you essentially have two options: You can have a resource that encapsulates a form that allows you to specify the parameters that, when submitted, will directly or indirectly via a redirect take you to the appropriate URI. Or you can include a poor man's form, a URI template.
In any case, and to re-iterate my first point: Don't view a RESTful interface as an API that manifests itself as a set of URI construction rules. Instead, think of resources, representations, and hypermedia.
Is it appropriate to perform actions with REST, other than simple create (POST), read (GET), update (PUT), and delete (DELETE)? I'm kind of new to the whole RESTful theology, so bear with me, but how should I accomplish the following:
I have a web service that needs to talk to another web service. Web service A needs to "reserve" an object on Web service B. This object has a timeout of validity, but can be deleted immediately if need be. It's essentially a glorified permissions system which requires web services to reserve a space on web service B before taking any actions.
My initial thought was to 1. enable authentication of some sort, 2. in the serverside response to a GET call, reserve the space and return the result, and 3. provide immediate "unreservation" of the object via a DELETE call. Is this still being RESTful?
Yes, it's OK to perform actions with rest. What matters is that these actions should be guided by the representations you exchange.
If you think about the way the web works (via a browser), you do this all the time: you get an HTML form that lets you choose a number of actions you can perform. Then, you submit the form (typically via POST) and the action is performed.
It's good to be able to use DELETE via a programmatic client (which is something that non-AJAX requests in browsers wouldn't support), but the overall approach of a RESTful system should be very similar to what you find for websites (i.e. the focus should be on the representations: the equivalent of web pages in your system).
GET shouldn't have side effects, so don't use GET to make the reservation itself, use something like POST instead.
No - unlikely to be restful
From your description ...
2. in the serverside response to a GET call, reserve the space and return the result
GETs should be idempotent. For this reason alone, your service is unlikely to be restful because the state of the system after the first GET is different.
You really need to consider that a Reservation is a resource and should be created with a POST to a reservations container which will return the URI of the new resource in the Location header of the HTTP response. This UrI can be used by Get to return the resource and updated with a PUT
Post should be used to extend an existing resource and Put for replacing the state of a resource. In your case, consider the Post to be updating a list of Reservations and returning the URI of the new resource (not just the I'd). Put can be used for changing the state associated with the resource identified by the UR
You're on the right track, but your reservation of the object should be with a PUT; you're PUTting a reservation on the object, i.e. changing the underlying object.
PUT is the right verb here, since you know what resource you're modifying, and it should be idempotent for multiple requests.