Reputation: 75
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
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
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-server
and/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
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:
POST /v1/servers
GET /v1/servers/{server_id}
POST /v1/servers/{server_name}
(given name is unique) returns single resourceGET /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