Ramda and GraphQL

Ramda and GraphQL

- 4 mins

Leveraging Functional Programming to Build Flexible Schemas in Apollo Server When building a GraphQL API with Apollo Server, defining the schema is a crucial first step. The schema defines the shape of our API by specifying all of the types, queries, mutations and more.

As our API evolves, we’ll inevitably need to make changes to the schema. Doing this by directly modifying the schema strings can quickly become cumbersome. This is where functional programming shines!

In this post, we’ll use the Ramda functional programming library to build a schema for an API for a library application. By leveraging Ramda’s composable functions, we can build a flexible schema that is easy to extend and modify over time.

Defining Our Schema Types First, let’s define the types we’ll need for our library API using GraphQL schema language:

type Book {
  id: ID!
  title: String!
  author: String!
}

type Author {
  id: ID! 
  name: String!
}

Rather than defining these types directly in our schema string, we’ll use Ramda to compose them separately so they are reusable.

First, we construct our Book type. We can keep the book fields in an object so we can easily add new fields later:

const bookFields = {
  id: 'ID!',
  title: 'String!',
  author: 'String'
}

We can even define some basic fields that will be reused across types:

const basicFields = {
    id: 'ID!',
    createdAt: 'String!',
}

Now we can construct the bookFields object by merging the basicFields with book-specific fields:

const bookFields = R.merge(basicFields, {
    title: 'String!',
    author: 'String'
}

This allows us to reuse the basic fields, while still customizing for the Book type.

Now let’s use Ramda to compose the Book type:

const BookType = R.compose(
  R.concat(R.of('type Book {'), R.of('}')),
  R.join('\n'),
  R.map(field => `  ${field}`),
  R.of,
  bookFields
);

And similarly for Author:

const AuthorType = R.compose(
  R.concat(R.of('type Author {'), R.of('}')), 
  R.join('\n'),
  R.map(field => `  ${field}`),
  R.of,
  authorFields
);

By constructing the types separately like this, we make them reusable composable units.

Assembling Our Schema Now let’s put together the full schema by composing the parts:

const schema = R.join('\n\n', [
  BookType,
  AuthorType,
  `type Query {
    books: [Book]
  }`  
])

We can now pass this schema string to Apollo Server to build our GraphQL API.

Evolving the Schema Need to add a new type? Just compose it separately like our existing types and add it to the schema composition.

Want to add a new field to Book? Simply add it to the R.of() call where we define the Book fields.

By using Ramda to compose our schema in this way, we’ve built a flexible foundation that makes schema changes painless. The schema can grow as our API evolves without duplication or tight coupling.

Functional programming gives us the ability to treat our schema as we would any other code - as small reusable composable parts that can change independently. This technique can streamline both early development and long term maintenance of a GraphQL API.

comments powered by Disqus
rss facebook X github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora