Case Study: Uber’s Edge Gateway API Architecture

Posted in

Sometimes tech tools and terminology can seem largely academic and abstract until you can see them in action. When we first encounter a new tool, it can be like someone handing you a 200-page instruction manual as an introduction. It can be hard to visualize that tool’s usefulness until you see it in action.

For APIs, that can leave you in the position where either they seem highly cerebral or like they’re some sort of toy. Seeing an API in action can make all the difference, especially when you’re first starting to work with them.

Recently, Uber has been raising the hood on some of their development projects on their Uber Engineering blog. The team has described the creation and evolution of their Edge Gateway API, as well as some of the ways it’s used inside their organization. The result serves as a masterclass on designing, growing, and maintaining an API catalog for an enormous global corporation. It also offers some good examples of API-first design so you can see that design pattern in action.

First Generation

When Uber was first starting out, its infrastructure was divided into two components. The dispatch was responsible for connecting a rider and a driver. The API component is where info about the driver, rider, and trip were stored.

Both the rider and driver apps accessed the dispatch service via a single endpoint, which was hosted at /. The endpoint had a special field called messageType in its body. When the driver queried that endpoint, the response would be delivered via a JSON payload.

The driver component could accept RPC commands, 15 of which were to determine the driver’s states. Some of the commands were accepting rides, rejecting rides, and one for the rider to request a trip.

The first generation of the Uber API is an example of one monolithic service that still managed to be of use to the public and the company. This system didn’t last very long, however, as the system quickly outgrew this rudimentary setup.

Uber Edge Gateway API: 2nd Generation

Uber was an early adopter of microservices. By 2019, all Uber services were powered by over 2,200 microservices. Between the years of 2015 and 2019, Uber developed RTAPI, or real-time API, which began as a single RESTful API to power over 20 different mobile clients. This was the beginning of the API Gateway in earnest.

Some of the goals for the 2nd generation of the Uber Gateway API were:

Decoupling

With Uber APIs exploding and growing at an exponential rate, things were quickly getting out of control. The Uber Gateway API allowed an indefinite amount of developers to work on new features for the API independently while still honoring the existing API contracts.

Transforming Protocols

Before the 2nd generation of Uber’s Gateway API, all transactions were handled via HTTP and JSON. Then, a new protocol was unveiled on Uber’s backend. This created a dichotomy that required an additional translation layer.

Reduced Backend Roundtrips

The 2nd generation of the Uber Gateway API also reduced the number of round trips from the frontend to the backend. The API Gateway consolidates all of the API calls and microservice queries at one central point to reduce the amount of back and forth trips to the backend. This is particularly important in areas with limited connectivity or expensive data plans.

Technical Challenges For 2nd Generation Uber Gateway API

Some of the challenges that Uber developers ran into during the second generation of the Uber Gateway API illustrate some of the challenges most companies face when their API reaches a particular size.

First of all, Uber had to decide what framework they’d use for the Gateway API. Previously, Uber’s developers were working exclusively with Node.js. However, this was proving to be problematic, as there were sometimes as many as 50,000 tests that needed to happen every time the code was updated. Updating Node.js could require upgrading over 2,500 NPM libraries as an additional challenge.

At this stage, Uber also switched to gRPC, which was also not supported by Node.js. These challenges made it evident that their API architecture would need to be re-thought during the next generation of the Gateway API.

Uber Gateway API: 3rd Generation

By 2018, Uber had unveiled a whole new suite of services, from delivering food to freight. This made the Uber API more of an ecosystem than one inclusive product. This created the conditions that made today’s Edge Gateway API possible.

The Edge Layer consolidated most of the features developed during the 2nd Generation. A ‘Presentation Layer’ was implemented as well, which allowed the different products to maintain their own appearance. It also allowed consumers to customize their displays.

A Product Layer was unveiled in the Gateway API’s 3rd generation, as well. This made an API describing the individual apps available, making it possible to develop new products using those APIs.

The 3rd Generation of the Gateway API addressed some of the technical limitations of the 2nd Generation. These revisions allowed for a pure Edge gateway to be implemented in the 3rd Generation. These revisions also made the API more scalable, as individual components were transformed into microservices.

The 3rd Generation of the Uber Gateway API is also when the Edge Gateway was introduced as a standalone product.

Enter the Edge Gateway

The Edge Gateway is a simple Golang service with a UI built on top. Its purpose is to serve as the API management layer. This gives Uber developers a single destination to create, configure, and modify APIs.

Now let’s delve into some of the features of the Edge Gateway itself to learn how the API management layer deals with some common problems in developing and maintaining APIs.

API Management

Most apps above a certain level of complexity consume several APIs to fulfill their intended purpose. This means that all of the backend services need to be handled by a single layer. This is the API management layer. API management is the name for the creation, configuration, editing, removal, and versioning of APIs, particularly gateway APIs.

The existence of an API management layer helps to standardize what developers include in their APIs, which also makes it ready to be consumed by other Uber apps. The API management layer declares an APIs:

  • Path
  • Data type
  • Response type
  • Maximum number of calls allowed
  • Headers
  • Field mapping
  • Apps allowed
  • Transfer protocols

Once an API’s configuration is determined, the API management layer creates functional APIs based on these constraints. It also creates the SDKs that allow an app to consume them.

Let’s take a peek under the hood to see what’s happening during an API call. This will help to illustrate how the Gateway Edge API streamlines the creation and consumption of APIs.

Protocol Manager

The first step in the API management layer is the Protocol Manager. This decouples a payload from its file format. The Protocol Manager largely works with JSON files as that’s what’s most commonly found in APIs, but it can also work with Thrift and Protobuf files.

Middleware

Middleware is the step between the backend and the final endpoint. Some common functions handled by middleware include:

  • Authorization
  • Rate limiting
  • Authentication

The Edge Gateway API also has several middleware functions that it performs automatically. This makes it so that individual API calls don’t have to implement them each time.

Endpoint Handler

The endpoint handler layer validates requests, transforms payloads, and converts the endpoint request into a client request object. The Endpoint Handler layer essentially acts as a translator, converting the behind-the-scenes actions of the backend, converting the returned object into the format specified by the schema.

Client

Finally, the Edge Gateway has a Client layer for managing client interactions. Users can specify request formats, transformations necessary for requests and responses, schema validation, deadline and timeline management, and error handling.

What We’ve Learned From Uber’s Edge Gateway API

Like we said at the beginning, one of the world’s biggest corporations revealing anything about the way they use technology is cause for celebration. For API users, the detailed notes that Uber has released on the evolution of their Edge Gateway API are especially informative and valuable as Uber has been using APIs for years. This means they’ve done all the trial and error for you. Following along with the evolution of the Edge Gateway can help reveal what not to do when designing an API. It’s an invaluable lesson in pitfalls to avoid.

The main takeaway from studying the Edge Gateway is how to make an API scalable. Uber has to have one of the most rugged, demanding API ecosystems on the planet, sometimes handling millions of API calls each second from all over the planet.

Uber’s Edge Gateway API illustrates how an API gateway, or some sort of abstraction layer, prepares your API for scalability. Even if your API demands are currently modest, following these or similar practices will make developing and maintaining your API as efficient and painless as possible. Adopting a microservice-like setup makes it so you can have multiple development teams working on your API simultaneously without having to worry about breaking anything or waiting on delays.

The Edge Gateway also illustrates how your API should be ready for anything. It’s a tutorial on using abstraction layers, API gateways, and schemas to configure API resources for any consumer.

The notes from Uber’s engineering blog are a masterclass in API design, as well. It’s an excellent example of how to think about the big picture and the smaller, individual components that make that picture possible. It’s all too common to make things up as you go along when starting a business or developing a new product.

As you can see from the different generations of the Edge Gateway, it’s all too common for this approach to result in service creep until either they become grossly inefficient or cease working altogether. It’s an illustration of the microservice dilemma. Some foresight and careful planning should help you to decide on the correct size and scope of each component, potentially even before you begin your project. This will also prevent features from breaking down the line, saving you and your audience much pain and countless headaches in the process. Finally, Uber’s Edge Gateway is an example of how a well-designed API could power an entire fleet of additional services or even become a service in and of themselves. The sky’s the limit when you unlock the full potential of APIs.