-
Notifications
You must be signed in to change notification settings - Fork 27.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
Update most Apollo Server examples to Apollo Server 3 #30082
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think is missing to add express
into package.json
as a dependency based on this section of the Migration to v3 docs:
In Apollo Server 3, these packages have peer dependencies on their corresponding framework packages. This means that you need to install a version of that package of your choice yourself in your app (though most likely that was already the case).
@elrumordelaluz I'm not a Next.js expert but I don't think that's true here. We're not actually using Express --- we're just converting an Express-style middleware into a Next.js-style handler using the pattern from the Next.js docs. |
Did you tried to run one of those examples?
Seems to be due to this. |
@elrumordelaluz Hmm, I did run them and they worked for me, but you're right that there is a runtime dependency on express (for |
ad31825
to
3488f39
Compare
@elrumordelaluz I'm not sure why it worked for me before; maybe a difference in what npm/yarn installation we used which made mine install peer dependencies automatically? Anyway, added the dependency to all the examples. |
I have been using Apollo Server with Next.js from some time and was about to start a new project. I checked out this example and to be honest, this feels like change for the worse, compared to previous starter. The fact that is uses webpack experimental |
@patryk-smc could you expand a little more? I am also using Apollo in several NextJs projects, and I feel more that the change is between Apollo 2 and 3. In case you were using Apollo 3, what is the main difference between using const apolloServer = new ApolloServer({ /* ... */ })
const startServer = apolloServer.start()
export default async function handler(req, res) {
// ...
await startServer
await apolloServer.createHandler({
path: '/api/graphql',
})(req, res)
} Sincerely don't know about heavyness of each Hope in one of this threads/discussions we can arrive into a solution for the best composition using Apollo 3 and Next. |
I agree that this new version requiring Even if you want to stick with apollo-server-micro you'll still need topLevelAwait if you want to upgrade to v3. |
The problem with the The problem with using Given that (as far as I understand) none of the examples actually use FWIW, if part of the issue is that having to stick |
Thanks for the micro background, now it all makes sense. For me, the biggest annoyance is that it requires an experimental flag, meaning that every minor webpack update could potentially break the thing. Chances are low, but still, it's a good practice to not relay on experimental stuff in production. The middleware is not a big deal, but it would be nice to have it as a part of |
Sure. But on the other hand, the idea that a server might have to do async work on startup and shouldn't start serving incoming traffic until that work succeeds seems like a pretty basic capability for a server. So if webpack were to remove this later, hopefully Next.js could find another mechanism for achieving the same goal? Or if that really isn't possible, then at that point the examples could be changed to the worse "server starts up but every request fails" semantics. (This change in Apollo Server wasn't undertaken lightly — "my server had a plugin whose startup hook failed but my server runs anyway" was a major problem in Apollo Server 2 that many users ran into.)
FWIW this |
@glasser As NextJS is often deployed in serverless environments, would it be more suitable for it to use |
I mean, I'm not exactly sure what "serverless" means here, in a more concrete sense than "runs on platforms like Lambda". If there's an issue with AS startup (ie, start throws) then that ApolloServer object will never be able to run operations successfully. So the best approach is whatever is most likely to result in the object being re-created, which might be process failure in this case. (But the best approach is not to start a brand new server on each handler invocation, because then you're doing startup more than is necessary.)
|
Yes I noticed that's how the lambda version is implemented. Top level await is based upon on the Node runtime being >14.8, which I believe is supported by AWS lambda. Since Node 14 is the current LTS, I think top level await should work fine, but maybe it's worth leaving a comment about |
I've tried to make the same changes in my own project as seen here to see how it would work. Unfortunately, I've gotten some errors that seem to have to do with express, but I have no idea what they mean.
|
@tettoffensive The first one looks like a webpack error. I'm not very familiar with webpack. Are you able to share your configuration in a way I could reproduce it? Do these issues appear on the actual examples from this PR for you? Is it possible for a maintainer to approve running workflows on this so I can see if it is passing CI? |
FYI: I successfully transitioned to apollo-server-express based on this example, but after I wanted to check new middleware functionality in next@11.1.3-canary.88, I noticed that webpack |
@patryk-smc interesting, what do you mean by "breaks the whole next.js app"? Like, it just gives an error saying topLevelAwait is not supported? Or using it doesn't work well? |
I would advise against a custom server, you are killing Next.js performance. That's pattern is something you would have found in Meteor apps for instance. |
Hit exactly this - and your snip works perfectly with v3 and next 12. I did nothing but copy the code, npm the deps, and fire. |
@glasser Any thoughts on #38315 (comment)? I'm trying to bring this PR out of limbo. Let me know your preference, and I can either: merge all |
I don't use Next.JS. My only motivation here is to stop the sea of people showing up at our repo complaining about the fact that they can't figure out how to upgrade from AS2 to AS3 in Next, and also to stop people from using the least feature-complete Apollo Server flavor (apollo-server-micro) for no reason. For what it's worth, we're nearing the end of development on Apollo Server 4, which provides an actual stable API for building web framework integrations instead of having a set of 9 fixed integrations hardcoded in core. Additionally, it will provide a simple API for folks who really want the "serverless" experience of "I'm not allowed to do any work on startup that might possibly fail, or if I do that it should just make every single subsequent request fail instead of preventing the server from starting in the first place". So given that this has already sat open for 9 months, maybe we might as well just wait for AS4. I can't say I'm a big fan of #38315, if for no other reason than that it still uses apollo-server-micro for no reason. It certainly does seem reasonable to have fewer AS examples in this repo; it sure was a pain to update all of them. |
@apuyou just tried your apollo-server-nextjs and perfectly works - thank you! Maybe you want to update this merge-request to include your changes? That way there should not be any external dependency and this MR can finally be merged. Thoughts? |
@sajadghawami Thank you for your interest! I think we should probably wait for Apollo Server 4 to be released before updating this. AS4 is much easier to integrate with other frameworks and avoids depending on the integration being updated on each AS release. I have created a v4 branch that uses this integration for https://github.com/apuyou/apollo-server-nextjs (it currently works with the Alpha but not the RC). |
@apuyou Very cool to see! I was planning to come back here and replace this PR with an AS4 one, but it's even better if actual Next users do so. My thought would be that I'd make two examples: one that uses top-level await and |
Next.js doesn't support top-level await at all in latest versions due to SWC. |
yeah, it continues to be incomprehensible to me why you'd build a server platform that doesn't allow you to do possibly-failing work at startup before you start listening for connections, but hey, what do I know, Next.js is quite popular so I must be missing something! So I guess we would just make a single example that uses |
To be correct, it's a limitation of SWC. The problem is more that it's being pushed as the default solution while it's clearly limited compared to Babel, missing top-level await being the biggest drawback. I still use Babel happily to this day and will switch only when SWC is mature. |
Anyone stumble upon this thread looking for a solution to increase the body limit and be able to use multipart upload using function runMiddleware(
req: NextApiRequest,
res: NextApiResponse<any>,
fn: Router
) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result);
}
return resolve(result);
});
});
}
const apolloServer = new ApolloServer({
schema,
dataSources: () => dataSources,
context: contextFunction,
plugins: [ApolloServerPluginLandingPageGraphQLPlayground()],
});
const startServer = apolloServer.start();
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
await startServer;
const contentType = req.headers["content-type"];
if (contentType && contentType.startsWith("multipart/form-data")) {
req.body = await processRequest(req, res);
}
const apolloMiddleware = apolloServer.getMiddleware({
path: "/api/graphql",
bodyParserConfig: {
limit: "50mb",
},
});
return runMiddleware(req, res, apolloMiddleware);
}
export default handler;
export const config = {
api: {
bodyParser: false,
externalResolver: true,
},
}; |
@daniel-johnsson thank you! the |
@sajadghawami |
df8579c
to
47e5ebe
Compare
…ons/next (#42771) Closes #42769 ## Description This PR address #42769 by updating the `api-routes-apollo-server`, `api-routes-apollo-server-and-client` and `api-routes-apollo-server-and-client-auth` examples to use Apollo Server 4 and [@as-integrations/next](https://github.com/apollo-server-integrations/apollo-server-integration-next), which is the Apollo Server Next integration package. The PR also updates the three examples to use Typescript. The functionality of the examples is the same. ## Documentation / Examples - [X] Make sure the linting passes by running `pnpm build && pnpm lint` - [X] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) closes #33545 closes #30082 closes #21984 closes #10413
Previously, most of the examples used Apollo Server 2. As a maintainer of Apollo
Server, we frequently found that users would start with one of these examples,
try to upgrade to Apollo Server 3, and get confused when it didn't work. Apollo
Server 3 has a more explicit lifecycle that requires awaiting a
start
methodon startup, and users often put this in the wrong place. The
api-routes-graphql
package did use Apollo Server 3 and did callstart
, butonly awaits it when the first request comes in rather than at the top level.
Additionally, all the examples use
apollo-server-micro
. While this package istechnically a maintained part of the Apollo Server project, it is not as fully
featured or battle-tested as the most popular package,
apollo-server-express
. For example, it doesn't have the same default CORSbehavior has the other Apollo Server framework integrations, and doesn't have a
way to drain servers gracefully on shutdown. (Future Apollo Server features may
target
apollo-server-express
before other integrations as well.) BecauseNext.js can easily use Express middleware with just a few lines of integration
code (documented at
https://nextjs.org/docs/api-routes/api-middlewares#connectexpress-middleware-support),
Next.js users would be best served by using the most mainstream ApolloServer
implementation rather than the least maintained one.
So this PR:
apollo-server-micro
v2 toapollo-server-express
v3graphql
and@graphql-tools/schema
, andinstalls them where relevant
examples/api-routes-graphql
becauseapollo-server-express
has better CORS defaults. (If the default is not goodenough for this example, pass a
cors
option togetMiddleware
instead ofdoing CORS manually. The value of the
cors
option is equivalent to theargument to the npm
cors
package's middleware.)This leaves the
with-apollo-neo4j-graphql
example alone, as I could not get itto work properly before or after upgrading Apollo Server.
Documentation / Examples