GraphQL Nexus

GraphQL Nexus

  • Docs
  • Playground
  • SDL Converter
  • Examples
  • GitHub

›Documentation

Documentation

  • Getting Started
  • Best Practices
  • Type Generation Details
  • Library Authors
  • Why Nexus?
  • Potential Future Features
  • Database Access w/ Prisma

API

  • API Core Concepts
  • objectType
  • unionType
  • scalarType
  • interfaceType
  • inputObjectType
  • enumType
  • args: arg / *Arg
  • makeSchema
  • extendType

GraphQL Nexus

Robust, composable type definition for GraphQL in TypeScript/JavaScript.

Note:

The documentation is very new and may contain some gaps, please help us fill them in by opening issues or better yet, pull-requests when you think something could be explained better. The examples are a great place to look to better understand how the library can be used.

GraphQL Nexus aims to combine the simplicity and ease of development of SDL development approaches like graphql-tools with the long-term maintainability of programmatic construction, as seen in graphene-python, graphql-ruby, or graphql-js.

Nexus builds upon the primitives of graphql-js, and attempts to take the simplicity of the SDL schema-first approach and pair it with the power of having the full language runtime ar your disposal.

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.

Check out the example projects to get some ideas of what this looks like in practice, or try it out in the playground to see what we mean!

Installation

GraphQL Nexus can be installed with either npm or yarn.

npm
yarn
npm install nexus
npm install graphql # required as a peer dependency
yarn add nexus
yarn add graphql # required as a peer dependency

Building an Example Schema

As documented in the API reference GraphQL Nexus provides a consistent, scalable approach to defining GraphQL types in code.

import {
  objectType,
  interfaceType,
  queryType,
  stringArg,
  intArg,
  fieldArg,
  makeSchema,
} from "nexus";

const Node = interfaceType({
  name: "Node",
  definition(t) {
    t.id("id", { description: "Unique identifier for the resource" });
    t.resolveType(() => null);
  },
});

const Account = objectType({
  name: "Account",
  definition(t) {
    t.implements(Node); // or t.implements("Node")
    t.string("username");
    t.string("email");
  },
});

const StatusEnum = enumType({
  name: "StatusEnum",
  members: ["ACTIVE", "DISABLED"],
});

const Query = queryType({
  definition(t) {
    t.field("account", {
      type: Account, // or "Account"
      args: {
        name: stringArg(),
        status: fieldArg({ type: "StatusEnum" }),
      },
    });
    t.list.field("accountsById", {
      type: Account, // or "Account"
      args: {
        ids: intArg({ list: true }),
      },
    });
  },
});

// Recursively traverses the value passed to types looking for
// any valid Nexus or graphql-js objects to add to the schema,
// so you can be pretty flexible with how you import types here.
const schema = makeSchema({
  types: [Account, Node, Query, StatusEnum],
  // or types: { Account, Node, Query }
  // or types: [Account, [Node], { Query }]
});

Nullability & Default Values

tl;dr - GraphQL Nexus assumes output fields are non-null by default

One benefit of GraphQL is the strict enforcement and guarentees of null values it provides in the type definitions. One opinion held by GraphQL is that fields should be considered nullable by default.

The GraphQL documentation provides this explanation:

... in a GraphQL type system, every field is nullable by default. This is because there are many things which can go awry in a networked service backed by databases and other services. A database could go down, an asynchronous action could fail, an exception could be thrown. Beyond simply system failures, authorization can often be granular, where individual fields within a request can have different authorization rules.

GraphQL Nexus breaks slightly from this convention, and instead assumes by all fields are "non-null" unless otherwise specified with a nullable option set to true. It also assumes all input types (fields/args) are nullable unless required is set to true.

The rationale being that for most applications, the case of returning null to mask errors and still properly handle this partial response is exceptional, and should be handled as such by manually defining these places where a schema could break in this regard.

If you find yourself wanting this the other way around, there is a nonNullDefaults option for the makeSchema which will make all fields nullable unless required: true (an alias for nullable: false) is specified during field definition.

This can also be configured on a per-type basis, using the nonNullDefaults option on the type definition object. This can be handy if you find yourself adding { nullable: true } to many fields of an output object type, or {required: true} to many arguments.

Resolving: Inline Function

One common idiom in GraphQL is exposing fields that mask or rename the property name on the backing object. GraphQL Nexus makes this simple by allowing a function as the second parameter to any built-in scalar resolver function.

const User = objectType({
  name: "User",
  definition(t) {
    t.id("id", (o) => o.user_id);
    t.string("name", (o) => o.user_name);
    t.string("description", (o) => o.user_description);
  },
});

Auto-Generated Artifacts

When you make a change to your GraphQL schema it is useful to see how exactly this changes the contract of the API, or the associated typings.

GraphQL Nexus takes care of this for you, simply provide a path to where you want these files to be output and it will auto-generate them when the server starts. By default, this only occurs when process.env.NODE_ENV !== "production".

const schema = makeSchema({
  types: [
    /* All schema types provided here */
  ],
  outputs: {
    schema: path.join(__dirname, "../../my-schema.graphql"),
    typegen: path.join(__dirname, "../../my-generated-types.d.ts"),
  },
});

Read more about how the automatic type generation works.

Although your .graphql file is generated, we recommend you check the file into source control. This gives you visibility into how changes in type construction affect the schema consumed by the end-user.

Type-Level defaultResolver

GraphQL Nexus allows you to define an override to the defaultResolver on a per-type basis, for advanced use-cases

Warning:

Specifying a defaultResolver for a type can have unintended consequences, and makes it harder to statically type. It is only recommended for advanced use-cases.

Testing Nexus

Nexus encourages separating your domain logic from the actual resolvers via context, so you should be able to test and reuse your application logic independent of GraphQL. See the use of the data-sources in the ghost example for a start on how you might structure your data layer.

Best Practices →
  • Installation
  • Building an Example Schema
  • Nullability & Default Values
  • Resolving: Inline Function
  • Auto-Generated Artifacts
  • Type-Level defaultResolver
  • Testing Nexus
GraphQL Nexus
Docs
Getting StartedAPI ReferencePlayground
More
GitHubStar
Copyright © 2019 Tim Griesser