REST Webservices (post / put) : which type of parameter should I choose, and when?

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.

3

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.

5

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

0

–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
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
      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
     end
       
     select  @status as statusResult --, @statusText as statusText ,@response as response
       
END

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *