Appropriate REST design for data export - api

What's the most appropriate way in REST to export something as PDF or other document type?
The next example explains my problem:
I have a resource called Banana.
I created all the canonical CRUD rest endpoint for that resource (i.e. GET /bananas; GET /bananas/{id}; POST /bananas/{id}; ...)
Now I need to create an endpoint which downloads a file (PDF, CSV, ..) which contains the representation of all the bananas.
First thing that came to my mind is GET /bananas/export, but in pure rest using verbs in url should not be allowed. Using a more appropriate httpMethod might be cool, something like EXPORT /bananas, but unfortunately this is not (yet?) possible.
Finally I thought about using the Accept header on the same GET /bananas endpoint, which based on the different media type (application/json, application/pdf, ..) returns the corresponding representation of the data (json, pdf, ..), but I'm not sure if I am misusing the Accept header in this way.
Any ideas?

in pure rest using verbs in url should not be allowed.
REST doesn't care what spelling conventions you use in your resource identifiers.
Example: https://www.merriam-webster.com/dictionary/post
Even though "post" is a verb (and worse, an HTTP method token!) that URI works just like every other resource identifier on the web.
The more interesting question, from a REST perspective, is whether the identifier should be the same that is used in some other context, or different.
REST cares a lot about caching (that's important to making the web "web scale"). In HTTP, caching is primarily about re-using prior responses.
The basic (but incomplete) idea being that we may be able to re-use a response that shares the same target URI.
HTTP also has built into it a general purpose mechanism for invalidating stored responses that is also focused on the target URI.
So here's one part of the riddle you need to think about: when someone sends a POST request to /bananas, should caches throw away the prior responses with the PDF representations?
If the answer is "no", then you need a different target URI. That can be anything that makes sense to you. /pdfs/bananas for example. (How many common path segments are used in the identifiers depends on how much convenience you will realize from relative references and dot segments.)
If the answer is "yes", then you may want to lean into using content negotiation.
In some cases, the answer might be "both" -- which is to say, to have multiple resources (each with its own identifier) that return the same representations.
That's a normal thing to do; we even have a mechanism for describing which resource is "preferred" (see RFC 6596).

REST does not care about this, but the HTTP standard does. Using the accept header for the expected MIME type is the standard way of doing this, so you did the right thing. No need to move it to a separate endpoint if the data is the same just the format is different.

Media types are the best way to represent this, but there is a practical aspect of this in that people will browse a rest API using root nouns... I'd put some record-count limits on it, maybe GET /bananas/export/100 to get the first 100, and GET /bananas/export/all if they really want all of them.

Related

GET vs. POST when the request is some arbitrary size

I understand the semantics of GETting vs. POSTing, one endpoint should get data, the other should post it. The latter being a request that you may not wish the user to be able to easily replay.
That said, on the project I'm working on at the moment - the approach has been to POST to endpoints that are clearly responsible for responding with data, and these endpoints do not transform data in any way.
The reasoning behind this has been that the payloads are (potentially) of considerable size and seem more appropriate for a body as opposed to a query string.
Can anybody please shed light on which request would be right for a GET request that takes a large request payload? I'm not asking for opinion, I'm asking for what would be compliant to RESTful deisgn.
Further Context
The request is potentially large due to the fact it's a search DTO from the UI, where users may choose to pass any number of filters or search terms.
Can anybody please shed light on which request would be right for a GET request that takes a large request payload? I'm not asking for opinion, I'm asking for what would be compliant to RESTful deisgn.
Today's answer: It's OK to use POST.
For requests that are fundamentally read-only, we'd like to use standardized HTTP semantics to communicate that to general purpose components, so that they can themselves do intelligent things.
BUT: GET, while being both safe and ubiquitous, isn't an appropriate choice when you need to include a message-body in the request:
content received in a GET request has no generally defined semantics
So if you can't, for whatever reason, copy the information you need into a resource identifier, then GET is not an option.
Now, if your payloads are consistent with WebDAV, then you might be able to use one of the safe methods described in those specifications. But, as far as I can tell, they aren't really appropriate for general use.
Tomorrow's answer: the HTTP-WG accepted a proposal for a safe-method-with-body. So we should eventually expect to see a registered HTTP method that is safe and has defined semantic for the request content.
Then, depending on what those semantics are, we may be able to use it for requests like yours.

REST API Design: Can I use parameters to change the response structure?

I am trying to design a REST API that will return detailed information about an identifier that I pass in. For the sake of an example, I am passing in an identifier and returning information about a specific vehicle. The problem that I am facing is that there are many different kinds of vehicles, each with different unique properties. I am wondering if there is a way so that I can only return the relevant details with the REST API.
Currently I plan on having one endpoint /vehicles and passing in the identifier as a parameter.
My current request will consist of something like this GET /vehicles?id=123456
My current response structure will be something like this:
{
"vehicleDetails" : {
"color": "someColor",
"make: "someMake",
"model: "someModel",
"year: "someYear",
"carDetails": {
// some unique car fields
},
"motorcycleDetails" : {
// some unique motorcycle fields
},
"boatDetails" : {
// some unique boat fields
}
}
}
As you can see, there are some fields that are common to all vehicle types, but there are also fields that are unique to a certain type of vehicle, for example boatDetails. As far as I understand, I will have to return the entire resource which will have many empty fields. For example, when I request information about a car, I will still have boat and motorcycle details returned as part of the JSON response, even though they will all be empty. My concern with this is that the response payloads will be rather large when only a small subset of the fields will actually be used by the consumer. Would it make sense to add another parameter to filter the fields that come back? Something like /vehicles?id=123456&type=Car? Then in my code I could manipulate the response structure based on the type parameter? I feel that this violates REST best practices. Any advice into how I could change the design of my API would be appreciated.
Note: I cannot use GraphQL for this and would appreciate input about how I can improve this REST API design
Sure,query parameters (as well as matrix and path parameters) are fine from a REST standpoint. You'll end up with a unique URI that identifies a resource. Responses will be cacheable regardles what type of parameters you use. It is though questionable whether exposing the parameter as query parameter has any advantages over exposing it directly as path paramter, i.e. /vehicles/12345 in that case.
What IMO is more important than the actual form of the URI is the representation format you return. The proposed response format bears the potential of being treated as typed resource instead of utilizing a general, multi-purpose format and propper content-type negotiation. Think of HTML i.e. it defines the syntax and semantics of certain hyper-media controls you can use and any arbitrary Web client will be able to present it and operate on the response format. With custom formats, however, you will miss out on that feature.
If you only have one client, that moreover is under your control, the additional overhead you need to put in is probably not worth aiming for a REST environment in general, as it is easier to change the client once the server stuff changed. Though if you aim for a long-living environment that may be utilized by clients not under your control, this is for sure a thing to consider.
Can I use parameters to change the response structure?
Yes.
Example: https://www.merriam-webster.com/dictionary/JPEG
Notice that -- even though the URI says JPEG, the server is actually returning a text/html document, and the browser knows that from the Content-Type header in the HTTP response.
Identifiers are semantically opaque, in the same way that variable names are. We tend to choose spellings that make things easy for humans, but the machines don't care what spelling conventions we use.
So there's no constraint that says that /vehicles?id=1 and /vehicles?id=2 have to have the same "structure".
So you could have application/prs.rbanders-car, application/prs.rbanders-boat and application/prs.rbanders-rocketship, each with its own specific processing rules.
More likely, though, you'll want to piggyback on some other more common representation; so it's common to see a structured syntax suffix: application/prs.rbanders-car+json`, etc. Effectively, you are promising a json document, but with a more specific schema.
Of course, there's nothing stopping you from creating a application/prs.rbanders-vehicle+json schema, and then describing some fields as optional that will only appear if some condition is met.
Different options, different trade offs.
I feel that this violates REST best practices.
Not really - the important ideas are to handle metadata in a standard way (so that general purpose components can understand what is going on) and to use common formats where it makes sense to do so (to leverage the libraries that are already available).

With REST, do you use a body or query params when creating a Resource?

I'm working on a digital media library where users can create entries for a Media resource.
The media resource is made up of tons of properties, eg:
Media:{
id,
name,
type,
private,
}
the url users use to create a resource is
POST api/media
On the backend, we are creating the resource with a UID generated for them while defaulting name, type and private values. However, users can pass in name, type, private if they choose to.
RFC 4.3.3 doesn't seem to have an opinion on whether or not to use params or post body for these data.
So is it better to do this
api/media?type="audio"&name="Hopkins County Collective"&private=false
or with a body instead?
api/media
body{
name:
type:
private:
}
Althought after reading section 4.3.3 for POST here https://www.rfc-editor.org/rfc/rfc7231#section-4.3.3 and I see this piece
Providing a block of data, such as the fields entered into an HTML
form, to a data-handling process;
I'm leaning toward the post fields in the body but I'm still unsure.
Thanks
do you use a body or query params when creating a Resource?
The Body. But it can be more complicated than that.
HTTP gives us standardized message semantics - we all agree, by adopting the common standard, what a given message means. That doesn't necessarily constraint what we do with the message when we get it.
For example.
PUT /id=1 HTTP/?.?
Content-Type: text/plain
id=2
That message means that we want the resource identified by /id=1 to have the representation id=2. In other words, this is the future behavior intended by the client
GET /id=1 HTTP/?.?
200 OK
Content-Location: /id=1
Content-Type: text/plain
id=2
So the body describes what we want the representation to be, and the effective-uri identifies which document we are talking about.
The same basic pattern holds for POST and PATCH - the effective-uri tells us which resource we want to change, the body describes that change.
BUT...
You the server aren't actually required to do what the request asks you to do. You can reject the request (4xx), or you can do something similar to the request, and tell the client about that.
So you might, as part of the implementation hidden behind your REST facade, copy information from the effective-uri in addition to, or instead of, exactly applying the instructions provided by the client in the body of the request. (You have to be a little bit careful with the response metadata to ensure there's no ambiguity about what you did do).
Anecdotally, "just about everyone" seems to be using the body to represent what they want the created resource to look like, be, or contain.
Parameters are often not likely to be used at all, and if they are, only for, perhaps, controlling aspects of how that resource is to be created, not anything having to do with what the resource is to look like, be, or contain.
I say anecdotal, because I'm sure there are exceptions to this -- you're even contemplating it. That said, REST does not specifically say anything about parameters vs. body.
For the sake of conformity, and for the sake of "doing it like everyone else", go with body.
There are other considerations pointing away from parameters: 1) they are part of the URI, and URIs are used for identification purposes, 2) the query string length is highly constrained, so would prevent creating large objects, and 3) it would be a diagnostics/debugging nightmare parsing the query string in your head trying to make sense of it.

How do I design a REST call that is just a data transformation?

I am designing my first REST API.
Suppose I have a (SOAP) web service that takes MyData1 and returns MyData2.
It is a pure function with no side effects, for example:
MyData2 myData2 = transform(MyData myData);
transform() does not change the state of the server. My question is, what REST call do I use? MyData can be large, so I will need to put it in the body of the request, so POST seems required. However, POST seems to be used only to change the server state and not return anything, which transform() is not doing. So POST might not be correct? Is there a specific REST technique to use for pure functions that take and return something, or should I just use POST, unload the response body, and not worry about it?
I think POST is the way to go here, because of the sheer fact that you need to pass data in the body. The GET method is used when you need to retrieve information (in the form of an entity), identified by the Request-URI. In short, that means that when processing a GET request, a server is only required to examine the Request-URI and Host header field, and nothing else.
See the pertinent section of the HTTP specification for details.
It is okay to use POST
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”
It's not a great answer, but it's the right answer. The real issue here is that HTTP, which is a protocol for the transfer of documents over a network, isn't a great fit for document transformation.
If you imagine this idea on the web, how would it work? well, you'd click of a bunch of links to get to some web form, and that web form would allow you to specify the source data (including perhaps attaching a file), and then submitting the form would send everything to the server, and you'd get the transformed representation back as the response.
But - because of the payload, you would end up using POST, which means that general purpose components wouldn't have the data available to tell them that the request was safe.
You could look into the WebDav specifications to see if SEARCH or REPORT is a satisfactory fit -- every time I've looked into them for myself I've decided against using them (no, I don't want an HTTP file server).

REST API routing with params good practice

There's routing for my server:
/api/debts/:id
to get info about particular debt and
/api/debts/search?searchData=something
to search debts by something.
And first route always handles search requests. I want to change it and know how to do it in several ways (just remove /api/debts in the second route etc) but I want to know a good practice for this.
UPD: There's also the route
/api/debts
to get all debts
For search or filter purposes /api/debts?searchData=something is preferred.
In /api/debts/search?searchData=something, this is not considered good, because it has search which it verb and the searchData is outside the resources.
For details please refer
here
I want to change it and know how to do it in several ways (just remove /api/debts in the second route etc) but I want to know a good practice for this.
REST doesn't care what spelling conventions you use for your resource identifiers.
So if you decide, in the support of other concerns, that you want to use a different path, then go ahead and do that.
/debts/search?searchData=something
/search/debts?searchData=something
Those are both fine. Sticking additional path-segments like api on the front is also fine. General purpose clients don't care, because they are just copying the identifier into the request line
this is not considered good, because it has search which it verb
Consider the URI below
https://www.merriam-webster.com/dictionary/search
This works, and exactly the way you would expect, even though "search" happens to be a verb (sometimes) in the English language.
It's even ok to use registered HTTP methods in your identifiers:
GET /dictionary/delete HTTP/1.1
Host: www.merriam-webster.com
You can try that one in your web browser by clicking on
https://www.merriam-webster.com/dictionary/delete
What doesn't work particularly well is assuming that the identifier defines the request semantics; the request method is the appropriate mechanism for communicating the request semantics, not the identifier. In other words
GET /delete
is a request that promises safe semantics; if you handle that request by making a bunch of destructive edits, then that's a fault of the implementation
The confusion here is not Raj's fault, of course -- there is a LOT of literature on the web that (a) describes arbitrary spelling constraints for resource identifiers and (b) cites "REST" as an authority for those constraints.
Part (b) has no factual basis - it's just folklore that has gained traction.
REST doesn't care about spelling conventions for your identifiers in the same way that compilers don't care about spelling conventions for your variable names.
REST cares a lot about when two identifiers are the same, because caching, and particularly cache invalidation are important things for the general purpose components to be able to do correctly.
But the machines don't distinguish between nouns, verbs, hmac codes, rot13 ciphers, etc.