Why you should consider using RPC over REST for internal API
- Published
REST is a very popular architecture style for communication. HTTP - as the most commonly used protocol for REST - gives a lot of features for free: cache, basic authentication, metadata channel (via headers), security (SSL/TLS), CORS etc. It fits almost perfectly for public API. But are those features really necessary for internal API?
Have you heard about RPC? Ask your teammates about it and you will probably hear "RPC? Do you mean SOAP?" or "RPC? Dude, no one uses it anymore. Remember CORBA?". That's right. A lot of people hate RPC because of ancient technologies. But times have changed and nowadays we have really good implementations of RPC: GRPC , JSON-RPC, Thrift. Is it worth trying it again? What's wrong with REST then?
Before we move further I'd like to state what I mean by "internal API". Internal API is a communication interface between internal services with restricted access, for instance, between web app and microservice for user management.
Public API vs internal API
Set of requirements is different for each of them.
Internal API | Public API | |
---|---|---|
Caching | No, to prevent fetching stale data | Desirable |
Authentication | Not necessary in private networks | Required |
Impersonation | Desirable | No |
Abuse detection/prevention | No | Desirable |
Ease to use | As easy as possible during development process | Publish API SDK for customers |
Versioning | Not necessary | Desirable |
Performance | As fast as possible | You can sacrifice some performance for usage flexibility (HTTP content type negotiation, e-tag caching, CORS, HATEOAS) |
Having that in mind it's easy to conclude that you don't have to use the same mechanisms for both APIs.
REST verbs are very limited
For REST in order to perform an operation on a resource you need to set a HTTP Method like GET (default), PUT, POST, DELETE or custom (read further). What if you need to validate entity before saving or activating an user? There is no HTTP method for validation and activation. We need some workaround (BTW REST got a lot of them).
You can use sub-resources
# activate user
PUT /user/1/activate
# validate entity
POST /entity/validate {...}
but this one is really weird. Exposing "action" as a fake resource is a hack and definitely not intuitive.
Let's try custom method then.
ACTIVATE /user/1
VALIDATE /entity {...}
Unfortunatelly custom methods might not be supported by your http server (or a client) so you're forced to use X-HTTP-Method-Override header .
And now compare it to RPC
validateEntity {...}
activateUser 1
We've got a clear winner here.
REST arguments passing is complicated
With REST you have 4 channels to pass the arguments in REST
- HTTP Headers
- URL path
- URL query
- HTTP Body
Examples of common operations
# Set access to "admin" for user 1 in team 2
PUT /user/1/teams/2/access "admin"
# Insert element at the end of the queue
POST /queue?last=true {...}
# or
X-Position: last
POST /queue {...}
# much simpler for RPC
setUserAccess 1, 2, "admin"
putToQueueAtTheEnd {...}
Handling such cases manually throughout the codebase gets messy very quickly so it's much better to create custom client
REST requires custom client
You don't want to build all URLs manually, set x-http-method-override header or perform other boring operations in order to make a simple call. You'll need a custom client for every service in every programming language 1 and that is counter-productive. In case of schema-less RPC libraries2 you don't have to, since making API calls is very simple.
rpcService.call('setUserAccess', userId, teamId, group);
Bulk actions
createUsers [{...}, {...}]
You're not limited to HTTP with RPC
Do you want to use pure TCP (or websockets) and binary format3 without HTTP overhead for the best possible performance? Not a problem. Do you want to use ZeroMQ with all its goodness for RPC? A piece of cake.
Can you do the same with REST? Well, you need to implement all REST key components: HTTP headers, URL, HTTP body, HTTP negotiation, Cache etc.
Summary
RPC is a very simple API design approach with absolutely no limitations. For public API stay with REST but for internal ones give a try to JSON-RPC, DDP or even GRPC and I bet you won't be disappointed.