egg-graphql目前存在以下问题
- 不支持formatError ,无法捕获异常
- 不支持文件上传
- graphiql调试界面没有graphql-playground好看
- 不支持apollo-server的选项
修改lib/load_schema.js
//增加
app.schemaConfig={
typeDefs:schemas,
resolvers:resolverMap,
directiveResolvers:directiveMap
}
修改app/middleware/graphql.js
const { ApolloServer } = require('apollo-server-koa')
const compose = require('koa-compose')
/**
* @param {Object} options The `options` of apollo-server.
* @return {Promise} The compose of middleware in apollo-server-koa.
*/
module.exports = (_, app) => {
let graphqlConfig=app.config.graphql
if(typeof graphqlConfig==='function'){
graphqlConfig=graphqlConfig(app)
}
const options = {...app.schemaConfig,...graphqlConfig}
const {graphiql=true,router,...ApolloServerConfig}=options
const server = new ApolloServer({
context: options=>options.ctx,
//不设置request.credentials 会导致请求不带cookie
playground:graphiql&&{
settings:{
"request.credentials": "include"
}
},
...ApolloServerConfig,
})
const middlewares = []
const proxyApp = {
use: m => {
middlewares.push(m)
},
}
server.applyMiddleware({
app: proxyApp,
path:router
})
return compose(middlewares)
}
更漂亮的调试界面.
不支持onPreGraphiQL,不过onPreGraphiQL只在开发阶段用
如果要支持onPreGraphQL的话,可以在app/middleware/graphql.js里添加
赞,这类插件,交给社区来维护吧,我这边接触不多。
@supperchong Thank you very much.
The existing official egg-graphql's GraphQL version is too fucking old.
之前实现了一个兼容现有 egg-graphql 功能,支持 ts,且基本完全支持 apollo-server-koa 现有功能的版本,思路如下:
// app/middleware/graphql.js
'use strict';
const { ApolloServer } = require('apollo-server-koa');
const { get } = require('lodash');
module.exports = (_, app) => {
const options = app.config.graphql;
const graphQLRouter = options.router || '/graphql';
let apolloServer;
return async (ctx, next) => {
const { onPreGraphQL, onPrePlayground, playground } = options;
if (ctx.path === graphQLRouter) {
if (ctx.request.accepts([ 'json', 'html' ]) === 'html') {
playground && onPrePlayground && await onPrePlayground(ctx);
} else {
onPreGraphQL && await onPreGraphQL(ctx);
}
}
// init apollo server
if (!apolloServer) {
const { getApolloServerOptions } = options;
const apolloServerOptions = Object.assign(
{
// log the error stack by default
formatError: error => {
const stacktrace = (get(error, 'extensions.exception.stacktrace') || []).join('\n');
ctx.logger.error('egg-graphql', stacktrace);
return error;
},
},
options.apolloServerOptions,
// pass ctx to getApolloServerOptions
getApolloServerOptions && getApolloServerOptions(ctx),
// pass schema and context to apollo server
{
schema: app.schema,
context: ({ ctx }) => ctx,
}
);
apolloServer = new ApolloServer(apolloServerOptions);
apolloServer.applyMiddleware({ app, path: graphQLRouter });
}
await next();
};
};
感兴趣的小伙儿伴可以一起试用维护:
Is this possible to add an authorization layer/middleware before accessing Graphql paths? I need this so much!
@taviroquai
One soluton
//config.default.js
config.middleware=['isLogin','graphql']
config.isLogin = {
ignore:/^\/api\/v1\/login$/
}
post /api/v1/login
//middleware/isLogin.js
module.exports = options => {
return async function(ctx, next) {
if (!ctx.session.user) {
return (ctx.body = {
...commonCode.unLogin,
})
}
await next()
}
two solution
reference apollo-server
@supperchong thanks. I need to access the Graphql operation info (for example: https://github.com/graphql/express-graphql/blob/master/src/index.js#L460)
Maybe I have to parse the graphql request by my own... but it would be nice to have this before... ah I see, I can create another middleware to parse the graphql request.
@taviroquai Oh I know, It will be a feature latter.I have a idea ,
auth//auth.js
let auth=resolver=>{
return (_, args, ctx) {
const token = req.headers.authentication || ''
// try to retrieve a user with the token
const user = getUser(token)
// optionally block the user
// we could also check user roles/permissions here
if (!user) throw new AuthenticationError('you must be logged in to query this schema')
return resolver(_, args, ctx)
}
}
wrap resolver with auth if need authorization
```js
const auth = require('../util/auth.js')
module.exports = {
Query: {
companies: auth((root, args, ctx) => {
return ctx.service.company.getCompanies(args)
}),
},
}
or use directive?
Cool! I would even extract to configuration...
authorization.json
{
"anonymous": [
"Query.companies"
],
"admin": [
"Query.companies"
]
}
auth.js
// Deny or allow using currentPath
const authConfig = require('./authorization.json');
let auth = (currentPath, resolver) => { ... }
module.exports = auth;
resolvers.js
const resolvers = {
Query: {
companies: (root, args, ctx) => {
return ctx.service.company.getCompanies(args)
},
},
}
Add authorization
const resolvers = require('./resolvers');
const auth = require('./auth');
const wrapAuth = (resolver, path = '') => {
Object.keys(resolver).forEach(key => {
const currentPath = [path, key].join('.');
if (typeof resolver[key] === 'object') wrapAuth(resolver[key], currentPath);
else resolver[key] = auth.bind(null, currentPath, resolver);
}
}
wrapAuth(resolvers);
return resolvers;
Most helpful comment
之前实现了一个兼容现有 egg-graphql 功能,支持 ts,且基本完全支持 apollo-server-koa 现有功能的版本,思路如下:
感兴趣的小伙儿伴可以一起试用维护:
https://github.com/Carrotzpc/egg-graphql/tree/next#readme