apollo prisma nexus QuickStart

QuickStart

リンク

構成

  • 構成
    • HTTPサーバー: apollo-server
    • Graphqlスキーマ: prisma
    • apolloとprismaの接続: nexus
  • その他
    • nexus自体にもHTTPサーバーの機能はある。
    • ApolloServerにわたすスキーマ情報のコーディングに必要な型データの src/generated/nexus.ts は、ビルド時に自動生成される

セットアップ

curl https://www.gitignore.io/api/osx,node,intellij+iml,visualstudiocode -o .gitignore
// tsconfig.json

$ cat << EOF > tsconfig.json
{
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src",
    "lib": ["esnext"],
    "esModuleInterop": true,
    "strict": true
  },
  "include": ["src/**/*"]
}
EOF
$ yarn init -y
$ yarn add typescript ts-node ts-node-dev @types/node --dev
$ yarn add @prisma/client nexus-prisma @nexus/schema apollo-server graphql
$ yarn add @prisma/cli --dev
$ yarn run prisma init
// prisma/schema.prisma

$ cat << EOF > prisma/schema.prisma
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}
EOF
// prisma/.env

$ cat << EOF > prisma/.env
DATABASE_URL="mysql://root@localhost:3306/my_prisma"
EOF
$ yarn run prisma introspect
$ yarn run prisma generate
$ mkdir src
// src/context.ts

$ cat << EOF > src/context.ts
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

export interface Context {
  prisma: PrismaClient
}

export function createContext(): Context {
  return { prisma }
}

EOF
// src/schema.ts

$ cat << EOF > src/schema.ts
import { nexusPrismaPlugin } from 'nexus-prisma'
import { intArg, makeSchema, objectType, stringArg } from '@nexus/schema'

const User = objectType({
  name: 'User',
  definition(t) {
    t.model.id()
    t.model.name()
    t.model.email()
    t.model.posts({
      pagination: false,
    })
  },
})

const Post = objectType({
  name: 'Post',
  definition(t) {
    t.model.id()
    t.model.title()
    t.model.content()
    t.model.published()
    t.model.author()
    t.model.authorId()
  },
})

const Query = objectType({
  name: 'Query',
  definition(t) {
    t.crud.post()

    t.list.field('feed', {
      type: 'Post',
      resolve: (_, args, ctx) => {
        return ctx.prisma.post.findMany({
          where: { published: true },
        })
      },
    })

    t.list.field('filterPosts', {
      type: 'Post',
      args: {
        searchString: stringArg({ nullable: true }),
      },
      resolve: (_, { searchString }, ctx) => {
        return ctx.prisma.post.findMany({
          where: {
            OR: [
              { title: { contains: searchString } },
              { content: { contains: searchString } },
            ],
          },
        })
      },
    })
  },
})

const Mutation = objectType({
  name: 'Mutation',
  definition(t) {
    t.crud.createOneUser({ alias: 'signupUser' })
    t.crud.deleteOnePost()

    t.field('createDraft', {
      type: 'Post',
      args: {
        title: stringArg({ nullable: false }),
        content: stringArg(),
        authorEmail: stringArg(),
      },
      resolve: (_, { title, content, authorEmail }, ctx) => {
        return ctx.prisma.post.create({
          data: {
            title,
            content,
            published: false,
            author: {
              connect: { email: authorEmail },
            },
          },
        })
      },
    })

    t.field('publish', {
      type: 'Post',
      nullable: true,
      args: {
        id: intArg(),
      },
      resolve: (_, { id }, ctx) => {
        return ctx.prisma.post.update({
          where: { id: Number(id) },
          data: { published: true },
        })
      },
    })
  },
})

export const schema = makeSchema({
  types: [Query, Mutation, Post, User],
  plugins: [nexusPrismaPlugin()],
  outputs: {
    schema: __dirname + '/../schema.graphql',
    typegen: __dirname + '/generated/nexus.ts',
  },
  typegenAutoConfig: {
    contextType: 'Context.Context',
    sources: [
      {
        source: '@prisma/client',
        alias: 'prisma',
      },
      {
        source: require.resolve('./context'),
        alias: 'Context',
      },
    ],
  },
})

EOF
// src/server.ts
$ cat << \EOF > src/server.ts
import { ApolloServer } from 'apollo-server'
import { schema } from './schema'
import { createContext } from './context'

new ApolloServer({ schema, context: createContext }).listen(
  { port: 4000 },
  () =>
    console.log(
      `🚀 Server ready at: http://localhost:4000\n⭐️ See sample queries: http://pris.ly/e/ts/graphql-apollo-server#using-the-graphql-api`,
    ),
)

EOF
$ yarn ts-node-dev --no-notify --respawn --transpileOnly src/server

その他

  • DBから yarn run prisma introspect する場合、 schemaのPostとなっているリレーション名をpostsなどに修正するのは手動

  • exampleにあるpackage.jsonのscriptsは以下

  "scripts": {
    "start": "node dist/server",
    "clean": "rm -rf dist",
    "build": "npm -s run clean && npm -s run generate && tsc",
    "generate": "npm -s run generate:prisma && npm -s run generate:nexus",
    "generate:prisma": "prisma generate",
    "generate:nexus": "ts-node --transpile-only src/schema",
    "postinstall": "npm -s run generate",
    "dev": "ts-node-dev --no-notify --respawn --transpileOnly src/server"
  }