REST and gRPC API design considerations

691 views
Skip to first unread message

ccl...@dieselpoint.com

unread,
Jan 10, 2017, 8:17:59 PM1/10/17
to grpc.io
I'm trying to design an API for our app. We're going to have to support a REST API, but I'd really also like to have a gRPC API as well.

The question is -- how to design them so they're roughly the same? And in particular, what do we do about verbs / actions?

The standard rule in designing a REST API is to use nouns, not verbs. This blog post explains it well:

https://apigee.com/about/blog/technology/restful-api-design-nouns-are-good-verbs-are-bad

You should have http methods that look like this:

GET /dogs/1234        // get a dog
POST /dogs              // create a dog
DELETE /dogs/1234  // delete a dog

and not this:

/createDog
/deleteDog

Unfortunately, gRPC makes standard REST-style calls impossible, because it doesn't support path parameters, and as far as I can tell it always uses the POST http method.

So, I have two ways to modify the REST calls to make them gRPC compatible:

1. Put a verb in the endpoint:

POST /dogs/create  body={ id: 1234, name="Fluffy" }

or 2. Put the verb in the body:

POST /dogs body={ action:"create", id: 1234, name="Fluffy" }

What do most people do?

Michael Rose

unread,
Jan 10, 2017, 10:20:58 PM1/10/17
to grpc.io
We solved this by building a layer to map HTTP+JSON calls onto RPCs. The https://github.com/grpc-ecosystem/grpc-gateway project does this, as does https://github.com/fullcontact/grpc-jersey (what we built). They both map normal HTTP/JSON requests onto gRPC handlers by annotating RPC methods with rules which expose them as HTTP/1.1 methods. e.x.:

service UserService {
    rpc GetUser (GetUserRequest) returns (User) {
        option (google.api.http).get = "/users/{id}";
    }
    rpc CreateUser (CreateUserRequest) returns (User) {
        option (google.api.http) = {
            post: "/users/"
            body: "*"
        };
    }
}


We left RPC as RPC, and then mapped HTTP/1.1 (sometimes "REST", not all RPC maps well as REST) onto it. REST resource verbs map well onto resource management RPCs (e.x. createFoo/listFoo/getFoo/deleteFoo/updateFoo -> POST /foo, GET /foo, GET /foo/{id}, DELETE /foo/{id}, PUT /foo/{id}).

gRPC is implemented on top of HTTP/2, certainly, but I wouldn't try to interface with it directly. Treat it as any other binary protocol. gRPC's use of HTTP trailers make it fairly unsuitable for interfacing with. I don't believe you'll achieve much success trying to modify gRPC to produce a REST-compatible API, even if you can have it produce JSON. Either use one of the available projects or write a manual mapping layer.

Regards,
Michael

Carl Mastrangelo

unread,
Jan 13, 2017, 4:41:23 PM1/13/17
to grpc.io
I can't speak for most people, but IMO rest breaks down after a few years of API evolution.  RPC breaks down too, but to a lesser extent*.  

To answer your specific question, you can probably just double expose your API under two endpoints, since they will have different semantics and usage patterns.  Since you are splitting methods by nouns and verbs none of your URL paths should overlap.  You can delegate based on the initial request path to the correct gRPC or Rest handler.

*In case it matters I worked on a REST API for a while, and was occasionally bitten by REST semantics not being convenient.  Doing transactional updates in a REST model is pretty annoying.  Doing anything involving a non-idempotent mutation is annoying (like incrementing a view counter).   
Reply all
Reply to author
Forward
0 new messages