Understanding RPC Vs REST For HTTP APIs — Smashing Magazine (2024)

  • Phil Sturgeon
  • 0 comments
  • 12 min read
  • Coding,Tools,JavaScript,Ruby on Rails

About The Author

Phil is a programming polyglot, author of Build APIs You Won’t Hate, and a Software Engineer at WeWork. As a Brit in New York, he’s always trying to …More aboutPhil↬

Email Newsletter

.
Trusted by 200,000+ folks.

REST stands for “representationalstatetransfer,” For the last few years, whenever somebody wants to start building an HTTP API, they pretty much exclusively use REST as the go-to architectural style, over alternative approaches such as XML-RPC, SOAP and JSON-RPC. In this article, Phil Sturgeon discusses two approaches in the context of buildingHTTP APIs. RPC and REST can both be used via other transportation protocols, such as AMQP, but that is another topic entirely.

Knowing the differences between REST and RPC can be incredibly useful when you are planning a new API, and it can really help when you are working on features for existing APIs. It’s best not to mix styles in a single API, because this could be confusing both to consumers of your API as well as to any tools that expect one set of conventions (REST, for example) and that fall over when it instead sees a different set of conventions (RPC). Use REST when it makes sense, or use RPC if it is more appropriate. Or use both and have the best of both worlds!

For the last few years, whenever somebody wants to start building an HTTP API, they pretty much exclusively use REST as the go-to architectural style, over alternative approaches such as XML-RPC, SOAP and JSON-RPC. REST is made out by many to be ultimately superior to the other “RPC-based” approaches, which is a bit misleading because they are just different.

This article discusses these two approaches in the context of building HTTP APIs, because that is how they are most commonly used. RPC and REST can both be used via other transportation protocols, such as AMQP, but that is another topic entirely.

REST stands for “representational state transfer,” described by Roy Fielding in his dissertation. Sadly, that dissertation is not widely read, and so many people have their own idea of what REST is, leading to a lot of confusion and disagreement. REST is all about a client-server relationship, where server-side data are made available through representations of data in simple formats, often JSON and XML. These representations for resources, or collections of resources, which are then potentially modifiable, with actions and relationships being made discoverable via a method known as hypermedia. Hypermedia is fundamental to REST, and is essentially just the concept of providing links to other resources.

Beyond hypermedia there are a few other constraints, such as:

  • REST must be stateless: not persisting sessions between requests.
  • Responses should declare cacheablility: helps your API scale if clients respect the rules.
  • REST focuses on uniformity: if you’re using HTTP you should utilize HTTP features whenever possible, instead of inventing conventions.

These constraints (plus a few more) allow the REST architecture to help APIs last for decades, not just years.

Before REST became popular (after companies such as Twitter and Facebook labeled their APIs as REST), most APIs were built using an XML-RPC or SOAP. XML-RPC was problematic, because ensuring data types of XML payloads is tough. In XML, a lot of things are just strings, so you need to layer meta data on top in order to describe things such as which fields correspond to which data types. This became part of the basis for SOAP (Simple Object Access Protocol). XML-RPC and SOAP, along with custom homegrown solutions, dominated the API landscape for a long time and were all RPC-based HTTP APIs.

The “RPC” part stands for “remote procedure call,” and it’s essentially the same as calling a function in JavaScript, PHP, Python and so on, taking a method name and arguments. Seeing as XML is not everyone’s cup of tea, an RPC API could use the JSON-RPC protocol, or you could roll a custom JSON-based API, as Slack has done with its Web API.

Take this example RPC call:

POST /sayHello HTTP/1.1HOST: api.example.comContent-Type: application/json{"name": "Racey McRacerson"}

In JavaScript, we would do the same by defining a function, and later we’d call it elsewhere:

/* Signature */function sayHello(name) { // ...}/* Usage */sayHello("Racey McRacerson");

The idea is the same. An API is built by defining public methods; then, the methods are called with arguments. RPC is just a bunch of functions, but in the context of an HTTP API, that entails putting the method in the URL and the arguments in the query string or body. SOAP can be incredibly verbose for accessing similar-but-different data, like reporting. If you search “SOAP example” on Google, you’ll find an example from Google that demonstrates a method named getAdUnitsByStatement, which looks like this:

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="https://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"> <soapenv:Header> <ns1:RequestHeader soapenv:actor="https://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0" xmlns:ns1="https://www.google.com/apis/ads/publisher/v201605"> <ns1:networkCode>123456</ns1:networkCode> <ns1:applicationName>DfpApi-Java-2.1.0-dfp_test</ns1:applicationName> </ns1:RequestHeader> </soapenv:Header> <soapenv:Body> <getAdUnitsByStatement xmlns="https://www.google.com/apis/ads/publisher/v201605"> <filterStatement> <query>WHERE parentId IS NULL LIMIT 500</query> </filterStatement> </getAdUnitsByStatement> </soapenv:Body></soapenv:Envelope>

This is a huge payload, all there simply to wrap this argument:

<query>WHERE parentId IS NULL LIMIT 500</query>

In JavaScript, that would look like this:

/* Signature */function getAdUnitsByStatement(filterStatement) { // ...};/* Usage */getAdUnitsByStatement('WHERE parentId IS NULL LIMIT 500');

In a simpler JSON API, it might look more like this:

POST /getAdUnitsByStatement HTTP/1.1HOST: api.example.comContent-Type: application/json{"filter": "WHERE parentId IS NULL LIMIT 500"}

Even though this payload is much easier, we still need to have different methods for getAdUnitsByStatement and getAdUnitsBySomethingElse. REST very quickly starts to look “better” when you look at examples like this, because it allows generic endpoints to be combined with query string items (for example, GET /ads?statement={foo} or GET /ads?something={bar}). You can combine query string items to get GET /ads?statement={foo}&amp;limit=500, soon getting rid of that strange SQL-style syntax being sent as an argument.

So far, REST is looking superior, but only because these examples are using RPC for something that REST is more adept at handling. This article will not attempt to outline which is “better,” but rather will help you make an informed decision about when one approach might be more appropriate.

What Are They For?

RPC-based APIs are great for actions (that is, procedures or commands).

REST-based APIs are great for modeling your domain (that is, resources or entities), making CRUD (create, read, update, delete) available for all of your data.

REST is not only CRUD, but things are done through mainly CRUD-based operations. REST will use HTTP methods such as GET, POST, PUT, DELETE, OPTIONS and, hopefully, PATCH to provide semantic meaning for the intention of the action being taken.

RPC, however, would not do that. Most use only GET and POST, with GET being used to fetch information and POST being used for everything else. It is common to see RPC APIs using something like POST /deleteFoo, with a body of { "id": 1 }, instead of the REST approach, which would be DELETE /foos/1.

This is not an important difference; it’s simply an implementation detail. The biggest difference in my opinion is in how actions are handled. In RPC, you just have POST /doWhateverThingNow, and that’s rather clear. But with REST, using these CRUD-like operations can make you feel like REST is no good at handling anything other than CRUD.

Well, that is not entirely the case. Triggering actions can be done with either approach; but, in REST, that trigger can be thought of more like an aftereffect. For example, if you want to “Send a message” to a user, RPC would be this:

POST /SendUserMessage HTTP/1.1Host: api.example.comContent-Type: application/json{"userId": 501, "message": "Hello!"}

But in REST, the same action would be this:

POST /users/501/messages HTTP/1.1Host: api.example.comContent-Type: application/json{"message": "Hello!"}

There’s quite a conceptual difference here, even if they look rather similar:

  • RPC.
    We are sending a message, and that might end up storing something in the database to keep a history, which might be another RPC call with possibly the same field names — who knows?
  • REST.
    We are creating a message resource in the user’s messages collection. We can see a history of these easily by doing a GET on the same URL, and the message will be sent in the background.

This “actions happen as an afterthought” can be used in REST to take care of a lot of things. Imagine a carpooling app that has “trips.” Those trips need to have “start,” “finish” and “cancel” actions, or else the user would never know when they started or finished.

In a REST API, you already have GET /trips and POST /trips, so a lot of people would try to use endpoints that look a bit like sub-resources for these actions:

  • POST /trips/123/start
  • POST /trips/123/finish
  • POST /trips/123/cancel

This is basically jamming RPC-style endpoints into a REST API, which is certainly a popular solution but is technically not REST. This crossover is a sign of how hard it can be to put actions into REST. While it might not be obvious at first, it is possible. One approach is to use a state machine, on something like a status field:

PATCH /trips/123 HTTP/1.1Host: api.example.comContent-Type: application/json{"status": "in_progress"}

Just like any other field, you can PATCH the new value of status and have some logic in the background fire off any important actions:

module States class Trip include Statesman::Machine state :locating, initial: true state :in_progress state :complete transition from: :locating, to: [:in_progress] transition from: :in_progress, to: [:complete] after_transition(from: :locating, to: :in_progress) do |trip| start_trip(trip) end after_transition(from: :in_progress, to: :complete) do |trip| end_trip(trip) end endend

Statesman is an incredibly simple state machine for Ruby, written by the GoCardless team. There are many other state machines in many other languages, but this is an easy one to demonstrate.

Basically, here in your controllers, lib code or DDD logic somewhere, you can check to see if "status" was passed in the PATCH request, and, if so, you can try to transition to it:

resource.transition_to!(:in_progress)

When this code is executed, it will either make the transition successfully and run whatever logic was defined in the after_transition block, or throw an error.

The success actions could be anything: sending an email, firing off a push notification, contacting another service to start watching the driver’s GPS location to report where the car is — whatever you like.

There was no need for a POST /startTrip RPC method or a REST-ish POST /trips/123/start endpoint, because it could simply be handled consistently within the conventions of the REST API.

When Actions Can’t Be Afterthoughts

We’ve seen here two approaches to fitting actions inside a REST API without breaking its RESTfulness, but depending on the type of application the API is being built for, these approaches might start to feel less and less logical and more like jumping through hoops. One might start to wonder, Why am I trying to jam all of these actions into a REST API? An RPC API might be a great alternative, or it could be a new service to complement an existing REST API. Slack uses an RPC-based Web API, because what it’s working on just would not fit into REST nicely. Imagine trying to offer “kick,” “ban” or “leave” options for users to leave or be removed from a single channel or from the whole Slack team, using only REST:

DELETE /users/jerkface HTTP/1.1Host: api.example.com

`DELETE` seems like the most appropriate HTTP method to use at first, but this request is so vague. It could mean closing the user’s account entirely, which might be very different to banning the user. While it could be either of those options, it definitely would not be kick or leave. Another approach might be to try `PATCH`ing:

PATCH /users/jerkface HTTP/1.1Host: api.example.comContent-Type: application/json{"status": "kicked"}

This would be a weird thing to do, because the user’s status wouldn’t be globally kicked for everything, so it would need further information passed to it to specify a channel:

PATCH /users/jerkface HTTP/1.1Host: api.example.comContent-Type: application/json{"status": "kicked", "kick_channel": "catgifs"}

Some folks try this, but this is still odd because there is a new arbitrary field being passed, and this field doesn’t actually exist for the user otherwise. Giving up on that approach, we could try working with relationships:

DELETE /channels/catgifs/users/jerkface HTTP/1.1Host: api.example.com

This is a bit better because we’re no longer messing with the global /users/jerkface resource, but it is still missing a “kick,” “ban” or “leave” option, and putting that into the body or query string is once again just adding arbitrary fields in an RPC way.

The only other approach that comes to mind is to create a kicks collection, a bans collection and a leaves collection, with some endpoints for POST /kicks, POST /bans and POST /leaves endpoints to match. These collections would allow meta data specific to the resource, like listing the channel that a user is being kicked from, for example, but it feels a lot like forcing an application into a paradigm that doesn’t fit.

Slack’s Web API looks like this:

POST /api/channels.kick HTTP/1.1Host: slack.comContent-Type: application/json{ "token": "xxxx-xxxxxxxxx-xxxx", "channel": "C1234567890", "user": "U1234567890"}

Nice and easy! We’re just sending arguments for the task at hand, just like you would in any programming language that has functions.

One simple rule of thumb is this:

  • If an API is mostly actions, maybe it should be RPC.
  • If an API is mostly CRUD and is manipulating related data, maybe it should be REST.

What if neither is a clear winner? Which approach do you pick?

Use Both REST And RPC

The idea that you need to pick one approach and have only one API is a bit of a falsehood. An application could very easily have multiple APIs or additional services that are not considered the “main” API. With any API or service that exposes HTTP endpoints, you have the choice between following the rules of REST or RPC, and maybe you would have one REST API and a few RPC services. For example, at a conference, somebody asked this question:

“We have a REST API to manage a web hosting company. We can create new server instances and assign them to users, which works nicely, but how do we restart servers and run commands on batches of servers via the API in a RESTful way?”

There’s no real way to do this that isn’t horrible, other than creating a simple RPC-style service that has a POST /restartServer method and a POST /execServer method, which could be executed on servers built and maintained via the REST server.

Further Reading

  • HTTPS Everywhere With Nginx, Varnish And Apache,” Rachel Andrew
  • A Beginner’s Guide To jQuery-Based JSON API Clients,” Ben Howdle
  • How To Apply Transformations To Responsive Web Design,” Ishan Anand
  • Responsive Web Design - What It Is And How To Use It,” Vitaly Friedman

Understanding RPC Vs REST For HTTP APIs — Smashing Magazine (9)(rb, yk, al, il, nl, mrn)

Explore more on

Understanding RPC Vs REST For HTTP APIs — Smashing Magazine (2024)
Top Articles
Estimating project costs with confidence and accuracy | Nulab
Top 10 Reasons Why Python Is So Popular In 2024
Davita Internet
Ffxiv Palm Chippings
Research Tome Neltharus
Valley Fair Tickets Costco
Mohawkind Docagent
Emmalangevin Fanhouse Leak
Mndot Road Closures
Erskine Plus Portal
13 The Musical Common Sense Media
World Cup Soccer Wiki
Craigslist Heavy Equipment Knoxville Tennessee
Slag bij Plataeae tussen de Grieken en de Perzen
Oscar Nominated Brings Winning Profile to the Kentucky Turf Cup
Love In The Air Ep 9 Eng Sub Dailymotion
Leader Times Obituaries Liberal Ks
Committees Of Correspondence | Encyclopedia.com
Huntersville Town Billboards
Timeforce Choctaw
Ford F-350 Models Trim Levels and Packages
Routing Number For Radiant Credit Union
Bn9 Weather Radar
Sofia the baddie dog
City Of Durham Recycling Schedule
Urbfsdreamgirl
Truvy Back Office Login
Table To Formula Calculator
Sandals Travel Agent Login
Orange Park Dog Racing Results
Neteller Kasiinod
Maths Open Ref
DIY Building Plans for a Picnic Table
Have you seen this child? Caroline Victoria Teague
The Pretty Kitty Tanglewood
Steven Batash Md Pc Photos
Tamil Play.com
Atlantic Broadband Email Login Pronto
Spinning Gold Showtimes Near Emagine Birch Run
Oreillys Federal And Evans
Asian Grocery Williamsburg Va
Afspraak inzien
Directions To 401 East Chestnut Street Louisville Kentucky
Academic important dates - University of Victoria
Gpa Calculator Georgia Tech
Housing Intranet Unt
T&Cs | Hollywood Bowl
St Vrain Schoology
Online College Scholarships | Strayer University
Understanding & Applying Carroll's Pyramid of Corporate Social Responsibility
Unpleasant Realities Nyt
Tyrone Unblocked Games Bitlife
Latest Posts
Article information

Author: Nathanael Baumbach

Last Updated:

Views: 5671

Rating: 4.4 / 5 (55 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Nathanael Baumbach

Birthday: 1998-12-02

Address: Apt. 829 751 Glover View, West Orlando, IN 22436

Phone: +901025288581

Job: Internal IT Coordinator

Hobby: Gunsmithing, Motor sports, Flying, Skiing, Hooping, Lego building, Ice skating

Introduction: My name is Nathanael Baumbach, I am a fantastic, nice, victorious, brave, healthy, cute, glorious person who loves writing and wants to share my knowledge and understanding with you.