GraphQL Nexus简介:代码优先的GraphQL服务器开发

GraphQL Nexus简介:代码优先的GraphQL服务器开发

翻译:hanagm

原文链接

上一篇文章中,我们概述了SDL-first GraphQL服务器开发的问题。本周,我们很高兴地宣布GraphQL Nexus,这是一个代码优先的GraphQL库。Tim Griesser的文章。

img

本文是由三部分组成的系列文章的第二部分:

Twitter上关注我们,以便在即将发布的文章时收到通知。


如前一篇文章所述,SDL-first GraphQL服务器开发存在许多挑战,例如保持SDL和解析器同步模块化GraphQL架构以及实现出色的IDE支持。大多数问题可以解决,但这只会以学习,使用和集成无数其他工具为代价。

今天我们介绍一个库,它实现了GraphQL服务器开发的代码优先方法:GraphQL Nexus


在上一篇文章中,我们对比了对schema-firstSDL-firstcode-first 方法的理解,用于构建GraphQL服务器:

  • schema-first:前端架构设计是开发过程的关键部分
  • SDL-first:GraphQL架构的SDL版本是API 的真实来源
  • *code-first:GraphQL架构以编程方式构建

作为代码优先框架,GraphQL Nexus仍可用于schema优先开发。架构优先和代码优先不是对立的方法:它们在组合时变得更有用。

使用Nexus,GraphQL架构以编程方式定义和实现。因此,它遵循GraphQL服务器在其他语言中的成熟方法,例如sangria-graphql(Scala)graphlq-rubygraphene(Python)。

GraphQL Nexus在设计时考虑了TypeScript / JavaScript intellisense。它结合了TypeScript泛型,条件类型和类型合并,以提供完全自动生成的类型覆盖。Nexus的核心设计目标是使用尽可能少的手动类型注释来获得最佳类型覆盖。

img

Nexus基于其原语graphql-js,使其与当前的GraphQL生态系统基本兼容。

Nexus的API公开了许多函数,允许您为GraphQL架构定义和实现构建块,例如对象类型联合接口枚举以及您在GraphQL类型系统中找到的所有其他内容:

Object Types

const User = objectType({
  name: 'User',
  definition(t) {
    t.int('id', { description: 'Id of the user' })
    t.string('fullName', { description: 'Full name of the user' })
    t.list.field('posts', {
      type: Post, // or "Post"
      resolve(root, args, ctx) {
        return ctx.getUser(root.id).posts()
      },
    })
  },
})

const Post = objectType({
  name: 'Post',
  definition(t) {
    t.int('id')
    t.string('title')
  },
})

Unions

const MediaType = unionType({
  name: 'MediaType',
  description: 'Any container type that can be rendered into the feed',
  definition(t) {
    t.members('Post', 'Image', 'Card')
    t.resolveType(item => item.name)
  },
})

Interfaces

const Node = interfaceType({
  name: 'Node',
  definition(t) {
    t.id('id', { description: 'GUID for a resource' })
  },
})

const User = objectType({
  name: 'User',
  definition(t) {
    t.implements('Node')
  },
})

Input Types

const InputType = inputObjectType({
  name: 'InputType',
  definition(t) {
    t.string('key', { required: true })
    t.int('answer')
  },
})

Enums

// Definining as an array of enum values:
const Episode = enumType({
  name: 'Episode',
  members: ['NEWHOPE', 'EMPIRE', 'JEDI'],
  description: 'The first Star Wars episodes released',
})

// As an object, with a simple mapping of enum values to internal values:
const Episode = enumType({
  name: 'Episode',
  members: {
    NEWHOPE: 4,
    EMPIRE: 5,
    JEDI: 6,
  },
})

Scalars

const DateScalar = scalarType({
  name: "Date",
  asNexusMethod: "date"
  description: "Date custom scalar type",
  parseValue(value) {
    return new Date(value)
  },
  serialize(value) {
    return value.getTime()
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.INT) {
      return new Date(ast.value)
    }
    return null
  },
})

QueryMutation类型是所谓的root schema。Nexus提供了一个API来定义:

Query

const Query = queryType({
  definition(t) {
    t.field('user', {
      type: User,
      nullable: true,
      args: { id: idArg({ nullable: false }) },
      resolve: (parent, { id }) => fetchUserById(id),
    })
  },
})

Mutation

const Mutation = mutationType({
  definition(t) {
    t.field('createUser', {
      type: User,
      args: { name: stringArg() },
      resolve: (parent, { name }) => createUser(name),
    })
  },
})

一旦为GraphQL架构定义了所有类型,就可以使用该makeSchema函数创建一个GraphQLSchema将成为GraphQL服务器基础的实例(例如graphql-yogaapollo-server):

const schema = makeSchema({
  // The programmatically defined building blocks of your GraphQL schema
  types: [User, Query, Mutation],

  // Specify where the generated TS typings and SDL should be located
  outputs: {
    typegen: __dirname + '/generated/typings.ts',
    schema: __dirname + '/generated/schema.graphql',
  },

  // All input arguments and return types are non-null by default
  nonNullDefaults: {
    input: true,
    output: true,
  },
})

// ... feed the `schema` into your GraphQL server (e.g. apollo-server or graphql-yoga)

makeSchema还可以提供prettier的配置,以便生成的代码符合您的风格指南💅

开始使用Nexus的最快方法是探索官方示例或使用在线Playground

由于GraphQL Nexus严重依赖graphql-js,因此需要作为安装的对等依赖项

npm

npm install --save nexus graphql

yarn

yarn add nexus graphql

文档中的最佳实践部分包含许多有关理想编辑器设置的说明以及构建Nexus项目的提示。

当graphql nexus动态生成类型时,开发人员最好的体验是通过在后台运行的开发服务器来实现的。无论何时保存文件,它都会更新生成的类型。

为TypeScript配置开发服务器

使用TypeScript时,一种可能的设置是ts-node-dev用于开发服务器:

npm

npm install -D ts-node-dev

yarn

yarn add -D ts-node-dev

然后,您可以在以下位置配置用于开发的npm脚本package.json

{
  // ...
  "scripts": {
    "start": "...",
    "dev": "ts-node-dev --no-notify --transpileOnly --respawn ./src"
  }
}

为JavaScript配置开发服务器

使用JavaScript时,您可以使用nodemon

npm

npm install -D nodemon

yarn

yarn add -D nodemon

然后,您可以在以下位置配置用于开发的npm脚本package.json

{
  // ...
  "scripts": {
    "start": "...",
    "dev": "nodemon ./src/index.js"
  }
}

完成编辑器设置后,就可以开始构建graphql模式了。下面是一个“Hello World”应用程序与graphql-yoga的代码片段:

import { queryType, stringArg, makeSchema } from 'nexus'
import { GraphQLServer } from 'graphql-yoga'

const Query = queryType({
  definition(t) {
    t.string('hello', {
      args: { name: stringArg({ nullable: true }) },
      resolve: (parent, { name }) => `Hello ${name || 'World'}!`,
    })
  },
})

const schema = makeSchema({
  types: [Query],
  outputs: {
    schema: __dirname + '/generated/schema.graphql',
    typegen: __dirname + '/generated/typings.ts',
  },
})

const server = new GraphQLServer({
  schema,
})

server.start(() => `Server is running on http://localhost:4000`)

SDL转换器可让您提供的SDL模式定义,并输出相应的Nexus代码(没有任何 resolvers):

img

Nexus API的设计特别注重开发人员的体验。一些核心设计目标是:

  • 类型安全

  • 可读性

  • 开发人员效率

  • Prettier轻松集成

在构建API时运行的开发服务器可确保您始终对刚刚引入的架构更改进行自动完成和错误检查。

借助GraphQL Playground中的新架构轮询功能,您可以在调整架构时立即重新加载GraphQL API。

我们对GraphQL Nexus非常兴奋,并希望你也会如此。您可以通过浏览官方示例或按照文档中的“入门”指示随意试用Nexus 。

如果您遇到任何问题,请打开GitHub或在我们的Slack中联系

返回