nexus是一个令人愉快的GraphQL应用程序框架,是Node.js代码优先的GraphQL框架。文档:https://www.nexusjs.org (这个文档还在建设中,其中有些错误的地方)。
Nexus有一个官方的Prisma插件,可帮助您将GraphQL API连接到数据库。具体prisma的知识见这篇文章:prisma2.0和nexus搭建graphql后端(1)—prisma2.0
Nexus开箱即用,带有CLI。安装命令如下:
yarn global add nexus
这只是您现在需要了解的3个CLI命令:
nexus dev:此命令以监视模式启动开发服务器。每次更改文件时,您的应用都会重新启动。
nexus build:此命令将构建一个“生产就绪”服务器,准备进行部署。
nexus create: 它将为您搭建一个新的Nexus项目。这就是通常应启动Nexus项目的方式。
mkdir nexus-tutorial && cd nexus-tutorial
yarn init
yarn add nexus
"scripts": {
"dev": "nexus dev",
"build": "nexus build"
}
还可以用 nexus create 命令一键帮你把框架搭建好,它会提示你选择yarn还是npm ,同时会提示你是否要使用prisma,然后选择数据种类。按照提示走,会帮你搭建好最初的框架。同时里面还有些示例代码。
过程如下:
生成的目录结构如下:
然后yarn dev 最后访问 http://localhost:4000
Nexus有一个非常规的概念,叫做“反射”。它指的是这样一个事实,即当nexus dev或nexus build运行时,不仅会运行您的应用程序代码,而且还在收集信息并且在派生工件。反射用途包括:
object Types对象类型:在许多情况下,您不想从API返回数字或字符串。您要返回一个具有其自身复杂行为的对象。 就是这里的 object Types。
mkdir api/graphql && touch api/graphql/Post.ts
Post.ts 的内容如下
import { schema } from 'nexus'
schema.objectType({
name: 'Post', // <- Name of your type
definition(t) {
t.int('id') // <- Field named `id` of type `Int`
t.string('title') // <- Field named `title` of type `String`
t.string('body') // <- Field named `body` of type `String`
t.boolean('published') // <- Field named `published` of type `Boolean`
},
})
GraphQL上下文是在所有解析器之间共享的普通JavaScript对象。
// touch api/db.ts
// api/db.ts
export const db = {
posts: [{ id: 1, title: 'Nexus', body: '...', published: false }],
}
// api/app.ts
import { schema } from 'nexus'
import { db } from './db'
schema.addToContext(() => {
return {
db,
}
})
// api/graphql/Post.ts
// ...
schema.extendType({
type: 'Query',
definition(t) {
t.field('drafts', { // 第一个参数指定字段的名称3
type: 'Post', // 指定字段的类型应该是
list: true, // 返回数组
resolve(_root, _args, ctx) { // 上下文是第三个参数,通常标识为ctx
return ctx.db.posts.filter(p => p.published === false)
},
})
},
})
// api/graphql/Post.ts
schema.extendType({
type: 'Mutation',
definition(t) {
t.field('createDraft', {
type: 'Post',
args: { // 将args属性添加到字段定义以定义其args。键是arg名称,值是类型规范。
title: schema.stringArg({ required: true }), // 使用Nexus辅助函数定义arg类型。例如schema.intArg和schema.booleanArg。
body: schema.stringArg({ required: true }), // 如果要引用类似某些InputObject的类型,请使用schema.arg({type:“ ...”})。
},
resolve(_root, args, ctx) {
const draft = {
id: ctx.db.posts.length + 1,
title: args.title, // 在我们的解析器中,访问我们在上面指定的args并将它们传递给我们的自定义逻辑。
body: args.body,
published: false,
}
ctx.db.posts.push(draft)
return draft
ctx.db.posts.push(/*...*/)
return // ...
},
})
},
})
yarn add prisma nexus-plugin-prisma
// api/app.ts
import { use } from 'nexus'
import { prisma } from 'nexus-plugin-prisma'
use(prisma())
mkdir prisma
touch prisma/schema.prisma
touch prisma/.env
// prisma/schema.prisma
datasource postgres {
provider = "postgresql"
url = env("DATABASE_URL")
}
# prisma/.env
DATABASE_URL="" // 这里是数据库地址
import { use } from 'nexus'
import { prisma } from 'nexus-plugin-prisma'
use(prisma())
prisma generate 生成prisma client
import {schema} from "nexus"
schema.objectType({
name: "Post",
definition(t) {
t.id("id")
t.string("title")
t.string("body")
t.boolean("publish")
}
})
import { schema } from 'nexus';
import { PostWhereInput } from '.prisma/client';
schema.extendType({
type: 'Query',
definition(t) {
t.list.field('posts', {
args: {
isPublished: schema.booleanArg({ required: false }),
title: schema.stringArg({ required: false, default: '' }),
body: schema.stringArg({ required: false, description: '' })
},
type: 'Post',
resolve(_root, args, ctx) {
let { isPublished, title, body } = args;
let whereObj: PostWhereInput = {
title: {
contains: title
},
body: {
contains: body
}
};
if (isPublished !== undefined) {
whereObj.published = isPublished;
}
return ctx.db.post.findMany({
where: whereObj
});
}
});
}
});
(2) 分页
import { schema } from 'nexus';
import { PostWhereInput } from '.prisma/client';
schema.extendType({
type: 'Query',
definition(t) {
t.field('postsWithPageInfo', {
type: 'PostWithPageInfo',
args: {
pn: schema.intArg({ required: true }),
ps: schema.intArg({ required: true }),
isPublished: schema.booleanArg({ required: false }),
title: schema.stringArg({ required: false, default: '' }),
body: schema.stringArg({ required: false, description: '' })
},
resolve: async (_root, args, ctx) => {
let { isPublished, title, body, pn, ps } = args;
let whereObj: PostWhereInput = {
title: {
contains: title
},
body: {
contains: body
}
};
if (isPublished !== undefined) {
whereObj.published = isPublished;
}
const data = await ctx.db.post.findMany({
where: whereObj,
skip: ps * (pn - 1),
first: ps
});
const total = await ctx.db.post.count({ where: whereObj });
return {
data,
pageInfo: { pn, ps, total }
};
}
});
}
});
import { schema } from 'nexus';
schema.extendType({
type: 'Mutation',
definition(t) {
t.field('createPost', {
type: 'Post',
args: {
isPublished: schema.booleanArg({ required: false, default: false }),
title: schema.stringArg({ required: true }),
body: schema.stringArg({ required: true })
},
resolve(_root, args, ctx) {
let { isPublished, title, body } = args;
return ctx.db.post.create({ data: { published: isPublished as boolean, title, body } });
}
});
}
});
(2) delete
import { schema } from 'nexus';
schema.extendType({
type: 'Mutation',
definition(t) {
t.field('deletePosts', {
type: 'BatchPayload',
args: {
ids: schema.intArg({ required: true, list: true })
},
resolve: async (_root, args, ctx) => {
const { ids } = args;
return ctx.db.post.deleteMany({ where: { id: { in: ids } } });
}
});
}
});
(3) update
import { schema } from 'nexus';
import { PostUpdateInput } from '.prisma/client';
schema.extendType({
type: 'Mutation',
definition(t) {
t.field('updatePost', {
type: 'Post',
args: {
id: schema.intArg({ required: true }),
title: schema.stringArg({ required: false }),
body: schema.stringArg({ required: false }),
published: schema.booleanArg({ required: false })
},
resolve: async (_root, args, ctx) => {
const { id, title, body, published } = args;
const post = await ctx.db.post.findOne({ where: { id } });
if (!post) {
throw new Error(`id为${id}的文章不存在`);
}
const data: PostUpdateInput = {};
if (title !== undefined) {
data.title = title;
}
if (body !== undefined) {
data.body = body;
}
if (published !== undefined) {
data.published = published;
}
return ctx.db.post.update({ data, where: { id } });
}
});
}
});