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, 2016 at 10:34
  • 1
    Cross site duplicates: stackoverflow.com/q/1619302, stackoverflow.com/q/4024271
    – null
    Oct 3, 2016 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, 2016 at 11:14

3 Answers 3


REST API over HTTP 1.1

These are the "principles" we consider when parenting to be make a Web API. But not the only! See also CoRE RFC6690)

Path variables

Used to identify resources within a hierarchy. In other words, along with the rest of the path, they make an identifier.

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

Query variables

Used as response modifiers. By modifiers I mean: filters, pagination, projection,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

Can 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 existing ones.

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

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"}


  • 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 both use HTTP variables in different ways.

SOA WS don't use URI for resource identification. Instead they 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 their function as response modifiers.

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 WS.

  • 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, 2016 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, 2016 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, 2016 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, 2016 at 12:31
  • I have never used PATCH. I would take note of it :-)
    – Laiv
    Oct 3, 2016 at 13:42

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


--this is a implementation with PUT and Ole Microsoft --note : the parameter go in Exec sp_OAMethod @Object, 'send', NUll, @jsonDataEdit

alter PROCEDURE [dbo].[Sp_WSInvokeApiMPExpirePreference] 
    -- Add the parameters for the stored procedure here
    --@pidPayment varchar(200)
    @pidEmp int,
    @pidDestino int,
    @pidReserva int
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
      declare @status varchar(500)='-1' --No se expiro, sin link d pago
      declare @statusText varchar(1500)=''
      declare @response varchar(3500)=''
      declare @pidPayment varchar(200) = (select [idPreference] from [dbo].[PreferenciasIdVentas] 
                                          where idventa = (select R.[idventa] from Reservas R where R.id_Empresa=@pidEmp and R.Id_Destino=@pidDestino 
                                                           and R.ID_Reserva= @pidReserva and    not Exists (Select 1 from LogCobrosMercadoPago L where L.idventa=R.idventa)))
     if @pidPayment is not null begin
         declare @jsonDataEdit  varchar(500) = '{"expiration_date_to": "'+FORMAT(GetUtcDate(),'yyyy-MM-ddTHH:mm:ssZ')+'"}'
         declare @accesToken varchar(500) ='APP_USR-4558-061211-f94e98afa1edbb6aee17c1001fd86221__LD_LC__-101777428'
         declare @Url varchar(500) = 'https://api.mercadopago.com/checkout/preferences/'+@pidPayment+'?access_token='+@accesToken 
         Declare @Object as Int;
         Declare @ResponseText as Varchar(8000);
         --Code Snippet
         Exec sp_OACreate 'MSXML2.ServerXMLHttp', @Object OUT;
         Exec sp_OAMethod @Object, 'open', NULL, 'PUT', @Url
         Exec sp_OAMethod @Object, 'send', NUll, @jsonDataEdit
         EXEC sp_OAGetProperty @Object, 'responseText', @response OUT
         EXEC sp_OAGetProperty @Object, 'status', @status OUT;
         EXEC sp_OAGetProperty @Object, 'statusText', @statusText OUT;
         Exec sp_OADestroy @Object
     select  @status as statusResult --, @statusText as statusText ,@response as response

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