Mayur
Mayur

Reputation: 75

REST API POST/PUT with different set of requests

Can a post or put method that creates / modifies resource can accept different set of request objects?

For eg: I have a resource called 'server'. It can be distinguished by its os. for example I can have two resource instances - a windows server and a linux server. My basic decision here is to treat them as same type of resource i.e. server.

Now it may happen that to create a windows server my POST API accepts request object that is different from what that same API would take for linux server.

For creating windows server I have -

POST : /v1/server
accepts 
{
    name : win-server-1
    os : 'windows'
    ms-office: 'Office2009'
}

For creating linux server I use same api but consume different request object -

POST : /v1/server
accepts
{
   name : linux-server-1,
   os : 'linux'
   kernel-version : '3.10.0' 
}

As you can see requests accepted by same POST API are different for windows and linux server. My business logic will handle these request based on 'os' attribute. So technically, it will work (with ugly switch cases). But is it truly restful? Or I should have different APIs like /v1/windows-server and /v1/linux-server and have unique request definitions defined for each of them?

Upvotes: 0

Views: 790

Answers (3)

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57239

But is it truly restful?

A good way to test that question, is to ask how closely what you are trying to do matches the web.

In this case, the analog would be to have two different forms that submit requests to the same target URI described the by the form action attribute.

windows: <form action="/v1/server" method="post">
    <!-- ... -->
    Office: <input type="text" name="config.office"><br>
    <input type="submit" value="Submit">
</form> 

linux: <form action="/v1/server" method="post">
    <!-- ... -->
    Kernel-version: <input type="text" name="config.kernel-version"><br>
    <input type="submit" value="Submit">
</form>

Any standards compliant web client will handle that just fine. The processing rules for the text/html media type tell the client how to construct a request from each of these forms.

Notice that because the browser is just processing the form.action, you can easily change the resource identifier. So if you later decide that windows and linux requests should use different requests, you can do that easily enough:

windows: <form action="/v1/windows-server" method="post">
    <!-- ... -->
    Office: <input type="text" name="config.office"><br>
    <input type="submit" value="Submit">
</form> 

linux: <form action="/v1/linux-server" method="post">
    <!-- ... -->
    Kernel-version: <input type="text" name="config.kernel-version"><br>
    <input type="submit" value="Submit">
</form>

But is it truly restful?

Being "truly restful" has relatively little to do with how your server handles a request -- what is much more important is understanding how the server describes requests to the client (aka hypermedia).

Upvotes: 1

Irek L.
Irek L.

Reputation: 334

I would go for /v1/server/linux and /v1/server/windows. This will allow you to keep /v1/server for example for GET.

POST : /v1/server - as you have said, this would require more code and some "ugly switch cases". This approach will be also harder to maintain and develop when someone will request you to add new types of servers.

/v1/linux-serverand/v1/windows-server - I think it is also good approach. With just 2 types it is not a big deal to have separate endpoints. With the larger number, /v1/server/{os_type} looks better in documentation and is more readable than the list of X separate endpoints.

Upvotes: 0

jannis
jannis

Reputation: 5200

From client's POV it's better to have one endpoint. Note that having separate resources would move the neccessity of "ugly switching" to the client.

I'd go with your current solution. Client's convienience and API clarity/simplicity is more important than developer's. API is more important than implementation. And IMHO your current solution is better in this regard:

  • create: POST /v1/servers
  • fetch: GET /v1/servers/{server_id} POST /v1/servers/{server_name} (given name is unique) returns single resource
  • query: GET /v1/servers/?{filter_expression} (e.g. GET /v1/servers/?os=linux) returns collection of (filtered) resources (preferably with pagination)

One thing I'd change is I'd extract the OS-specific stuff to a nested resource. This will make the implemenation simpler and the API even clearer:

{
    name : win-server-1,
    os : 'windows',
    config: {
        ms-office: 'Office2009'
    }
}

{
    name : linux-server-1,
    os : 'linux',
    config: {
        kernel-version : '3.10.0' 
    }
}

Upvotes: 2

Related Questions