REST API design for action that is not REST [closed] - rest

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I'm designing REST API for devices management system.
Endpoints:
http://api.example.com/users
http://api.example.com/devices
I want to achieve that there is an endpoint that will do some action on selected device. Something like that:
http://api.example.com/devices/1/send_signal
I know that is not REST compatible and I'm looking for suggestions to make it the right way.
I was thinking about adding another endpoint like:
http://api.example.com/calls
So when user send POST request with let's say deviceId parameter to that endpoint there will be new entry into the database (to have history of all calls and who called the function) and at the same time calls that function on specified device.
Would it be great architecture and REST compatible?

You are right about your hunch. It is not proper REST. Sometimes that is OK, but most often, it is a sign that something in your Domain needs redesigning.
Quite often, there is a domain model waiting to be discovered. Most often, things like "send_signal" are telling you that you've modeled your API too close to some library, backend service or database. An API, after all, is the interface you provide.
AS I've written before: The R in REST stands for resource (which isn't true.... etc).
Think in resources. Not in procedures or calls, or internal tools, backend services or architecture of your system. That is your stuff. The API-user should only be bothered with (clean) abstractions that make senses to the API-user.
Both /call and /.../send_signal bother too much about procedures and internals.
What do you want to do with a device? You want to turn it's camera on? That would be an update to the Camera model on the Device with ID 1337:
PUT /device/1337/camera { power: "on" }
You want a device to bzip up some log files and send them to a debug-server? You're creating a DebugSession model:
POST /device/1337/debug_session { delivery_bucket: 42, compress: "bzip" }
You want a device to send a message to some server? Create a Message on a Device:
POST /device/1337/messages { to: john, body: "Hello World" }
And so on.
That is REST. In REST you model your domain models carefully. Lots of REST servers are really poor because they are very thin wrappers around some relational databases, and suffer from far too much leaky abstractions. Lots of other REST servers are really poor because they are written far too close around backend services, jobs being ran, or other internal details.
If I want to start a new server, I want to say:
POST /server/ { region: eu-1, size: xl, disk: 1MB }
And not:
POST /resources/blockdisks/create { size: 10GB } => 1337 is created
GET /resources/blockdisks/1337?include_attrs=mountpoint,format
GET /servers/available/map_for/eu-1?xl => DB-Zfaa-dd-12
POST /servers/reserve { id: DB-Zfaa-dd-12, attach: { id: 1337, mountpoint: /dev/sdb2, format: zfs }
(I'm not making this up, I had to deal with such API's they are a PIAS to use, and quite certainly an even bigger PIAS to maintain)
The lesson here: the first exposes a domain model of a Server, with few attributes only interesting to the user of the API. The second is modeled far too close around all sorts of internal tooling, and systems.
Edit: and all this completely ignores the even more important REST-part: discovery. Links, headers, redirects, etc. But you were explicitly asking about naming resources, so that's what my answer is about. Once you have your resources, your domain models, architectured, go back to the whiteboard and do it all over: now including Links, headers, or other metadata so that your API-clients can discover what they can do and where they can do that.

http://api.example.com/devices/1/send_signal
I know that is not REST compatible and I'm looking for suggestions to make it the right way.
It is REST compatible. REST doesn't care what spellings you use for your resource identifiers.
Would it be great architecture and REST compatible?
If this is what you want, think about how you would achieve the same result with a website. The client would open a bookmark in a browser, maybe follow some links, fill in a form, and submit it. That would all work because the (generic) browser understands the processing rules for HTML, and how to manage cache meta data in HTTP, and so on. There's no point in the chain where the client needs to compose an identifier -- it either uses one provided by the server as is, or it calculates one using the generic processing rules for HTML forms.
OP clearly uses a verb, to communicate intent and procedures, which is not RESTful.
No; this is a common misunderstanding. There's nothing in the REST architectural style that says anything about human readable semantics in identifiers. URL shorteners work.
It's analogous to saying that a variable name in a program should never be a verb, because that doesn't correctly communicate intent -- the compiler/interpreter doesn't care.
The use of spelling conventions does not make a URI more or less RESTful. See Tilkov. It might even be preferable to avoid using predictable identifiers, as that ensures that consumers read the identifiers provided in the hypermedia representations, which is the point.

I think you are on the right track. Based on what you said about the system, I would probably start with this way of doing it and go from there.
POST http://api.example.com/devices/123/calls
This would send the details of the call to the API and it would intern save the call to a data store and send off an event to the appropriate subsystem or internal library to call out to the device.
Then you could have the following endpoints to get call details.
GET http://api.example.com/devices/123/calls/456
GET http://api.example.com/devices/123/calls -This would also include query parameters to limit the results in some way, probably by date.
If you want to get calls from all devices then you could to this with some query parameters restricting the result set, again maybe by date.
GET http://api.example.com/devices/calls
Just as a side note, if this is an internal API used only by your applications RPC style may be appropriate. But, by following HTTP/REST you will make your software more malleable so you can use it in more ways without making it specific to any one function.
This is a good article on REST vs RPC if you'd like to learn more. https://cloud.google.com/blog/products/application-development/rest-vs-rpc-what-problems-are-you-trying-to-solve-with-your-apis

Related

Using GET verb to update in rest api?

I know the use of http verbs is based on standard specification. But my question if I use "GET" for update operations and write a code logic to update, does it create issues in any scenario? Apart from the standard, what else could be the reason to use these verbs for a specific purpose only?
my question if I use "GET" for update operations and write a code logic to update, does it create issues in any scenario?
Yes.
A simple example - suppose the network between the client and the server is unreliable; specifically, for a time, HTTP responses are being lost. A general purpose component (like a web proxy) might time out, and then, noticing that the method token of the request is GET, resend the request a second/third/fourth time, with your server performing its update on every GET request.
Let us further assume that these multiple update operations lead to an undesirable outcome; where do we properly affix blame?
Second example: you send someone a copy of the link to the update operation, so that they can send you a request at the appropriate time. But suppose you send that link to them in an email, and the email client recognizes the uri and (as a performance optimization) pre-fetches the link, triggering your update operation too early. Where do we properly affix the blame?
HTTP does not attempt to require the results of a GET to be safe. What it does is require that the semantics of the operation be safe, and therefore it is a fault of the implementation, not the interface or the user of that interface, if anything happens as a result that causes loss of property -- Fielding, 2002
In these, and other examples, blame is correctly affixed to your server, because GET has a standardized meaning which include the constraint that the semantics of the request are safe.
That's not to say that you can't have side effects when handling a GET request; "hit counters" are almost as old as the web itself. You have a lot of freedom in your implementation; so long as you respect the uniform interface, there won't be too much trouble.
Experience report: one of our internal tools uses GET requests to trigger scheduling; in our carefully controlled context (which is not web scale), we get away with it, and have for a very long time.
To borrow your language, there are certainly scenarios that would give us problems; but given our controls we manage to avoid them.
I wouldn't like our chances, though, if requests started coming in from outside of our carefully controlled context.
I think it's a decent question. You're asking a hypothetical: is there any value to doing the right other than that's we agree to use GET for fetching? e.g.: is there value beyond the fact that it's 'semantically nice'. A similar question in HTML might be: "Is it ok to use a <div> with an onclick instead of a <button>? (the answer is no).
There certainly is. Clients, servers and intermediates all change their behavior depending on what method is used. Even if your server can process GET for updates, and you build a client that uses this, your browser might still get confused.
If you are interested in this subject, don't ask on a forum; read the spec. The HTTP specification tells you what clients, servers and proxies should do when they encounter certain methods, statuses and headers.
Start at RFC7231

Rest Services conventions

In Rest Services,we normally use 'GET' requests when we want to retrieve some data from the server, however we can also retrieve data using a 'POST' request.
We use 'POST' to create, 'PUT' to update, and 'DELETE' to delete, however we can even create new data using a 'DELETE' request.
So I was just wondering what is the real reason behind for that, why these conventions are used?
So I was just wondering what is the real reason behind for that, why these conventions are used?
So the world doesn't fall apart!
No but seriously, why are any protocols or standards created? Take this historical scenario. Back in the early days of Google, many developers (relative to nowadays) weren't too savvy on the HTTP protocol. What you might've caught was a bunch of sites who just made use of the well known (maybe only known) GET method. So there would be links that would be GET requests, but would perform operations that were meant to be POST request, that would change the state of the server (sometimes very important changes of state). Enter Google, who spends its days crawling the web. So now you have all these links that Google is crawling, all these links that are GET requests, but changing the state of the server. So all these companies are getting a bunch of hits on their servers changing state. They all think they're being attacked! But Google isn't doing anything wrong. HTTP semantics state that GET requests should not have state changing behaviors. It should be a "read only" method. So finally these companies smartened up, and started following HTTP semantics. True story.
The moral of the story: follow protocols, that's what they're there for - to follow.
You seem to be looking at it from the perspective of server implementation. Yeah you can implement your server to accept DELETE request to "get" something. That's not really the matter at hand. When implementing the server, you need to think about what the client expects. I mean ultimately, you are creating an API. Look at it from a code API perspective
public class Foo {
public Bar bar;
public Bar deleteBar() {
return bar; // Really?!
}
public void getBar() {
bar = null; // What the..??!
}
}
I don't know how long a developer would last in the game, writing code like that. Any callers expecting to "get" Bar (simply by naming semantics) has another thing coming. Same goes for your REST services. It is ultimately a WEB API, and should follow the semantics of the protocol (namely HTTP) on which it is built. Those who understand the protocol, will have an idea of what the API does (at least in the CRUD sense), simply based on the type of request they make.
My suggestion to you or anyone trying to learn REST, is to get a good handle on HTTP. I would keep the following document handy. Read it once, then keep it as a reference
Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
GET cached by proxies POST and DELETE not!
Yes you can create data with GET but now you have to destroy that cached.Why to do extra job.
Also maximum header sizes accepted are different because of purpose of usage.
I recommend reading the spec which clearly states how each each http-method should be used.
why these conventions are used?
They are conventions, that is, best practices that have been adopted as a standard. You do not have to adhere to the standard, but most consumers of a REST service assume you do. That way it is easier to understand the implementation / interface.

Convention for combining REST requests and replies?

For a complex web application, one page view might require data of many different types. If you are doing client-side templating and pulling in this data from a RESTful web service, you may have to make a lot of requests to populate the page. Is there any convention by which REST requests can be combined, to receive back a single payload containing all the responses needed?
To use the Stack Exchange User page as an example, you probably would need to call at least these from the Stack Exchange API to build the page:
/users/{id}
/users/{id}/answers
/users/{id}/reputation
/users/{id}/tags
/users/{id}/questions
...etc
Could the provider of such an API allow you a single request to get all that data? Especially if other root types were involved, say you had to also request /revisions/{id} and /tags to build the page also for some reason.
To be clear, I don't want to know if it's possible to provide such functionality in a web API -- I want to know if there is a standard or at least documented means of doing so.
I think we need some standard way of doing this, but until then, you're probably on your own.
In the past I've had similar challenges when I wanted to do transactions spread across multiple resources. I invented new resources which described the actions I was about to make more clearly (subtracting 5 from account A and adding 5 to account B becomes a transaction with from and to members).
Maybe a similar (but more general) approach could be applied here by using another REST call as container;
POST /batchRequests { requests: [
{ method: 'POST', url: '/resource', payload: { ... } }
], transactional: false }
Which in turn returned a "BatchRequest" object containing results. It's pretty close to what Facebook did as well.
I think that might be against REST principles, no? i.e. the unique URI per object representation and its payload. Wouldn't it make things worse? Given that it's not TI calculator but a modern computer capable of parallel HTTP requests verses a single one that'll take as long as the logest of them all.
Don't think there is a standard, but here's an example -- https://developers.facebook.com/docs/reference/api/batch/
I know I am very late, but maybe my thoughts could help others...
My solution is a bit different.
I store the resources in a single uri (unified resource identifier) per resource.
User
GET /user => INDEX
PUT /user => CREATE (RETURN LOCATION HEADER)
GET /user/{id} => FIND
POST /user/{id} => UPDATE
DELETE /user/{id} => REMOVE
Messages
GET /user/{id}/message => INDEX
PUT /user/{id}/message => CREATE (RETURN LOCATION HEADER)
GET /user/{id}/message => FIND
POST /user/{id}/message/{id} => UPDATE
DELETE /user/{id}/message/{id} => REMOVE
Friends
GET /user/{id}/friend => INDEX
PUT /user/{id}/friend => CREATE (RETURN LOCATION HEADER)
GET /user/{id}/friend => FIND
POST /user/{id}/friend/{id} => UPDATE
DELETE /user/{id}/friend/{id} => REMOVE
The resulting content-type can get changed through a HTTP-Header, the client needs to specify.
Accept: "application/vnd.com.example.api+json; version: 1.0;"
Currently it is the Accept HTTP-Header field, that tells the server which version and which content type to use.
To keep the browser or proxy cache functionality, i decided to return the Vary HTTP Header field on my api, with all content changing HTTP-Headers in it, so that browsers can correctly differ between resources, by uri and headers.
Vary: "Accept, Accept-Language"
The biggest problem is, how to combine resources to prevent the client from opening too much tcp connections at once.
As example: If you query the user list from my API via /user, the API will return an array of user objects in the desired content-type (JSON,XML,HTML).
I won't go into detail, as there is pagination and filter/search support available to.
Each of the user objects does has dependent resources, like friends and/or messages.
There is a very good structured standard called HAL (Hypertext Application Language) which provides some easy ways to combine a resource with its dependent resources or linked resources. It uses JSON to represent the data.
Have a look at http://stateless.co/hal_specification.html by Mike Kelly.
But that solution also doesn't combine resources in one call, it just sends the uri of the dependent or linked resource with the payload to the client.
This will let the client decide which additional informations to show.
And of course, all the caching functionality, which is very important, is working.
Most of the traffic, when browsing through resources, will be duplicated requests that can be cached very easy.
If u example given want to show the number of friends or number of messages of a user in the user list, think about adding the dependent resource as a key to your result.
Example User Response (JSON)
{
id: 1,
email: test#test.com,
...
friends: {
count: 1,
_links: [{
'id': '2',
'name': 'Peter Parker',
'uri': '//api.example.com/user/2'
}]
},
messages: {
count: 1,
_links: [{
'id': 'x4gZ6',
'subject': 'Testmessage',
'uri': '//api.example.com/user/1/message/x4gZ6'
}]
},
...
}
Now let's speak about how to prevent the use of multiple TCP Connections!
There is a very simple and good approach for that...
Why not use:
Connection: "keep-alive"
This will give a client the possibility to query as many resources at once as needed.
While all resources are queried via a single TCP connection to the server.
I know there are other concerns with keep-alive connections, so feel free to discuss with me about all the ideas.
Thanks!
I'm very late to this party, but I've been looking for some lit online on the topic of balancing clean REST design vs the realities of an actual web site. I've found the usual "reduce http requests for performance" but no good essays on good practices with an eye toward tradeoffs. (Commenters feel free to point me in a direction!) And what the hell, no marked answers yet.
Not sure whether you're asking whether it's possible for other people to make your life easier by doing this, or whether you're asking because you are designing an API. Your question says other people so here we go.
Could the provider of such an API allow you a single request to get all that data? Especially if other root types were involved, say you had to also request /revisions/{id} and /tags to build the page also for some reason.
To be clear, I don't want to know if it's possible to provide such functionality in a web API -- I want to know if there is a standard or at least documented means of doing so.
The short version: I haven't seen a lot of good essays on the subject. REST's popularity may be young yet for a good academic consensus-style set of answers. Where I can get away with it, I do what I have to do and I worry less about how pure my design is re: an acronym like REST. But I'd probably err towards a purer standard (again, e.g. REST) implementation if I were the provider for a big, public API (see below).
It's possible, and I've sullied many a pure REST design in my own applications to achieve what I needed in terms of performance. Mainly RPCs or combining resource gets/updates, to minimize the number of HTTP requests, into something a modern Frankenstein web developer might produce.
Could the provider of such an API allow you a single request to get all that data?
Technically s/he certainly could do that. But if I were the publisher of a popular, public-facing API I'd probably use a more "pure" REST approach because simplicity, usability, and maintenance now take on a whole new significance if a lot of strangers will be using it. Performance, for me and for consumers, may be lower priority in this case than it would for an enterprise app for which I'm both consumer and provider.
As usual, the developer must decide the appropriate balance between speed of implementation, clean design, maintainability, performance, and a zillion other things. (That decision already started with choice of language -- Python/Ruby vs Java/C# vs C++ vs...)

Writing a client for a RESTful (hypermedia) API

I've been reading up on 'real' RESTful APIs for a few days now, and I think I'm near to groking what it's about.
But one of the things that I stumble on is that I can't even begin to imagine how one would write a client for a 'real' hypermedia API:
Most of the examples I've read talk about browsers and spiders, but that's not especially helpful: one is human-directed and 'intelligent', the other is dumb and 'random'. As it stands, I kind of get the impression that you'd need to learn AI to get a client working.
One thing that isn't clear to me is how the client knows which verb to use on any given link? Is that implicit in the 'rel' type of the uri? The alternative (reading here) seems to be using xhtml and having a client which can parse and post forms.
How likely is it that a link will change, but not the route to the link?
In most examples you see around, the route and the link are the same:
eg. if I want to set up a client which will bring me back the list of cakes from Toni's Cake Shop:
http://tonis.com
{ link: { type : "cakes" ; uri : "http://tonis.com/cakes" } }
What happens when Toni's becomes Toni's Food Shop, and the link becomes http://tonis.com/desserts/cakes?
Do we keep the initial cakes link at the root, for reverse-compatibility? And if not, how do we do a 'redirect' for the poor little agent who has been told "go to root, look for cakes"?
What am I missing?
Ok, I'm not a REST expert either, I've been reading much related stuff lately, so what I'm going to write is not my experience or opinion but rather a summary of what I read, especially, the REST In Practice book.
First of all, you can't escape from having some initial agreement between client and server, the goal of REST is to make them agree on the very minimum of things which are relevant to both of them and let each party care about their own stuff themselves. E.g., client should not care about links layout or how the data is stored on server, and server should not care about a client's state. What they agree on in advance (i.e. before the interaction begins) is what aforementioned book's authors call "Domain Application Protocol" (DAP).
The important thing about DAP is that it's stateful, even though HTTP itself is not (since any client-service interaction has state, at least, begin and end). This state can be described in terms of "What a client can/may/is expected to do next": "I've started using the service, what now? Ok, I can search items. Search this item, what's next? Ok, I can order this and that... etc"
The definition of Hypermedia content-type is being able to handle both data exchange and interaction state. As I already mentioned, state is described in terms of possible actions, and as comes from "Resource" in REST, all actions are described in terms of accessible resources. I guess, you have seen the acronym "HATEOAS (Hypermedia as the engine of application state), so that's what it apparently means.
So, to interact with the service, a client uses a hypermedia format they both understand, which can be standard, homegrown or a mixture of those (e.g. XML/XHTML-based). In addition to that, they must also share the protocol, which is most likely HTTP, but since some details are omitted from the standard, there must be some idioms of its usage, like "Use POST to create a resource and PUT to update". Also, such protocol would include the entry points of the service (again, in terms of accessible resources).
Those three aspects fully define the domain protocol. In particular, a client is not supposed to know any internal links before it starts using the service or remember them after the interaction completes. As a result, any changes in the internal navigation, like renaming /cakes to /f5d96b5c will not affect the client as soon as it adhere the initial agreement and enters the shop through the front door.
#Benjol
You must avoid to program clients against particular URI's. When you describe a link main importance has it's meaning and not URI itself. You can change the URI any time, though this shouldn't break your client.
I'd change your example this way:
{"link": {
"rel": "collection http://relations.your-service.com/cakes",
"href": "http://tonis.com/cakes",
"title": "List of cakes",
"type": "application/vnd.yourformat+json"
}}
if there is a client which consumes your service, it needs to understand:
link structure itself
link relationships(in this case "collection" which is RFC and
"http://relations.your-service.com/cakes" which is your domain
specific link relation)
In this case client can just dereference address specified by "href" attribute and display list of cakes. Later, if you change the cake list provider URI client will continue to work, this implies that client still understands semantics of your media type.
P.S.
See registered link relation attributes:
http://www.iana.org/assignments/link-relations/link-relations.xml
Web Linking RFC: https://www.rfc-editor.org/rfc/rfc5988

RESTful Web Services: method names, input parameters, and return values?

I'm trying to develop a simple REST API. I'm still trying to understand the basic architectural paradigms for it. I need some help with the following:
"Resources" should be nouns, right? So, I should have "user", not "getUser", right?
I've seen this approach in some APIs: www.domain.com/users/ (returns list), www.domain.com/users/user (do something specific to a user). Is this approach good?
In most examples I've seen, the input and output values are usually just name/value pairs (e.g. color='red'). What if I wanted to send or return something more complex than that? Am I forced to deal with XML only?
Assume a PUT to /user/ method to add a new user to the system. What would be a good format for input parameter (assume the only fields needed are 'username' and 'password')? What would be a good response if the user is successful? What if the user has failed (and I want to return a descriptive error message)?
What is a good & simple approach to authentication & authorization? I'd like to restrict most of the methods to users who have "logged in" successfully. Is passing username/password at each call OK? Is passing a token considered more secured (if so, how should this be implemented in terms of expiration, etc.)?
For point 1, yes. Nouns are expected.
For point 2, I'd expect /users to give me a list of users. I'd expect /users/123 to give me a particular user.
For point 3, you can return anything. Your client can specify what it wants. e.g. text/xml, application/json etc. by using an HTTP request header, and you should comply as much as you can with that request (although you may only handle, say, text/xml - that would be reasonable in a lot of situations).
For point 4, I'd expect POST to create a new user. PUT would update an existing object. For reporting success or errors, you should be using the existing HTTP success/error codes. e.g. 200 OK. See this SO answer for more info.
the most important constraint of REST is the hypermedia constraint ("hypertext as the engine of application state"). Think of your Web application as a state machine where each state can be requested by the client (e.g. GET /user/1).Once the client has one such state (think: a user looking at a Web page) it sees a bunch of links that it can follow to go to a next state in the application. For example, there might be a link from the 'user state' that the client can follow to go to the details state.
This way, the server presents the client the application's state machine one state at a time at runtime. The clever thing: since the state machine is discovered at runtime on state at a time, the server can dynamically change the state machine at runtime.
Having said that...
on 1. the resources essentially represent the application states you want to present to the client. The will often closely match domain objects (e.g. user) but make sure you understand that the representations you provide for them are not simply serialized domain objects but states of your Web application.
Thinking in terms of GET /users/123 is fine. Do NOT place any action inside a URI. Although not harmful (it is just an opaque string) it is confusing to say the least.
on 2. As Brian said. You might want to take a look at the Atom Publishing Protocol RFC (5023) because it explains create/read/update cycles pretty well.
on 3. Focus on document oriented messages. Media types are an essential part of REST because they provide the application semantics (completely). Do not use generic types such as application/xml or application/json as you'll couple your clients and servers around the often implicit schema. If nothing fits your needs, just make up your own type.
Maybe you are interested in an example I am hacking together using UBL: http://www.nordsc.com/blog/?cat=13
on 4. Normally, use POST /users/ for creation. Have a look at RFC 5023 - this will clarify that. It is an easy to understand spec.
on 5. Since you cannot use sessions (stateful server) and be RESTful you have to send credentials in every request. Various HTTP auth schemes handle that already. It is also important with regard to caching because the HTTP Authorization header has special specified semantics to caches (no public caching). If you stuff your credentials into a cookie, you loose that important piece.
All HTTP status codes have a certain application semantic. Use them, do not tunnel your own error semantics through HTTP.
You can come visit #rest IRC or join rest-discuss on Yahoo for detailed discussions.
Jan