I'm designing a REST api, following best practices, including a form of hypermedia/hateoas. I'm using jsonapi for the design guidelines, which seems to be pretty complete.
Currently, I have a need for:
combining 2 resources in a response (a Resource A and a related Resource B). I do this using the Compound Documents - structure as specified in jsonapi. Or also commonly known as resource expansion
formatting the result of 1. in a specialized way so it can be readily consumed by a specialized client that expects said formatting.
My problem is with 2. How do I correctly represent this in a REST-way? It seems I may need a separate endpoint, but that wouldn't be 'RESTy', since that implies a separate resource, while it's just a transformation of the output of the same resource.
Any references on how to do this?
You could use a header or a query param to handle this.
When the client needs specific formatting, they could add an additional header to the request something like Format:Indented or something like http:\\myapp.com\resouces\myresource?format=indented
Or if the server is formatting and wants the client to know that the response is pre-formatted, the server could add a Format response header to notify the client that response is formatted.
Related
I am just getting started with REST API and I have a few question. I am not sure exactly when it's best to use query parameters or path parameters or to send data in the body?
Right now I am designing a social media platform, and for example I don't know if when a user adds a comment, how should he use it? Is adding it in the request body the best option?
Please, also explain in general, not only for this example. Thank you!
I am not sure exactly when it's best to use query parameters or path parameters or to send data in the body?
query parameters and path parameters are part of the resource identifier; these tell the server which resource we are talking about.
The information that describes how you want the server to change its resources belongs in the request body.
For example, when I submit this answer to stack overflow, the text I'm currently typing belongs in the HTTP request body.
The real difference between query parameters and path parameters is pretty small: with path parameters, other resources with identifiers in the same hierarchy can be described using relative references; with query parameters, you support the creation of general purpose HTML forms that can be used to compute resource identifiers.
But that's purely a mechanical concern. The machines don't care very much, so you can choose any spelling conventions that make life easier for some humans you care about.
First of all you should decide which method to use:
GET - retrieve data
PUT - update data
POST - create data
DELETE - remove data
For your example with comment I would use POST or PUT depending on your architecture. Normally both of them are used with the "body".
Query parameters are mostly used with GET for filtering etc. when you are obtaining some data.
In my app, the backend will use an endpoint to get and update data (with GET and PUT method). The exact same JSON schema is used for both operations. The question is, should I also use the same model for the update request body and the get response body for this or not? Can you tell me the pros and cons of either separating and combining them?
Thanks.
Should model of a request for a PUT method be the same class with the model of the response of the GET method?
See RFC 7231:
A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response.
It is normal that the PUT request will have the same Media Type as a successful GET response for that target-uri.
HTTP defines the semantics of the messages, but doesn't constrain the implementation (see Fielding 2002).
That said, if GET and PUT are using representations that change for the same reason, then a common implementation is reasonable, so it will likely be easier to maintain your code when those two paths share the same underlying model.
what about the Single Responsibility Principle if it's the same class?
My answer is that the Single Responsibility Principle doesn't actually make your code better in this case, so you don't use it. There are different ways you can try to generalize that idea; one is that you are working with a data structure, not an "object". Another is that this information is crossing a boundary, and at the boundaries, applications are not object-oriented.
Expressing that idea somewhat differently: what you have here is a single responsibility (manage some in memory representation of the message), but two different roles; an outbound role for the GET scenario (where you need to be able to convert the message into bytes, describe the content-type, and so on), and an inbound role for the PUT scenario (where you need to extract units of information from the data structure).
I'm designing a REST API and I'm a big defender of keeping my URL simple, avoiding more than two nested resources.
However, I've been having second thoughts because of data security restrictions that apply to my APIs, that have been trying to force me to nest more resources. I'll try to provide examples to be more specific, as I don't know the correct naming for this situation.
Consider a simple example where I want to get a given contact restriction for a customer, like during what period my customer accepts to be bothered with a phone call:
So, I believe it's simpler to have this:
- GET /customers/12345
- GET /customers/12345/contacts
- GET /contacts/9999
- GET /contacts/9999/restrictions
- GET /restrictions/1
than this:
- GET /customers/12345
- GET /customers/12345/contacts
- GET /customers/12345/contacts/9999
- GET /customers/12345/contacts/9999/restrictions
- GET /customers/12345/contacts/9999/restrictions/1
Note: If there are more related resources, who knows where this will go...
The first case is my favourite because since all resources MUST have a unique identifier, as soon I have its unique identifier I should be able to get the resource instance directly: GET /restrictions/1
The data security restriction in place in my company states that not everyone can see every customers' info (eg: only some managers can access private equity customers). So, to guarantee that, the architects are telling me I should use /customers/12345/contacts/9999/restrictions/1 or /customers/12345/contact-restrictions/1 so that our data access validator in our platform has the customerId to check if the caller has access to it.
I understand the requirement and I see its value. However, I think that this kind of custom security informatio, because that's what I believe to be, should be in a custom header.
So, I believe I should stick to GET /restriction/1 with a custom header "customerId" with the value 12345.
This custom header would only be needed for the apis that have this requirement.
Besides the simpler URL, another advantage of the header, is that if an API didn't start with that security requirement and suddenly needs to comply to it, we could simply require the header to be passed, instead of redefining paths.
I hope I made it clear for you and I'll be looking to learn more about great API design techniques.
Thank you all that reached the end of my post :)
TL;DR: you are fighting over URI design, and REST doesn't actually offer guidance there.
REST, and REST clients, don't distinguish between your "simpler" design and the nested version. A URI is just an opaque sequence of bytes with some little domain agnostic semantics.
/4290c3b2-134e-4647-867a-214d0c866f29
Is a perfectly "RESTFUL" URI. See Stefan Tilkov, REST: I don't Think it Means What You Think it Does.
Fundamentally, REST servers are document stores. You provide a key (the URI) and the server provides the document. Or you provide a key, and the server modifies the document.
How this is implemented is completely at the discretion of the server. It could be that /4290c3b2-134e-4647-867a-214d0c866f29 is used to look up the tuple (12345, 9999, 1), and then the server checks to see if the credentials described in the request header have permission to access that information, and if so the appropriate representation of the resource corresponding to that tuple is returned.
From the client's perspective, it's all the same thing: I provide an opaque identifier in a standard way, and credentials in a standard way, and I get access to the resource or I don't.
the architects are telling me I should use /customers/12345/contacts/9999/restrictions/1 or /customers/12345/contact-restrictions/1 so that our data access validator in our platform has the customerId to check if the caller has access to it.
I understand the requirement and I see its value. However, I think that this kind of custom security information, because that's what I believe to be, should be in a custom header.
There's nothing in REST to back you up. In fact, the notion of introducing a custom header is something of a down check, because your customer header is not something that a generic component is going to know about.
When you need a new header, the "REST" way to go about it is to introduce a new standard. See RFC 5988 for an example.
Fielding, writing in 2008
Every protocol, every media type definition, every URI scheme, and every link relationship type constitutes prior knowledge that the client must know (or learn) in order to make use of that knowledge. REST doesn’t eliminate the need for a clue. What REST does is concentrate that need for prior knowledge into readily standardizable forms.
The architects have a good point - encoding into the uri the hints that make it easier/cheaper/more-reliable to use your data access validator is exactly the sort of thing that allowing the servers to control their own URI namespace is supposed to afford.
The reason that this works, in REST, is that clients don't depend on URI for semantics; instead, they rely on the definitions of the relations that are encoded into the links (or otherwise expressed by the definition of the media type itself).
I am in a situation where in I want to REST GET only the objects that I require by addressing them with one of the parameters that I know about those objects.
E.g., I want to GET all the USERS in my system with ids 111, 222, 333.
And the list can be bigger, so I don't think it is best way to append the URL with what is required, but use payload with json.
But I am skeptical using JSON payload in a GET request.
Please suggest a better practice in the REST world.
I am skeptical using JSON payload in a GET request.
Your skepticism is warranted; here's what the HTTP specification has to say about GET
A payload within a GET request message has no defined semantics
Trying to leverage Undefined Behavior is a Bad Idea.
Please suggest a better practice in the REST world.
The important thing to recognize is that URI are identifiers; the fact that we sometimes use human readable identifiers (aka hackable URI) is a convenience, not a requirement.
So instead of a list of system ids, the URI could just as easily be a hash digest of the list of system ids (which is probably going to be unique).
So your client request would be, perhaps
GET /ea3279f1d71ee1e99249c555f3f8a8a8f50cd2b724bb7c1d04733d43d734755b
Of course, the hash isn't reversible - if there isn't already agreement on what that URI means, then we're stuck. So somewhere in the protocol, we're going to need to make a request to the server that includes the list, so that the server can store it. "Store" is a big hint that we're going to need an unsafe method. The two candidates I would expect to see here are POST or PUT.
A way of thinking about what is going on is that you have a single resource with two different representations - the "query" representation and the "response" representation. With PUT and POST, you are delivering to the server the query representation, with GET you are retrieving the response representation (for an analog, consider HTML forms - we POST application/x-www-form-urlencoded representations to the server, but the representations we GET are usually friendlier).
Allowing the client to calculate a URI on its own and send a message to it is a little bit RPC-ish. What you normally do in a REST API is document a protocol with a known starting place (aka a bookmark) and a sequence of links to follow.
(Note: many things are labeled "REST API" that, well, aren't. If it doesn't feel like a human being navigating a web site using a browser, it probably isn't "REST". Which is fine; not everything has to be.)
But I believe POST or PUT are for some requests that modify the data. Is it a good idea to use query requests with them ?
No, it isn't... but they are perfect for creating new resources. Then you can make safe GET calls to get the current representation of the resource.
REST (and of course HTTP) are optimized for the common case of the web: large grain hypermedia, caching, all that good stuff. Various use cases suffer for that, one of which is the case of a transient message with safe semantics and a payload.
TL;DR: if you don't have one of the use cases that HTTP is designed for, use POST -- and come to terms with the fact that you aren't really leveraging the full power of HTTP. Or use a different application - you don't have to use HTTP if its a bad fit.
For a resource that will be deleted, ultimately with a soft delete (isDeleted flag), I am looking to provide a reason to store along with the resource for audit purposes.
The options I have encountered don't feel correct.
Custom HTTP Header
DELETE with Body
I have also considered instead using a PUT, but the content I would be putting is different from what makes up the resource on a typical update.
Which method makes the most sense from a RESTful perspective ?
DELETE with a body is wrong, in that it doesn't respect the semantics of the uniform interface defined in the HTTP specification.
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
Note that the spelling used here is the same as that of a payload for a GET request.
Semantically, DELETE is the right choice; soft vs hard delete is "beyond the scope of the specification", which is to say it is an implementation choice.
But communicating the "reason" gives you two problems to solve. One is where to put that reason, and the answer is, of course, to use a header.
New header fields can be defined such that, when they are understood by a recipient, they might override or enhance the interpretation of previously defined header fields, define preconditions on request evaluation, or refine the meaning of responses.
You can look through the message-headers registry to see if there is a close match to your requirements, but failing that you would define one of your own.
The second problem is figuring out how to communicate with the client so that it knows to use the header field. The most common approach today is to just write the header into the description of the API, but that's not quite REST.
The REST answer is that your hypermedia specification describes how the server might communicate to the client which headers are important, and what data should be put there. Imagine an HTML form with a "field-value" input control, and you've got the right idea.
Not many API bother to do it that way.
PUT is an intriguing choice; there's nothing in the rules that says that a resource can have only one content type, or that an endpoint must accept only one content type.
For instance, RFC 7807 defines application/problem+json, a simple representation for reporting issues from the server. But there's no reason that you couldn't PUT an application/problem+json representation to a resource to induce a soft delete.
This specification gives you both a title and a details element to play with, so the client has room to work.
Of course, it doesn't have to be application/problem+json -- you can specify a more suitable media type of your own design.
Again, you have similar problems to the using delete with a custom header: how does the client discover that your resources support put deletes?