The apollo-server-koa plugin in egg.
With yarn:
yarn add egg-apollo-server
or using npm
npm install --save egg-apollo-server
- 开启插件
// config/plugin.js
exports.graphql = {
enable: true,
package: 'egg-apollo-server'
};
- 在 config/config.${env}.js 配置 graphql options。支持 apollo-server 中的所有 options.
config.graphql = {
router: '/graphql',
app: true, //是否加载到 app 上,默认为 true
agent: false, //是否加载到 agent 上,默认为 false
graphiql: true, //是否加载开发者工具 playground,默认为 true
uploads: true, //是否开启文件上传功能,默认开启
//是否添加默认的type Query,Mutation,默认为true
//如果为true须使用extend type Query|extend type Mutation,因为graphql规定同一个type只能定义一个
//带来的好处时egg/graphql下不用再新建query,mutation目录
defaultEmptySchema: true,
//subscriptions的值为<Object>|<String>|false 见https://www.apollographql.com/docs/apollo-server/api/apollo-server/
//如果为String 表示订阅的路径
//如果为false 关闭订阅
//如果为object 可以添加path,keepAlive,onConnect,onDisconnect
subscriptions: {
onConnect: (connectionParams, webSocket) => {
console.log('connect');
if (connectionParams.authToken) {
// return validateToken(connectionParams.authToken)
// .then(findUser(connectionParams.authToken))
// .then(user => {
// return {
// currentUser: user,
// }
// })
}
// throw new Error('Missing auth token!')
}
},
//可选字段,接受项目中发生的错误,然后自定义错误返回给前端
formatError: (error, app) => {
// console.log(error);
app.logger.error(error);
return error;
},
debug: false // 发生错误时,是否包含错误堆栈信息,生产环境要设置为false
};
// 添加中间件拦截请求
exports.middleware = ['graphql'];
- 项目目录
在 app 目录下新建 graphql 目录, graphql 相关文件写在此目录,插件会读取 app/graphql 下所有目录里面的 graphql 相关文件
├── app
│ ├── controller
│ │ └── home.js
│ ├── graphql
│ │ ├── tag
│ │ │ ├── resolver.js
│ │ │ └── schema.graphql
│ │ └── user
│ │ ├── resolver.js
│ │ └── schema.graphql
│ ├── router.js
│ └── service
├── config
│ ├── config.default.js
│ └── plugin.js
├── package.json
└── package-lock.json
graphql 相关文件包含:
- schema.graphql
a GraphQL type language string
#插件设置了默认的Query,Mutation 所以不用定义Query,直接使用extend继承
extend type Query {
users: [User]
user(id: ID!): User
}
type User {
id: ID!
name: String
age: Int
}
extend type Mutation {
addUser(input: AddUser): User
updateUser(input: UpdateUser): User
deleteUser(id: ID!): Boolean
}
input AddUser {
name: String
age: Int
}
input UpdateUser {
id: ID!
name: String
age: Int
}
- resolver.js
a nested object that maps type and field names to resolver functions
module.exports = {
Query: {
users: () => {
return users;
},
user: (root, params) => {
const { id } = params;
return users.find(user => user.id == id);
}
}
};
- schemaDirective.js
a nested object that maps type and field names to resolver functions
const { defaultFieldResolver } = require('graphql');
const { SchemaDirectiveVisitor } = require('graphql-tools');
class UpperDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
const { resolve = defaultFieldResolver } = field;
field.resolve = async (...args) => {
const defaultText = await resolve.apply(this, args);
if (typeof defaultText === 'string') {
return defaultText.toUpperCase();
}
return defaultText;
};
}
}
module.exports = {
upper: UpperDirective
};
- router - 处理 graphql 请求的路由,默认为 "/graphql"
- app - 是否加载到 app 上,默认为 true
- agent - 是否加载到 agent 上,默认为 false
- graphiql - 是否加载开发者工具 playground,默认为 true
- uploads - 是否开启文件上传功能,默认为 true
其它 options 参 见apollo-server
- 不支持 onPreGraphQL,onPreGraphiQL
- 不支持 directiveResolvers,用 schemaDirective 替代
- 支持文件上传.
- 更漂亮的调试界面.
- 支持自定义错误类型
- 支持 dataSources
- 支持缓存(redis 等)
- 支持 Subscriptions
- 支持 mock
- 支持默认的 Query
未设置默认 Query 之前,假如有 user,tag 两个表,需要建四个文件夹,这样导致 mutation,query 包含了所有的一级查询,增加,更新,删除 而 user 相关定义又在 user/graphql 下
app
└── graphql
├── mutation
│ └── schema.graphql
├── query
│ └── schema.graphql
├── tag
│ ├── resolver.js
│ └── schema.graphql
└── user
├── resolver.js
└── schema.graphql
有了默认 Query 后,只需要建两个文件夹
app
└── graphql
├── tag
│ ├── resolver.js
│ └── schema.graphql
└── user
├── resolver.js
└── schema.graphql
只需要在各自 schema.graphql 定义 例如 egg 中使用 graphql
#app/graphql/user/schema.graphql
extend type Query {
user(id: ID!): User
}
extend type Mutation {
addUser(input: AddUser): User
}
input AddUser {
name: String
age: Int
}
type User {
id: ID!
name: String
age: Int
}
- 支持自定义 schema,可自定义 graphql 相关文件结构
- 支持 typeDefs 里引用 model 数据