Introducing Grial

Creating a GraphQL API with Node.js easily

A Node.js framework for creating GraphQL API servers easily and without a lot of boilerplate.

The core server code of any GraphQL API it’s always basically the same, create the HTTP server, get your resolvers and schema, set the /graphql endpoint, in development set the endpoint for GraphiQL and if you are going to use subscriptions also create a subscription server and attach it to your HTTP server.

That’s a lot of boilerplate code! And Grial will handle all of that for you and let you only think about your application business logic and API layer. How? Grial it’s a serie of many little libraries, the core are @grial/cli and @grial/server which would create your API server and run it with a single command.

Grial also have many connectors little libraries that allow you to easily connect your API to different data sources and enable the creation of a big API that consumes data from Redis, MongoDB, Rest APIs, file disk, etc.

Let’s code an API!

Time to code, we’ll create a directory for the API and install this modules.

yarn add @grial/cli @grial/server @grial/connector-faker

The last one it’s a connector for the faker module and we are going to use it to fake our API data. Then we are going to add the following script to our package.json file.

{
"scripts": {
"start": "grial start"
}
}

That script will use @grial/cli to run our @grial/server, it’ll also try to read our environment variables from a .env file, we can then create one with this basic variables.

PORT=8000

By default it will set PORT=3000, every Grial module have the required and possible environment variables in the readme.

Define the schema

After that we are ready to write our API code, let’s define our schema, Grial let us write it inside a schema.gql or a schema.graphql file, so we’re going to define something like this in one of them.

type User {
id: Int!
username: String!
firstName: String!
lastName: String!
fullName: String!
bio: String!
}
type Query {
me: User!
}
schema {
query: Query
}

Write the resolvers

Now we need to create a resolvers.js files. Along with the schema these are the only required files.

// main resolvers
exports.Query = {
me(rootQuery, args, context) {
return context.models.User.me();
}
};
// type resolvers
exports.User = {
fullName(user) {
return `${user.firstName} ${user.lastName}`;
}
};

We exported many keys but we could also use module.exports and just export a single object with the keys Query and User.

My own personal recommendation is to use many exports, also as your resolvers grow create a resolvers directory with a file Query.js, Mutation.js, Subscription.js and one file for each type we need a custom resolver.

Create the models

As we saw we received the model User from our context object, Grial automatically will read our models.js file and instantiate each one. We will create this file now.

exports.User = async function User({ faker }) {
return {
me() {
return {
id: faker.random.number(),
username: faker.internet.userName(),
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
bio: faker.name.title()
};
}
};
};

That’s our User model, again we used a name export but we could have done a single export with an object. If you check we are creating an async function for our model, that’s because we could require to run asynchronous code before creating our resolvers (maybe to synchronize the model with a database).

Import the connectors

We also received faker in our model, that’s our connector, each model receive a single parameter with each environment variable and connector that of course allow a single model to get data using multiple connectors.

So, we receive the connector, but how Grial knows that? Simple, just create a connectors.js object and export each connector you want to use.

exports.faker = require('@grial/connector-faker');

Those are our API connectors, we can use this file to also define custom connectors, maybe using third-party APIs clients. Every connector will receive every environment variable and it’s going to use some of them, the Faker connector use FAKER_LOCALE and FAKER_SEED and have default values.

If you want to use the same connector multiple times you can wrap them with a high order function which receive the environment variables and pass new ones.

exports.faker = env => require('@grial/connector-faker')({
FAKER_LOCALE: env.DATA_LOCALE,
FAKER_SEED: env.DATA_SEED
})

Running the app

With that done we have our API code ready, just run yarn start or npm start and you will see something like this in your terminal.

$ grial start
Grial server running
> GraphiQL Endpoint = http://localhost:3000/ide
> API Endpoint = http://localhost:3000/graphql
> Subscriptions Endpoint = http://localhost:3000/subscriptions

We can then access to http://localhost:3000/ide and try the API. As you can see Grial also set you a subscriptions endpoint by default, if you create a PubSub instance and add subscriptions to your schema and resolvers you can start using them without worries.

You can also try this application running in production accessing to https://grial-example-basic.now.sh/ide and another API built with Grial fetching data from a Rest API https://grial-example-rest-wrapper.now.sh/ide

The second example wrap the JSONPlaceholder API into a GraphQL one and add tests for the models and resolvers.

Final word

Grial allow to customize its behavior using a grial.config.js file with the keys graphqlConfig, graphiqlConfig and subscriptionConfig, they let you customize GraphQL, GraphiQL and the subscription server configurations, useful to include some token based authentication and other features.

It’s also pluggable, you can use the programmatically API to integrate it inside any HTTP server or application, it can be Next.js, Express.js, etc.

You can contribute to Grial and help create an awesome GraphQL framework with more connectors, features, tools, examples and a completed docs.