15.05.2024
Can you imagine a world without APIs? A world without the ease and reliability of an OpenAPI schema? Yeah me neither - and yet only a few years ago developers had to come up with ingenious ways to let systems talk to each other.
There is a very good article "The land before modern APIs" by Darius Kazemi about the early days of ARPANET in 1970 and how decision-making back then is still influencing software development today. One of those decisions was the specification for error and response codes for the "RJE protocol" resulting in the HTTP status codes we all know and "love" today.
But why are these early decisions so important and the modern API design so significant for our daily work?
Well, the path paved by developers in 1970 led to the development of web APIs in the early 2000. Kin Lanes’ article "Intro to APIs: History of APIs" sums up the history of APIs very well. In short, APIs went from a commercial use case over socializing the internet to powering next-generation devices. Heck, there is even an "API hub" for APIs! This all shows that APIs play a big role in modern software engineering.
Although we love our APIs, there is still an ongoing debate on how an API should work under the hood. Before 2015 you would usually go for a REST-based API design. But then Facebook open-sourced the GraphQL language for API development and gave us a new way of interacting with our data.
In this post, I want to give a small overview of REST and GraphQL, compare those two, and finally mention some other approaches to API design.
So shall we start?
REST APIs feature two fundamental characteristics that underpin their design: being statelessness and the utilization of HTTP methods. Firstly, REST APIs implement the stateless paradigm, meaning each request from a client to the server must contain all necessary information to understand and fulfill it, without relying on any previous interactions. This simplifies server implementation and scalability, as it eliminates the need to maintain a session state on the server. Secondly, REST APIs leverage the HTTP protocol's versatile methods, such as GET, POST, PUT, DELETE, to perform various actions on resources. These methods enable developers to create APIs that align closely with the principles of CRUD (Create, Read, Update, Delete), enhancing the clarity, predictability, and accessibility of their API endpoints.
Whenever you are planning an API with a well-defined client-server contract (that means, among other things, less flexibility in server responses) REST is a very good option for you. Not only is REST efficient and easy to implement, but it also has wide support in all programming languages that can work with HTTP methods.
Although REST expects predefined requests and only gives set responses it still offers a high flexibility for creating an API. You can build anything using REST!
A simple example could be a simple API that gets the images from http.cat and returns them to the user:
from fastapi import FastAPI
from fastapi.responses import Response
import requests
app = FastAPI()
@app.get("/{status_code}", description="Get cat status code", response_class=Response)
async def get_cat_status_code(status_code: int):
response = requests.get(f"https://http.cat/{status_code}")
return Response(response.content, media_type="image/jpeg")
Mind that http.cat is already an API returning an image (it’s not uncommon to call other APIs in your API). But this example should just show what is possible with a simple REST API and how it adheres to the HTTP method model. Let’s dissect it!
In this example, I used the popular FastAPI package for Python. It allows for easy creation of REST APIs.
@app.get
defines an HTTP GET method on the root path with the path parameter status_code
. In the method get_cat_status_code
I then make a GET request to the http.cat API (using the provided status_code) and finally return the image bytes as a FastAPI Response object.
This concludes this short REST example.
Although GraphQL has been around since 2015 it’s still fairly new to the API world comparing it to REST or even older technology like SOAP-based APIs.
GraphQL APIs possess distinctive characteristics that differentiate them from traditional REST APIs, offering a more flexible and efficient approach to data retrieval. One notable feature of GraphQL is its ability to optimize queries and minimize data transfer. Unlike REST APIs, where endpoints are fixed and return predefined data structures, GraphQL allows clients to specify exactly what data they need using a single query. This capability eliminates over-fetching and under-fetching issues commonly encountered with REST APIs, where clients may receive more or less data than required. Furthermore, GraphQL's type system enables clients to request nested or related data in a single query, reducing the need for multiple round trips to the server. By providing a precise and declarative syntax for data fetching, GraphQL empowers clients to fetch only the necessary data, resulting in more efficient network usage and improved performance. Additionally, GraphQL supports features like query batching and caching, further optimizing data transfer and reducing latency for client applications. Overall, GraphQL's query optimization capabilities enhance the efficiency and responsiveness of API interactions, making it a great choice for modern application development.
The use case for GraphQL APIs differs a little from REST. GraphQL should be used in data-rich environments with complex requirements. It’s also worth considering when you have multiple clients with different data needs.
Let’s set up the same example like the REST API and get some http.cat images with GraphQL!
This is the main code for the API using FastAPI and its GraphQL integration with strawberry:
import strawberry
from fastapi import FastAPI
from strawberry.asgi import GraphQL
@strawberry.type
class Cat:
url: str
@strawberry.type
class Query:
@strawberry.field
def cat(self, status_code: int) -> Cat:
return Cat(url=f"https://http.cat/{status_code}")
schema = strawberry.Schema(query=Query)
graphql_app = GraphQL(schema)
app = FastAPI()
app.add_route("/graphql", graphql_app)
app.add_websocket_route("/graphql", graphql_app)
First we define a strawberry type called Cat, then another one called Query. Query has a field called cat, which has an implicit field url. Creating a GraphQL schema can be done with strawberry-Schema, handing it to the Query class.
As you can see GraphQL is not able to return the image bytes directly, meaning you need to handle stuff like that on your own. It also needs a client on the other side that can run a query against our API. Luckily strawberry has a built in server providing such a client:
On the left side, you can see the query I put together, and on the right the JSON response from the GraphQL API.
You often read about REST vs GraphQL on the web. In my opinion, you can’t let those two technologies compete against each other. They are two very different approaches to interacting with data that we want to access. Thus a comparison between these two is not fair and you cannot generally say one approach is better than the other. I’d rather suggest when to use either one.
When you are in an environment where you have to satisfy the needs of multiple clients that want data that is differently shaped you should probably go with GraphQL. With its easy querying language, you can achieve fast, efficient responses for your clients and their different needs.
On the other hand, if you can be a bit more strict about server responses and want good caching of requests a REST-based API might be what you are looking for. Due to its standardization and usage of HTTP methods REST is widely applicable and usable. With its call for clear separation of concerns and stateless communication architecture it is also a very scalable solution.
In the end, I want to mention two alternative approaches to API development that we also use and offer at Blueshoe.
gRPC (the g does not stand for Google) is an open-source remote procedure call (RPC) framework initially developed by Google. It is built on top of HTTP/2, Protocol Buffers (protobuf), and other modern technologies, offering a robust and efficient way to connect services across different environments.
gRPC offers many benefits in Microservice architectures. A few of those are:
SOAP (Simple Object Access Protocol), a protocol for exchanging structured information in the implementation of web services, has been a part of enterprise applications for decades. It provides a standardized way for applications to communicate over networks, facilitating interoperability between diverse systems and platforms. Despite criticisms of its verbosity and complexity compared to newer protocols like REST, SOAP continues to thrive in enterprise environments due to its reliability, extensibility, and comprehensive security capabilities.
As you can see there are many ways to implement an API and choosing the right technology can be tricky sometimes. I hope with this short overview I can give a hint on when to use a certain approach to build your API. And if you ever need a tailored solution, hit us up!
Michael and Robert are talking in depth about the ins and outs of local Kubernetes development and also provide some real coding examples.
More editions of our podcast can be found here: