egg graphql plugin
npm install @switchdog/egg-graphql[npm-image]: https://img.shields.io/npm/v/@switchdog/egg-graphql.svg?style=flat-square
[npm-url]: https://npmjs.org/package/@switchdog/egg-graphql
[download-image]: https://img.shields.io/npm/dm/@switchdog/egg-graphql.svg?style=flat-square
[download-url]: https://npmjs.org/package/@switchdog/egg-graphql
新的 v3.2 版本使用 apollo-server-koa 重写了中间件的实现方式,使用 GraphQL Playground 作为开发工具,可以在 eggjs 中更愉快的使用 apollo-server-koa:
``js
// app/middleware/graphql.js
const { ApolloServer } = require('apollo-server-koa');
const { get } = require('lodash');
const compose = require('koa-compose');
module.exports = (_, app) => {
const options = app.config.graphql;
const graphQLRouter = options.router || '/graphql';
// get apollo server options
const { getApolloServerOptions } = options;
const apolloServerOptions = Object.assign(
{
// log the error stack by default
formatError: error => {
const stacktrace = (get(error, 'extensions.exception.stacktrace') || []).join('\n');
app.logger.error('egg-graphql', stacktrace);
return error;
},
},
options.apolloServerOptions,
// pass app to getApolloServerOptions
getApolloServerOptions && getApolloServerOptions(app),
// pass schema and context to apollo server
{
schema: app.schema,
context: ({ ctx, connection }) => {
if (connection) {
return connection.context;
}
return ctx;
},
}
);
const onPreMiddleware = async (ctx, next) => {
const { onPreGraphQL, onPrePlayground } = options;
const { playground } = apolloServerOptions;
if (ctx.path === graphQLRouter) {
if (ctx.request.accepts([ 'json', 'html' ]) === 'html') {
playground && onPrePlayground && await onPrePlayground(ctx);
} else {
onPreGraphQL && await onPreGraphQL(ctx);
}
}
await next();
};
const middlewares = [ onPreMiddleware ];
// init apollo server
const apolloServer = new ApolloServer(apolloServerOptions);
apolloServer.applyMiddleware({
app: {
use: middleware => middlewares.push(middleware), // collecting middlewares
},
path: graphQLRouter,
});
// add Subscription support
if (apolloServerOptions.subscriptions) {
app.once('server', server => {
// websocket
apolloServer.installSubscriptionHandlers(server);
});
}
return compose(middlewares);
};
`
* 基于 apollo-server,具有 apollo-server 的所有优势
* 使用 Apollo Playground 作为调试界面,体验更佳
* 完全兼容 egg-graphql,支持 onPreGraphQL(ctx) 和 onPrePlayground(ctx) (onPrePlayground 替代原来的 onPreGraphiQL)apolloServerOptions.formatError
* 默认打印错误日志,方便定位问题,可通过 覆盖默认逻辑getApolloServerOptions(app)
* 可以以函数的方式传递 apollo-server 配置:,且能在函数中拿到 eggjs 的 app 实例Query
* 支持 Directive 以及 SchemaDirective
* 支持 Subscriptions by@Abenx
* 支持默认 等的定义,方便组织代码目录,可通过 extend 的方式将 Query、Mutation 以及 Subscription 等定义到各自的文件夹中。默认关闭,可以通过设置 defaultTypeDefsEnabled 为 true 开启
安装对应的依赖 [egg-graphql] :
`bash`
$ yarn add @switchdog/egg-graphql@latestor
$ npm i @switchdog/egg-graphql@latest
开启插件:
`js`
// config/plugin.js
exports.graphql = {
enable: true,
package: '@switchdog/egg-graphql',
};
// 添加中间件拦截请求
exports.middleware = [ 'graphql' ];
在 config/config.${env}.js 配置提供 graphql 的路由。
`jsQuery
// config/config.${env}.js
exports.graphql = {
router: '/graphql',
// 是否加载到 app 上,默认开启
app: true,
// 是否加载到 agent 上,默认关闭
agent: false,
// 是否添加默认的 、Mutation 以及 Subscription 定义,默认关闭extend
// 开启后可通过 的方式将 Query、Mutation 以及 Subscription 定义到各自的文件夹中schema
defaultTypeDefsEnabled: false,
// graphQL 路由前的拦截器
onPreGraphQL: function* (ctx) {},
// 开发工具 apollo playground 路由前的拦截器,建议用于做权限操作(如只提供开发者使用)
onPrePlayground: function* (ctx) {},
// apollo server 的配置,除 context 外均可配置app
// 详见 https://www.apollographql.com/docs/apollo-server/api/apollo-server
apolloServerOptions: {
rootValue, // the value passed to the first resolve function
formatError, // a function to apply to every error before sending the response to clients
validationRules, // additional GraphQL validation rules to be applied to client-specified queries
formatParams, // a function applied for each query in a batch to format parameters before execution
formatResponse, // a function applied to each response after execution
tracing, // when set to true, collect and expose trace data in the Apollo Tracing format
logFunction, // a function called for logging events such as execution times
fieldResolver, // a custom default field resolver
debug, // a boolean that will print additional debug logging if execution errors occur
cacheControl, // when set to true, enable built-in support for Apollo Cache Control
subscriptions, // String defining the path for subscriptions or an Object to customize the subscriptions server. Set to false to disable subscriptions
playground, // GraphQL Playground 开发工具配置,详见 https://github.com/prisma/graphql-playground#usage
// ...
},
// 用于获取 apollo server 的配置, 会作为参数传进来,可以用来做一些特殊操作,例如 formatError 时利用 app.logger 打印错误日志getApolloServerOptions
// 方式获取的配置最终会通过 Object.assign() 的方式 merge 到 apolloServerOptions 上`
getApolloServerOptions: function (app) {
// 如果想使用订阅,在进行 websocket 连接的时候传递 Authorization
return {
subscriptions: {
onConnect: (connectionParams, webSocket, context) => {
const ctx = app.createAnonymousContext()
ctx.request.header.Authorization = connectionParams.Authorization
return ctx
},
},
}
},
};开发调试
使用 GraphQL Playground 工具进行开发调试,详见 https://www.apollographql.com/docs/apollo-server/features/graphql-playground

请将 graphql 相关逻辑放到 app/graphql 下,请参考测试用例,里面有 connector/schema 的目录结构, 以及 dataloader 的使用。
目录结构如下
`
.
├── app
│ ├── graphql
| | ├── common
| | | └── directive.js // 自定义 directive
│ │ ├── project
│ │ │ └── schema.graphql
│ │ ├── schemaDirectives
│ │ │ └── schemaDirective.js // 自定义 SchemaDirective
│ │ │
│ │ └── user // 一个graphql模型
│ │ ├── connector.js
│ │ ├── resolver.js
│ │ └── schema.graphql
│ ├── model
│ │ └── user.js
│ ├── public
│ └── router.js
``
MIT