4

On a POST (or PUT) webservice, I know can use three different type of parameters, I can send my parameters in the path of the URL /objects/{path_param}, after a question mark in the URL /objects?{param_name}={Param_value} or in the body of the request.

For GET webservices, I use path to identify a ressource, and query to add some filtering when the ressource is a list.

My main question is "When should I choose to use a path/query/body on a POST/PUT webservice?". Based on that, is it acceptable to have both query parameters and body parameters on the same webservice?

For now, the only difference between query and body parameters I know is that query parameters can be sent as part of the URL, and can therefore be cached or kept in the browser history, so I'd like to know the other differences that should be take into consideration.

  • Related SO topic: 1 2 – Nelson Oct 3 '16 at 10:34
  • 1
    Cross site duplicates: stackoverflow.com/q/1619302, stackoverflow.com/q/4024271 – null Oct 3 '16 at 10:54
  • 1
    Not exactly the same question @Nelson. OP is not asking when to use GET, POST. Is asking how to use "properly" path/query/body variables into GET,POST,PUT methods – Laiv Oct 3 '16 at 11:14
4

REST API over HTTP 1.1

These are (summarising) the "principles" we should considerate if we want to be RESTful-compliant. Among many other things (see also CoRE RFC6690)

Path variables

These variables are used for referencing resources within a hierarchy. (independently of the Method)

GET: /app/{appId}/user/{userId} #single resource
GET: /app/{appId}/users #collection
POST: /app/{appId}/user/{userId}
DELETE: /app/{appId}/user/{userId}
...

Query variables

These variables are used as modifiers of the response. By modifiers we mean: filters, pagination, attribute selection,etc.

GET: /app/{appId}/users # all app users

Response modification:

  GET: /app/{appId}/users?name=Jhon&surname=Conor # Subset by filtering
  GET: /app/{appId}/users?page=1&pageSize=10 # Subset by pagination
  GET: /app/{appId}/users?page=1&pageSize=10&filter=name:jhon;surname:conor # Subset by pagination and filtering

AppId is still working for referencing. It gives the scope/context where to look at (users of the app X). Changing this value we are not modifying the response, we are switching the resource.

These variables could be used with PUT, POST, DELETE in order to perform these actions over a subset of resource, but in the words of the OP

I think the use case would be possible in theory but very rare in the practice.

(And I agreed)

Body variables

Being dogmatic, we use POST to create new resources, and PUT to modify an existing one.

Both of them require a request body, where the resource to create/update is represented in its final status.

Note: Here is important to make reference to their idempotent nature

POST: /app/{appId}/user
BODY: {"name":"Jhon", "surname":"Conor"}
PUT: /app/{appId}/user/{userId}
BODY: {"name":"Sara", "surname":"Conor"}

Again, appId and userId are mere referencing variables.

Summarizing

  • path variables: for referencing (resource navigation)
  • query variables: for response modifications
  • Body: for resource creation or modification.

Here the specifications: RFC7230 - RFC7235

SOA Webservices over HTTP 1.1

I have separated SOA WS from API RESTful because these are 2 different designs where each of them uses the mentioned Http variables in a different way.

These WS does not use URI for web resource referencing. They use them to expose procedures.

POST: /app/register
Body:  {"name":"Jhon", "pass":"Conor"}
POST: /app/sendNotification
Body:  {"from":"Jhon", "to":"skynet", text:"see you yesterday"}
POST: /app/markNotificationAsRead
Body:  {"id":"0"}
POST: /app/moveNotifications
Body:  {"from":"inbox", "to":"trash", messages:[]}
GET: /app/notifications?from=Jhon
GET: /app/notifications?if=from:Jhon;to:skynet

In this approaches, GET and POST are predominant.

Path and body variables are used as procedure arguments.

Query variables keep its function of response modificator.

The specs to implement depends on the needs of the system. As @Eric has pointed out, there are specs like RPC that can be applied to this sort of Webservices.

  • Thanks for your answer. Do that mean that use of query variables is not appropriate for PUT/POST? I don't see a case where I could apply filtering when creating/updating a given ressource. – gvo Oct 3 '16 at 11:31
  • You may need to add a new resource to certain group of resources :-). I have never made something alike, but sounds doable to me with the scenario you are pointing out – Laiv Oct 3 '16 at 11:33
  • For instance: PUT: /app/{appId}/users?name=Jhon&surname=Conor, {chasedBy:skynet}`. It could be read as Set chasedBy = skynet to any user (related to the app appId) which name is Jhon and surname is Conor. It sounds a little bit convoluted to me, but still possible. It even keeps my conventions related to query/path and body variables – Laiv Oct 3 '16 at 12:22
  • 1
    I like the idea, however I would rather use a PATCH than a PUT for such a partial update. I think the use case would be possible in theory but very rare in practice. – gvo Oct 3 '16 at 12:31
  • I have never used PATCH. I would take note of it :-) – Laiv Oct 3 '16 at 13:42
2

By the design of HTTP (RFCs 7230-7235), each endpoint represents a thing that the server is keeping track of, usually called a Resource. Sometimes that Resource is just one thing (like a single widget), and sometimes it's a group of things (or widgets). The URI is intended to be a unique specifier for a widget or group of widgets.

Most APIs use human-readable names and ids to identify these things in URIs. Some security-minded services do not do this, because it exposes information to end users that the service does not want them to have. Among human-readable APIs, the convention has become to use plural nouns to indicate collections, a plural noun followed by a unique identifier to indicate an individual item in a collection. These can nest - an individual item might itself have either a collection or individual item you want to expose directly. So:

/widgets               > all the widgets the user can see
/widgets/12            > a specific widget
/widgets/12/texture    > a widget has zero or one textures
/widgets/12/colors     > a widget has zero or more colors
/widgets/12/colors/5   > color #5 of widget #12

The above approach is typically called RESTful, even though REST is really a lot more than just that. The other common approach is called Remote Procedure Calls, or RPC for short. In RPC, endpoints represent instructions to the server, such as /writeEndOfYearCsv. If a client were to call that URL with a POST, the response might stream a CSV file with the end-of-year report. RPC is waning in popularity because it's believed to be harder to maintain over time. Properly written RPC will only use POST and GET calls.

Query parameters, defined in RFC 3986, are used to narrow down the details of a response to a URI. They are used most often with "collection resources", such as /widgets?shape=round, to narrow down the contents of the collection. In general, they are used to provide information to the server about how to build the response.

For instance, /widgets/12?expand=texture might return a widget resource with the texture information embedded in it, while /widgets/12 would only return the direct properties of the widget. A client who doesn't care about the texture doesn't have to get it, and a client who does care can save a server hit by getting the information embedded rather than just a link.

In RPC, you would use query parameters for about the same thing: POST /writeEndOfYearCsv?format=csv would give you a CSV report, while POST /writeEndOfYearCsv?format=xslx would give you an Excel report.

The body of a request typically contains the resource being created/modified (if you're using a RESTish approach), or instructions on how to process the request (if you're using an RPC approach). So when creating or updating a widget, the request would contain all the information about what makes up a widget (colors, texture, name, etc). When asking for an end-of-year report, the request might contain the year the request is for, the clients to include in the report, etc.

It is still possible to use RPC-style requests in a RESTish system. You just need to think of the request itself as a resource. So POST /reports/end-of-year with a body containing instructions would create a new report, and you could later GET /reports/end-of-year/9 to view that report.

If it seems like RPC-style requests blur the lines heavily in terms of where things "belong", that's because they do. Since HTTP was designed around a "URL-as-resource" paradigm and RPC was squeezed in on top of that, it's often up to individual developers to figure out where the right place is for a specific instruction. If you use RPC (and in general, you should try not to), figure out a general rule and be consistent within your service as to what goes where.

The body of a request or response typically depends on the type of request. In REST, the body and the response are always resource representations, but sometimes that resource is really an instruction. You would

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.