GraphQL is really becoming a standard when dealing with APIs. It’s helping a lot of companies and developers to thrive and create better APIs, consequently creating better applications for their clients. A lot of companies, including GitHub, Shopify, Airbnb, PayPal, have adopted GraphQL.
There are a lot of points and concepts that make GraphQL an easy choice when starting to create a new API. The idea is to ask only for what you want and get exactly that. This doesn’t always happen with a REST API. Basically, in REST APIs, when we want to get data, we receive a whole object instead of a specific part of the data that we want. Imagine that we want to get only the name of a specific user, to do that we would normally hit an endpoint to get the user’s data. The problem is that, if we don’t create a specific endpoint just to retrieve the user’s name, we will receive the whole user object, containing more data than we want.
Building a scalable GraphQL API is not easy, and it takes a lot of time, effort, and study. We need to know exactly which approach is going to be used, which technology, and how to design the schema correctly.
Essentially, GraphQL has two main approaches that we can use to create our APIs, the code-first approach, and the SDL-first approach (also known as schema-first approach).
In this article, we are going to learn about how we can use GraphQL Nexus a code-first and strongly-typed GraphQL schema construction to create better, type-safe, and declarative GraphQL APIs.
To have a better understanding of GraphQL Nexus, we need to understand a little bit about how these two approaches work.
When GraphQL was released a few years ago, Facebook released a reference implementation for GraphQL APIs called graphql-js.
The graphql-js reference implementation uses the code-first approach, the GraphQL schema is created by using a plain JavaScript object:
import { GraphQLSchema, GraphQLObjectType, GraphQLString } from 'graphql'; const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'QueryType', fields: { helloWorld: { type: GraphQLString, resolve: () => 'Hello world!', }, }, }), })
With the code-first approach, we define our schema in the code. The code-first approach, in a large codebase, can be really useful and helpful to organize and move fast with your GraphQL schema.
Although the code-first approach is a really good way to build your GraphQL API, many developers think that the code-first approach can be verbose to write. For a few developers, the idea to create your GraphQL schema using code is not visually easy to understand while implementing the schema.
The SDL-first (also known as schema-first) approach is perfect for that. In the SDL-first approach, we define the GraphQL schema using SDL (Schema Definition Language):
type Query { helloWorld: String! }
The SDL is a well-defined way to build your schema, and it’s part of the official GraphQL specification. The schema-first approach makes it easier to understand and visualize in a clear way our GraphQL schema, making the process of creating the schema more intuitive.
One of the downsides is that we need to implement our resolvers separately from our GraphQL schema. Another downside that we can have with the SDL-first approach is that sometimes the usage of directives in the schema makes no sense.
Now that we know the differences between the code-first vs. SDL-first, we can learn more about GraphQL Nexus.
Created by Prisma, GraphQL Nexus is a declarative, code-first, and strongly typed GraphQL schema construction.
GraphQL Nexus is part of the Nexus framework, but it can be used on its own. To get started with it, all we have to do is install two dependencies:
yarn add @nexus/schema graphql
We need the graphql
dependency here because GraphQL Nexus requires it as a peer dependency.
GraphQL Nexus was designed to combine both the simplicity of the SDL-first approach and the long-term and organization of the code-first approach. It was built upon graphql-js
, so if you have used it before, you might notice some familiarity.
As the documentation says:
GraphQL Nexus was designed with TypeScript/JavaScript IntelliSense in mind, and combines TypeScript generics, conditional types, and type merging to provide full auto-generated type coverage out of the box.
After having installed GraphQL Nexus, to create your first schema all you have to do is import the makeSchema
from GraphQL Nexus:
import { makeSchema } from '@nexus/schema';
The makeSchema
function is used to define the GraphQL schema. You can combine GraphQL types defined with GraphQL Nexus or even pass types that you manually defined as types such as Scalar
, ObjectType
, Enum
, etc.
Using the makeSchema
function, is very similar to the graphql-js implementation. Create an object for your schema, and inside that object, you can pass two properties, types
and outputs
:
const schema = makeSchema({ types: [Query], outputs: { schema: __dirname + '/generated/schema.graphql', typegen: __dirname + '/generated/typings.ts', }, });
The types
property is where you can pass your GraphQL types. In the outputs
property, you can pass two properties called schema
and typegen
. GraphQL Nexus is going to generate a file called schema.graphql
for you with your entire GraphQL schema and a file called typing.ts
with all of our types.
Of course, you can pass more than two properties inside the makeSchema
function. GraphQL Nexus has a property called plugins
, where you can have an array of plugins to extend the functionality of your GraphQL:
const schema = makeSchema({ types: [Query, Mutation], outputs: { schema: __dirname + '/generated/schema.graphql', typegen: __dirname + '/generated/typings.ts', }, plugins: { fieldAuthorizePlugin({ ... }), nullabilityGuard({ ... }) } });
To create a query using GraphQL Nexus, first you need to import the QueryType
:
import { queryType, makeSchema } from '@nexus/schema';
After importing it you can create an object called Query
where all your queries will be. You need to use a function called definition
, and inside this function, you can use the t
argument to define the type of response of your queries:
const Query = queryType({ definition(t) { ... }, });
For example, let’s imagine that we wanted to create a query called user
. If we wanted to return a string
as an expected type of response of this query, we could do it like this:
const Query = queryType({ definition(t) { t.string('user', { resolve: (root, args, context) => 'Hello!', }); }, });
Notice that we used t.string
to specify the type of response of the query. There are a variety of types that you can use to specify the type of response such as boolean
, field
, float
, id
, int
, etc.
Creating a mutation using GraphQL Nexus is really similar to queries, first, you need to import the MutationType
:
const Mutation = mutationType({ definition(t) { t.string('createUser', { resolve: (root, args, context) => 'Hello!', }); }, });
One nice thing about GraphQL Nexus is that you can define arguments that can be used in any object or interface type:
import { stringArg } from '@nexus/schema'; const userArgs = { name: stringArg({ required: true, description: 'The name of the user to be created' }) };
There are a lot of different argument functions that you can use such as arg
, intArg
, stringArg
, floatArg
, idArg
, and booleanArg
.
The most important part of a GraphQL API is the object types. To create one using GraphQL Nexus, all you need to do is import the objectType
.
import { objectType } from '@nexus/schema';
Creating an object type is very similar to creating a query or mutation. You can pass a property called name
, to define the name of the type, and inside the definition
function you define the properties of the type:
import { objectType } from '@nexus/schema'; const User = objectType({ name: 'User', definition(t) { t.int('id'); t.string('title'); t.int('age'); } });
You can create other types such as Scalar
, ObjectType
, Enum
very easily, GraphQL Nexus has nice support to work with those types:
import { scalarType } from '@nexus/schema'; const DateScalar = scalarType({ name: 'DateScalar', description: 'Date custom scalar', ... });
Another useful type is the inputObjectType
. You can create an input object type that can be defined and passed as an input value, this is really helpful for mutations and queries when you have a complex input value:
import { inputObjectType } from '@nexus/schema'; const UserInputType = inputObjectType({ name: 'UserInputType', description: 'User input type', definition(t) { t.string('id', { required: true }); t.string('name'); t.int('age'); } });
Another really nice feature that GraphQL Nexus has is plugins. GraphQL Nexus has a plugin API that allows you to define your abstractions when building your GraphQL Schema.
GraphQL Nexus also has a lot of plugins out of the box, such as:
GraphQL Nexus has a few more plugins that can be very useful to work with, such as:
The code-first approach is, on some occasions, better than SDL-first. With GraphQL Nexus, we can benefit from this approach and create a more robust and well-defined GraphQL schema. Created upon the graphql-js
implementation, GraphQL Nexus is one of the best options available to create a really good, robust, maintainable, and concise GraphQL API.
In this article, we first learned about the two main approaches that we have in GraphQL, code-first, and SDL-first. We also took a look at GraphQL Nexus, how to create your first schema, and define your queries and mutations. GraphQL ships with a lot of features such as plugins, which we can use to define our own abstractions and helps us to improve our GraphQL API.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on problematic GraphQL requests to quickly understand the root cause. In addition, you can track Apollo client state and inspect GraphQL queries' key-value pairs.
LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
3 Replies to "How GraphQL Nexus can help you create better APIs"
Hello,
May I ask how Nexus resolve N+1 queries problem?
Thank you
Hi Houssem,
To solve N+1 queries with GraphQL it’s recommended to use Dataloader.
https://github.com/graphql/dataloader
Hi,
How to combine two different queryType into one?