dwwoelfel / oneblog-brand-new

0 stars 1 forks source link

Sofa — The best way to REST (is GraphQL) #256

Open dwwoelfel opened 4 years ago

dwwoelfel commented 4 years ago

Ending the REST vs GraphQL debate once and for all

TL;DR

Wait, WHAT!?

Many articles have been written about the pros and cons of GraphQL and REST APIs and how to decide which one to use. I’m not going to repeat those here..

A lot of time and energy spent by smart consultants to write those articles, read those articles, while most of them are finished with the “it depends on your use case” summary, without actually specifying those use cases!

I’ve been working with REST, GraphQL and SOAP APIs for many years. So I thought, why not come up with a list of those use cases and for each one of those to check — what can’t you do in GraphQL that you can do with REST and what you wouldn’t want to do with GraphQL and you would prefer REST.

After creating that list, I suddenly had a thought — what if there was another option — what if my powerful GraphQL server could just generate a REST API for me?

Then I could get the best of both worlds!

The more I dived into the idea and implementation then more I realized it’s not only that we can have both types of APIs created for us, but even if we just want to expose REST APIs, and none of our clients use GraphQL, GraphQL is the best way the create REST APIs!

How does the above sentence even make sense?!

Usually when we (The Guild) help companies and organizations to modernize their APIs, the first to understand the benefits of GraphQL are the frontend developers, for obvious reasons. But as soon as the backend developers “Get it”, they become the biggest advocates of the technology. But they still need to support existing clients and 3rd party partners.

That’s why those newly generated REST APIs get a lot of the features and benefits from the internal GraphQL implementation that make backend developers happy:

What I get from having resolvers?

Sofa — Use GraphQL to create RESTful APIs

So we created Sofa (pun intended), an open source library you install on your GraphQL server to create a fully RESTful and configurable API gateway. Use GraphQL to REST.

“How to” tutorial

Let’s create a short step by step tutorial on how to create a RESTful API.

Step 1: npm install the `sofa-api` package and add the following line of code:

import sofa from 'sofa-api';
import express from 'express';

const app = express();

app.use(
  sofa({ schema })
);

Step 2: Go REST on a Sofa, you’re done.

Kamil Kisiela added Sofa to the SpaceX GraphQL API implementation by Carlos Rufo, in a single commit.

Check out the fully generated REST endpoints, the Swagger live documentation, GraphiQL editor and the GraphiQL-Explorer!

By the way, what you see here is a REST API, generated on top of a GraphQL API, created on top of another REST API….

Why did you do that for!?!?

Gradually migrating from old REST implementations

This is actually a good direction to go. In many of the companies we work with, they’ve created REST API layers using old technology on top of their original web-services.

But those REST implementations are problematic (for all the obvious reasons people choose to move to GraphQL).

So our way to go is to create GraphQL implementations on top of those REST layers, migrate the clients to those implementations and then gradually remove the old RESTful layer and call the services directly.

Using Sofa made those transitions much faster because we can offer all the existing clients to migrate to our GraphQL implementation without actually using GraphQL themselves. We simply expose the same REST endpoints on top of GraphQL and they are moving to our layer happily because we can accommodate all of their requests and custom REST endpoints much faster than the original, old REST implementations.


Give me more details

Sofa uses Express by default but you can use any other server framework. Sofa is also GraphQL server implementation agnostic.

Head over to the Sofa website for documentation and to the Github repository for reporting issues and helping out.

How Sofa works?

Under the hood, Sofa turns each field of Query and Mutation types into routes. First group of routes is available only through GET method, mutations on the other hand get POST.

Sofa uses GraphQL’s AST to create an operation with all possible variables (even those deeply nested) and knows exactly what to fetch. Later on it converts the request’s body into operation’s variables and execute it against the Schema. It happens locally, but it’s also possible to use an external GraphQL Server or even Apollo Link.

Right now Sofa has a built-in support for Express but it’s totally possible to use a different framework. The main concept stays exactly the same so only the way we handle the request differs across different server implementations.

GraphQL Subscriptions as Webhooks?

The way it works is simply, you start a subscription by calling a special route and you get a unique ID that later on might be used to update or even stop the subscription. Subscriptions are Webhooks. Sofa knows exactly when there’s an even happening on your API and notifies you through the endpoint you’ve assigned a subscription to.

Models / Resources?

In some cases you don’t want to expose an entire object but just its id. How you’re able to do that with Sofa? You need to have two queries. First one has to return a single entity based just on its id (which would be an argument) and the second one should resolve a list of those. Also the names should match, for example a resource called User should have two queries: user(id: ID): User and users: [User]. Pretty much the same thing you would do with REST.

type Query {
  user(id: ID!): User
  users: [User]
}

Before Sofa creates the routes, it looks for those Models and registers them so when the operations are built you don’t fetch everything but only an id.

But what if you want to fetch an entire object but only in few places?

There’s an option called ignore that allows you to do that. You simply pass a path in which you want to overwrite the default behavior.

Given the schema below, you would get just author’s id.

type Book {
  id: ID
  title: String!
  author: User!
}
extend type Query {
  book(id: ID!): Book
  books: [Book]
}

With ignore: ['Book.author']you end up with an entire User object.

sofa({
  ...,
  ignore: ['Book.author'],
})

Swagger and OpenAPI

Thanks to GraphQL’s type system Sofa is able to generate always up-to-date documentation for your REST API. Right now we support Swagger and its OpenAPI specification but it’s really easy to adopt different specs.

import sofa, { OpenAPI } from 'sofa-api';

const openApi = OpenAPI({
  schema,
  info: {
    title: 'Example API',
    version: '3.0.0',
  },
});

app.use(
  sofa({
    schema,
    onRoute(info) {
      openApi.addRoute(info, {
        basePath: '',
      });
    },
  })
);

openApi.save('./swagger.json');

Summary

sofa-api makes it extremely easy to create a RESTful API with all the best practices of REST from a GraphQL server using all its power.

Stop wasting your life arguing about REST vs GraphQL — Be productive, get the benefits of both worlds and move into the future of API development.

I hope this would become the last REST vs. GraphQL article out there…. if you think it won’t, comment with a use case and let’s try it out!

Thanks to Kamil Kisiela for working with me on this and making this library a reality!

Follow us on GitHub and Medium, we are planning to release many more posts in the next couple of weeks about what we’ve learned using GraphQL in recent years.

{"source":"medium","postId":"d9da6e8e7693","publishedDate":1548435958095,"url":"https://medium.com/the-guild/sofa-the-best-way-to-rest-is-graphql-d9da6e8e7693"}
dwwoelfel commented 4 years ago

Hey there!