Search code examples
resthttppostgetrequest

What is the correct http verb for a Download in a REST API?


I have encountered a the case where I'm not sure whether an Endpoint should be answering a POST or a GET Request.

The Situation:

I have a database table called Reports with UUIDs as primary keys. The user should be able to create a Report as PDF according to some logic and data stored in different tables.

For now I implemented an endpoint as reports/<uuid>/export which is a GET endpoint.

But, after implementing this, i was curious: Is GET even the correct HTTP verb/request type for this endpoint?

Or more general: What is the correct HTTP verb for an endpoint which provides a download of a resource provided a primary key?


Solution

  • What is the correct HTTP verb for an endpoint which provides a download of a resource provided a primary key?

    Short answer is that GET semantics are normally what you want to use.

    The request method token is the primary source of request semantics; it indicates the purpose for which the client has made this request and what is expected by the client as a successful result. RFC-7231; section 4.1

    The GET method requests transfer of a current selected representation for the target resource. GET is the primary mechanism of information retrieval and the focus of almost all performance optimizations. Hence, when people speak of retrieving some identifiable information via HTTP, they are generally referring to making a GET request. RFC-7231; section 4.3.1

    Resources are identified by their URI; the two requests below target different resources:

    GET /example?uuid=764baee2-c5be-49cc-ac83-c9d1ea61d68a HTTP/1.1
    GET /example?uuid=3b90b949-911c-433c-bec4-e6063f5377e0 HTTP/1.1
    

    From the point of view of REST, these are different even though the underlying implementation (aka the "endpoint") is likely to be the same.

    You can think of the URI itself as being a key used to look up a resource in a document store.

    It's more common that we will use some form of template to extract from the target uri the specific information that we need on the server to access the data -- for instance, extracting the uuid parameter out of the query part and using that as a primary key.

    That's the ideal setting: if the request semantics are effectively read-only, and we are expecting a representation of the resource (for example, a PDF) to be returned, then GET is the method we want.

    Sometimes circumstances aren't ideal: this comes about when we need information contained in the request-body to do the right thing. In HTTP, a payload (message-body) on a GET request has no defined semantics. So if you need to have a body on the request, then GET is out of bounds, and you are probably going to use POST instead.

    Various ad hoc limitations on request-line length are found in practice. It is RECOMMENDED that all HTTP senders and recipients support, at a minimum, request-line lengths of 8000 octets. RFC-7230; section 3.1.1

    Unless you control the clients, you may not be able to ensure that 8000 octets is supported. So you'll often instead end up with a simpler resource identifier, and lots of information encoded into the message-body (think SOAP, or GraphQL), and POST as the request method because the semantics of the other methods don't fit.

    It's not ideal, because something like a PDF representation of a resource should be cacheable, but the semantics of HTTP caching don't support the use case where the request's message-body must be part of the cache key. See Mark Nottingham 2012-09-04