Webinar: Personalizing your web apps with Fauna & Netlify | October 20th at 1:00 p.m. PT
Register now
Fauna logo
Product
Solutions
Pricing
Resources
Company
Log InContact usSign Up
Fauna logo
Pricing
Customers
Log InContact usSign Up
© 2022 Fauna, Inc. All Rights Reserved.

Get Started

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
graphql

Request Demo

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
graphql

Table of Contents

graphql

The quest for the universal protocol: REST, XML, and GraphQL

Evan Weaver|Jan 18th, 2022
GraphQL occupies a unique place in the technology landscape. It’s an application interchange format that’s both efficient and human-readable, general-purpose but semantically clear, standards-based yet extensible. It is neither too narrow and specialized nor too broad and vague.
I wrote a previous post that explored the evolution of API formats and network RPC protocols reaching back to the mainframe days through to CORBA and COM embedding in Microsoft Windows. In this post we pick up in the early 90s with HTTP and then XML. These technologies helped lay the foundation for the widespread adoption of GraphQL we are seeing today. We will also talk about why Fauna is investing heavily in it.

HTTP and XML

As we discussed in the last post, while CORBA was trying to solve the general-purpose application interchange problem, HTTP was trying to solve the single-purpose information exchange problem. HTTP and HTML defined an API for reading and updating documents, and that was basically it. Unlike Gopher, which still had a terminal-driven mindset, HTML made fewer assumptions about the interaction model between the client and the server and was both human-readable and easily extensible for more complex types of documents.
That sounds great! Why didn’t we make CORBA do that? Well, we tried, and that try was XML in the 2000s.
For a while, XML was treated with the same reverence that containers have been treated today. It was the general-purpose, completely flexible solution that was going to solve every productivity problem, including every API problem, as long as you just believed enough and invested enough to implement it purely and completely.
This did not work. At some point, some semantics have to be agreed on out-of-band for an API to mean anything. XML took great pains to allow you to define any data type you wanted and any semantics you wanted. Of course, this meant that someone else consuming your API, including a human being reading it, couldn’t do anything with it, because they lacked any shared semantics despite the interchange documents being HTML-like text.
Several attempts were then made to narrow what XML could do to make it more useful, specifically XML-RPC and SOAP. The XSLT standard was developed to support arbitrary transformations of XML, such that if you received some random nonsense with obscure semantics, you could declaratively convert it to something meaningful via what was essentially a giant XML-ified regular expression. This was usually very slow with the limited computing power of the time.
Here is an example of a simple XSLT transformation:
XML Document
<?xml version="1.0"?>
<salutation>
    Hello, World!
</salutation>
XSLT transformation
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
    <xsl:apply-templates select="salutation"/>
</xsl:template>
<xsl:template 
match="salutation">
    <html>
   	 <body>
   		 <h1>
   			 <xsl:value-of select="."/>
   		 </h1>
   	 </body>
    </html>
</xsl:template>
</xsl:stylesheet>
Output
<html>
    <body>
   	 <h1>
   		 Hello, World!
   	 </h1>
    </body>
</html>
If this does not sound very great, it was not, and we’re glad you did not have to live through it. However, XML greatly influenced the regularization of HTML into HTML5 and many other things.

Contemporary binary protocols

Now we finally reach the modern era, and the bifurcation between the two types of RPC protocols persists. On the one hand, we have machine-oriented protocols like GRPC, Avro, and Thrift. These are designed to be very flexible within a specific environment where clients and servers share common organizational control. They offer a shared IDL and standardized networking implementations that make it easy to stand up servers to do arbitrary things without reinventing the networking and API wheel. They use binary wire formats that are very fast to parse and reflect the realities of modern hardware implementations well.
However, there is no reasonable way for arbitrary clients and servers to interact over these protocols and preserve the collaborative properties that make the web so great: human readable formats, shared semantics, simple implementations, and a commitment to indefinite forwards and backwards compatibility. What if we want those things?

REST

Prior to GraphQL, the best choice for such a use case was REST. REST is essentially a standardization, and an articulation of the philosophy, of what HTTP was designed to be. It fixes endpoint semantics to GET, POST, PUT, PATCH, and DELETE, resource namespaces to URIs, and supports the absolute minimum amount of semantic discovery: the OPTIONS verb, which simply tells you which of the other five verbs are allowed.
In practice, almost all use of REST for APIs uses JSON as the interchange format, and because JSON has fixed datatypes and a self-describing schema, tautology ensures that the data itself is also well-formed and discoverable (although not necessarily enforced). Luckily for us as well, JSON parsing is no longer slow as machine resources and implementations have evolved, to the point that it is competitive with binary protocols in non-critical path scenarios.
REST works amazingly well if the fundamentals of your interaction pattern are document-oriented and you do not need content negotiation for the body of the request or the response. It does not work so well if, for example, you want to implement additional verbs, or evolve your schema over time, or handle large numbers of small objects at once, or traverse a state machine like a shopping cart application needs to do. To accomplish this with REST, you need to layer your own semantic meaning over a command-style pattern, which sort of defeats the purpose.
Shopping cart state diagram

State machines are difficult to model in REST

However, in contrast to XML, adding complexity to a simple solution is still usually better than taking an overly complex solution and attempting to narrow it to your use case. This is an important lesson for the final protocol we will discuss: GraphQL.

GraphQL, a universal interface

What if we could bake extensible interface schemas into REST? If we could, we would get GraphQL. Parsing efficiency notwithstanding, we get everything we need for both the totally general, controlled, custom APIs, and the document-oriented, discoverable, human-readable, standardized and collaborative APIs.
With GraphQL we get a server-side IDL and schema that is self-hosted and discoverable, helping developers understand the API semantics, and the software understand the syntax. We also get the ability for a client to provide a dynamic schema with each of those requests, which can issue multiple commands, refer to multiple endpoints (resolvers), and pass arguments as well. The schema and inner arguments communicate to the server how to compose, filter, and transform the data in the way the client wants to see it, which solves many compatibility and efficiency problems.
type User {
	login: ID!
	name: String
	avatar: String
}
type Photo {
	id: ID!
	name: String!
	url: String!
	description: String
	created: DateTime!
	category: PhotoCategory!
	postedBy: User!
}
Like REST, GraphQL most often uses HTTP as the network transport and JSON as the interchange format. Other transports and formats are possible but less commonly used. GraphQL types are encoded as JSON without extending JSON itself. Unlike XML, GraphQL does not allow for arbitrary type definition at the protocol level. It supports argument-passing within the request, rather than as HTTP query strings, which are prone to encoding and proxy problems. The composition ability also lets the implementers of GraphQL servers (like Fauna) ensure that every request is transactional, which solves many correctness problems that otherwise arise when composition needs to happen across many individual requests.
GraphQL simplifies the REST verbs to just “query”, “mutation”, and “subscription”, consolidating the overlapping update types, but adding a new type of streaming read. Streaming read semantics are fundamentally different from normal read semantics, and attempts to layer streaming on top of REST resulted in hacky, non-composable abstractions. We also get other useful things based on the practical experience of building modern applications, like variables and basic control flow that we can use within the request to reduce redundancy.
query {
	allPhotos(category: "Pets") {
    	name
    	description
    	url
	}
}

type Mutation {
	postPhoto(
    	name: String!
    	description: String
    	category: PhotoCategory=Pets
	): Photo!
}
Of course, GraphQL isn’t perfect or complete, nor is it ideal for every use case. The security model is underspecified. Nor is Oracle rushing to migrate Oracle database drivers to use GraphQL under the hood. But especially for modern web and mobile applications, as well as service-oriented development within a larger organization, GraphQL is a huge step forward and at least to me, effectively merges the best qualities of the two strands of API and RPC protocol development back together.

What comes after GraphQL

There isn’t really an “after GraphQL” right now. We don’t expect that GraphQL will be replaced with a new protocol. In the same way that HTML evolved into HTML5 through efforts both within the standards bodies and outside of them by innovative developers and vendors, GraphQL has a long and rich future ahead of it as it gets used more broadly and pushed into more complex and higher-value locations in the modern application stack. Adjacent technologies that offer additional capability will emerge the same way JavaScript, CSS, Flash, VRML, Java Applets, and other web technologies emerged adjacent to HTML, became popular, and sometimes faded away.
At the same time, GraphQL is an incomplete solution for the general shift towards an API-driven, serverless, programmable web. Ultimately it is still a data access interface. It is not a general-purpose programming language like JavaScript, or a general-purpose query language like SQL.
This is a good thing. It keeps the standard simpler and approachable, trading completeness for ease of implementation across multiple platforms and domains. Imagine if every web server had to parse and execute JavaScript or SQL to serve web pages and you can see the level of complexity that using a programming language as an API format would create.
However, you know, sometimes we really do want to program computers, we just don’t want to deal with the messy reality of operating them. GraphQL leaves this problem unaddressed, but we suspect that conventions will evolve over time to move the interface from merely a way to access programs that were implemented elsewhere and deployed to a GraphQL server, to a way to program general-purpose servers themselves.
Naturally, the most popular type of server that can be programmed through its API is a database, like an RDBMS, or of course, like Fauna.

Next in the series

In our next post, we will go into much more detail on Fauna’s investment in GraphQL today and how we expect it to evolve.
If you are interested in diving into Fauna’s GraphQL interface, sign up for a free account now, read our documentation, or watch our GraphQL workshop.

If you enjoyed our blog, and want to work on systems and challenges related to globally distributed systems, serverless databases, GraphQL, and Jamstack, Fauna is hiring!

Share this post

TWITTERLINKEDIN
‹︁ PreviousNext ›︁

Subscribe to Fauna's newsletter

Get latest blog posts, development tips & tricks, and latest learning material delivered right to your inbox.