-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bring back composable middlewares in apollo-server 2 #1308
Comments
I've been stuck on this for half a day today, trying to mix my other middlewares in (e.g. jwt authorization) so that they go before graphql, but no success |
+1 for this, this is not so |
We use to mount Apollo on |
Apollo Server 2.0 (e.g. the For those saying that it's not possible to compose middleware, have you attempted to use these patterns from the 2.0 migration guide? |
@abernix, Yes, I tried the Basically, I was using Any suggestion? |
@flisky Are you passing
For example, this sample server demonstrates running two separate Apollo Server 2 instances on the same |
Sorry, I cannot. The path would be any tenant name, which could be resolved dynamically, because tenant could be dynamic registered. In apollo server 1.x, I would do
But I cann't find way to do this in apollo server 2 |
From the linked issue it was already clear that core team has no interest in this one and since v2 is out, the possibility is very close to zero. 😞 |
I understand the aim of getting a GraphQL server running quickly with best practices, but this pattern is very restrictive and not transparent as to what is inside. I would prefer an approach more similar to adopted for the apollo client, whereby apollo-boost was created which is a preset bundle of the other packages aimed at getting the client running ASAP, but preserved the integrity of individual packages. |
@alexFaunt same idea was proposed here :) |
@abernix even if you put your middlewares before applyMiddleware to be run on the same path, where your own middlewares do something with koaContext e.g. add authenticated user object to it, the context object is reset when resolving graphql middlewares, meaning your changes to the context object are not available inside graphql resolvers - eventually making it's super-difficult to use context-related data |
@abernix I'm curious to get your feedback on my current solution for bringing back ASv1 middleware style below. The main reason for this is to get access to graphqlExpress() to return a schema specific to the request. I removed typescript stuff just for readability here.
This works, the main issue is having to copy graphqlExpress manually since /* Have to import these extra libraries */
const { renderPlaygroundPage } = require('@apollographql/graphql-playground-html')
const accepts = require('accepts')
const { json } = require('body-parser')
const { ApolloServer, makeExecutableSchema } = require('apollo-server-express')
/* Don't think it's exported normally, get directly */
const { graphqlExpress } = require('apollo-server-express/dist/expressApollo')
class CustomApolloServer extends ApolloServer {
applyMiddleware({ app, path }) {
/* Adds project specific middleware inside, just to keep in one place */
app.use(path, json(), auth, (req, res, next) => {
/* Playground collapsed for readability */
if (this.playgroundOptions && req.method === 'GET') { // ...
/* Not necessary, but removing to ensure schema built on the request */
const { schema, ...serverObj } = this
/**
* This is the main reason to extend, to access graphqlExpress(),
* to be able to modify the schema based on the request
* It binds to our new object, since the parent accesses the schema
* from this.schema etc.
*/
return graphqlExpress(
super.createGraphQLServerOptions.bind({
...serverObj,
graphqlPath: path,
/* Retrieves a custom graphql schema based on request */
schema: makeExecutableSchema(getCustomSchema(req)),
context: {
// ...other context
request: req
}
})
)(req, res, next)
})
}
}
const server = new CustomApolloServer({
/* adding a default graphql schema initially */
schema: makeExecutableSchema({ typeDefs, resolvers })
})
server.applyMiddleware({ app, path })
app.listen({ port: 4000 }, () =>
console.log(`http://localhost:4000${server.graphqlPath}`)
) |
Related: #1282 (comment) |
@chentsulin:Not sure whether your team will expose the middle-wares in the next release or in the future? |
We used to get the 'graphqlKoa' and 'graphiqlKoa' before as the middle-wares, but now they have been either removed or hidden from the public. And since v2 of apollo we've faced with a BREAKING CHANGE (See:apollographql/apollo-server@dbaa465#diff-64af8fdf76996fa3ed4e498d44124800 ). In order to be compatible with the older codes users are referring, we have to do some tricks: 1) Directly refer 'graphqlKoa' from 'apollo-server-koa/dist/koaApollo' instead of 'apollo-server-koa', because it's NOT exposed through 'index.js'. 2) 'apollo-server-module-graphiql' is removed, so in order to compatible with what it was, we have to add this in our package and reuse that. And then we should rewrite 'graphiqlKoa' function as the middle-ware copied from: https://github.com/apollographql/apollo-server/blob/300c0cd12b56be439b206d55131e1b93a9e6dade/packages/apollo-server-koa/src/koaApollo.ts#L51 Notice: This change is also a BREAKING one, so please DO NOT apply to apollo's version that is less than 2.x. And there're many ambigious problems about this design of v2 for apollo (See: apollographql/apollo-server#1308). So according to chentsulin's ideas, maybe the middle-ware functions would be re-added in the future (See: apollographql/apollo-server#1282 (comment)).
@evans hey, can you tell us (the users of apollo-server) if middleware way of handling things is planned for apollo-server v2? Personally, I can't use v1 forever (graphql 14 and up already give you a warning) but I don't like the design of v2. If you don't have plans to bring back support / change the way v2 is doing things, we can create a separate package with separate middlewares and use it instead. I don't want to pollute npm with such package if you have plans for this but if you don't, it would be great to have your confirmation before start. Thank you. |
I really need this too. |
The thing is most of these are already available as separate packages or can be put together with little effort.
We could have an
https://github.com/jaydenseric/graphql-upload
I see this as the "primary" one, default export of
This one should be entirely optional, I believe, and not even published/shipped to production.
https://www.npmjs.com/package/@koa/cors
|
Yes, I agree that almost everything is available as a separate package. |
I am able to replicate the existing middleware behavior of v1 for Koa as follows import koaBody from 'koa-bodyparser'
import { graphqlKoa } from 'apollo-server-koa/dist/koaApollo'
import { resolveGraphiQLString } from 'apollo-server-module-graphiql'
const graphiqlKoa = options => async ctx => {
const query = ctx.request.query
const body = await resolveGraphiQLString(query, options, ctx)
ctx.set('content-type', 'text/html')
ctx.body = body
}
// assuming koa-router
router.get('/graphql', graphqlKoa({ schema }))
router.post('/graphql', koaBody(), graphqlKoa({ schema }))
router.get('/graphiql', graphiqlKoa({ endpointURL: '/graphql' })) There are few issues with this:
|
As mentioned in [this issue](apollographql/apollo-server#1308), Apollo Server 2.0 doesn't work with the way this repo had been built. This was just an experiment anyway (though with hope to use in real world applications), and considering my other hesitations about how Apollo works, this is just the deciding factor. I'm going to try a different approach.
I also have a multi-tenant server with some specific authentication requirements. I was trying to upgrade to 2.0 today to do subscriptions but I'm stuck on this issue. The "simple made easy" clojure paradigm comes to mind. Middleware is simple and easy to compose and reason about. Trying to abstract the middleware away to make it "easy" does not make it "simple" to use IMO. |
I just wanted to confirm--Currently it's not possible to pass an express router instance to createServer? It would be fantastic if I could create a router, apply middleware to it, and then use the router to create the server. Instead of this: const express = require('express')
const app = express()
const apiPath = '/api'
apolloServer.applyMiddleware({ app, path: apiPath }) It would be fantastic if I could do this: const express = require('express')
const app = express()
const apiPath = '/api'
const apiRouter = express.Router()
// middleware that is specific to this router
apiRouter.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// NOTE: cannot pass router to `apolloServer.applyMiddlware()`
apolloServer.applyMiddleware({ router: apiRouter })
app.use(apiPath, apiRouter) See Related Stackoverflow Post: https://stackoverflow.com/a/53597429/5373104 Please correct me if I'm wrong or missing something |
Almost half a year passed and there are no news about this one. It's pinned to version 2.2, but 2.3 was released and it's still not there. Can we have any info from core team about status of this one? |
+1 |
Aye, +1 from me too - don't know why a completely non-standard way of doing things was implemented here. |
For everyone watching - upvote and track this PR - #2244, maybe we'll finally get v1 methods instead of current horrible ones in v2. |
I need this to be able to use Apollo server 2. #1907. This is blocking me from using stable graphql 14.x which is problematic because most of the ecosystem has moved to stable graphql. Can we not make this higher priority? Only caring that newcomers have an easy time and not caring about existing users with proper production code with more complex requirements is really not cool |
@BrendanBall I understand your frustration. Maybe you'd like to express that sentiment over at #2244? At least there, some contributors are responding back and explaining things a bit and where the API might go from here. |
Since this was something we really needed for our product, we went ahead and wrote our own implementation of a koa middleware for an apollo server. It's heavily leaning on the implementation provided by It does not yet support subscriptions or file uploads, but other than that it should be a suitable replacement for those looking for a traditional middleware approach: |
@falkenhawk That explains why context gets reset inside the GraphQL resolvers. Unfortunately the only solution is to look at GraphQL yoga, they seem to have a nice way of handling middlewares. |
Thanks to @ganemone's #2435, the latest The I'm hopeful that this will resolve this (admittedly painful, and drawn-out) pain-point, and make using |
Ok, after recovering from the need to revert it, the That said, I've made a proposal for what I hope is an even better and more flexible/customizable solution in the future. Those subscribers to this issue seem like a relevant audience to solicit for input, so please do take a look at the proposal I put together in #3184! 😄 (For now, I hope |
Hey, coming from this one.
I'd love to try apollo-server-koa 2 and would love to use composable middlewares, similar to how it is done in apollo-server-koa 1 now.
Unfortunately, now it's possible to use only
ApolloServer
and no middlewares are exported. While it can help beginners or reduce time to setup server, this way of things lacks the transparency and adds another layer of magic which is not always desired.ApolloServer
could be another way of doing things, without removing separate middlewares. Please bring back this middlewares, they are very convenient and easy to see what's going on.The text was updated successfully, but these errors were encountered: