Somu
Somu

Reputation: 3750

REST API design for non-CRUD actions, e.g. save, deploy, execute code

Resource in my REST API context is application code written in some programming language. CRUD operations that can be easily mapped to HTTP verbs are save/edit/delete code. Non-CRUD operations that are difficult to map to HTTP methods are deploy the code on server, execute the code, and undeploy.

Common suggestions I came across in SO are:

  1. Restructure the action to appear like a field of a resource, e.g. if your action is to activate an engine, design URI: PATCH engines/123, body: {"status":"active"}
  2. Treat the action like a sub-resource, e.g. PUT engines/123/active without a body
  3. Use query parameters, e.g. PUT engines/123?activate=true
  4. Be pragmatic and go for a non-RESTful, RPC-style URL, e.g. PUT engines/activate?id=123

I am definitely not able to fit deploy/undeploy/execute code actions to a resource as suggested in #1 and #2. Could you please share your opinion how best we can design the APIs for these actions?

Upvotes: 25

Views: 21831

Answers (3)

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57257

Could you please share your opinion how best we can design the APIs for these actions?

Create/Update/Delete information resources, and as a side effect of that, do work behind the API.

So think documents.

One very good example: In RESTful Casuistry, Tim Bray asked about an api to shut down a machine. Seth Ladd's response, in particular, is important to read

Fundamentally, REST is a bureaucracy that solves problems with paperwork. If you want to get anything done, you submit the right form; which becomes an information resource describing what you want done.

PUT /deploymentRequests/abcde

Please find the artifacts from build 12345 and deploy that artifact
to machine 67890

201 Created

The request is just a document, in exactly the same way a sticky note on your desk asking you to address some task is a document.

As far as REST is concerned, the spelling of the URI absolutely does not matter; but from the point of view of a human readable naming convention, start from the fact that the resource is the document -- not the side effect that you want the document to have.

So, for example, it's totally normal and compliant with REST that the document that describes the current state of a thing and the document that describes changes you want to make to a thing are different documents with different identifiers.

Upvotes: 15

inf3rno
inf3rno

Reputation: 26139

CRUD operations that can be easily mapped to HTTP verbs are save/edit/delete code. Non-CRUD operations that are difficult to map to HTTP methods are deploy the code on server, execute the code, and undeploy.

I think you misunderstood the whole concept. You map operations to the HTTP method and URI, not just to the HTTP method. In the case of CRUD this is evident. In the case of "non-CRUD", you need to add a new resource with a different URI instead of trying to add a new HTTP method to the list.

PATCH is for updating a resource just like PUT, but in the case of PATCH you send update instructions instead of a representation. Sure it can be used or POST can be used too. Using PUT is not a good idea if you don't send a representation of the new resource state in the body.

So any of these can be good:

PATCH engines/123 "activate"
PUT engines/123/state "active"
POST engines/123/activation null

You can do the same with "deploy/undeploy/execute":

PATCH engines/123 "deploy"
PUT engines/123/state "before-deploy"
POST engines/123/execution null

This is just a recommendation though. You can choose the verb based on the HTTP standard and I think it is better to avoid using verbs in the URI, I use just nouns, because it makes sense this way. The URI is not that important though, it is like nice URIs on web pages, it looks good, but nobody really cares unless they have to write it down. Just to make it clear, this is still not REST unless you send these hyperlinks in your responses.

{
    id: "engines/123",
    type: "docs/engine",
    operations: [
        {
            operation: "docs/engine/activation", 
            id: "engines/123",
            method: "PATCH",
            body: "activate"
        }
    ]
}

Using RDF and ontologies takes this a lot further.

Upvotes: 0

Alireza Rahmani Khalili
Alireza Rahmani Khalili

Reputation: 2954

I think you are looking for controllers, according to REST API design RuleBook:

A controller resource models a procedural concept. Controller resources are like executable functions, with parameters and return values; inputs and outputs. Like a traditional web application’s use of HTML forms, a REST API relies on controller resources to perform application-specific actions that cannot be logically mapped to one of the standard methods (create, retrieve, update, and delete, also known as CRUD). Controller names typically appear as the last segment in a URI path, with no child resources to follow them in the hierarchy. The example below shows a controller resource that allows a client to resend an alert to a user: POST /alerts/245743/resend

and also:

POST should be used to create a new resource within a collection and execute controllers.

Upvotes: 12

Related Questions