-
Notifications
You must be signed in to change notification settings - Fork 65
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
Serverless mode #782
Comments
This feature removes documented server methods and adds three new but undocumented app methods: start, stop, assemble. We will see if we document these in a future change. Also these methods are not statically exported as named exports. Motivations: What has been done is mostly about refactoring. - decouple concept of starting server from assembly to support future serverless feature #782 - assembly is the process of gathering the lazy state into a final runnable one - settings is now a component like schema and server - the components are designed to look a lot more symmetrical now - root app state is passed down to components which attach their namespaced state to, easier to reason about, think redux - introduce concept of checks that runs after schema assembly BREAKING CHANGE: - `server.start` and `server.stop` are no longer exposed. If you had a use-case for them please open an issue to discuss.
progresses #782 closes #528 #### Implementation Notes Several deps have been added in this PR. The goal is to move quickly and iterate on our server components. None of the deps are large, even [fp-ts](https://bundlephobia.com/[email protected]). fp-ts is exciting. It begins our journey into throw-free code! #### User Notes This feature will remain undocumented while we make progress on more parts around it. This feature exposes request handlers on the server component. ```ts import { server } from 'nexus' server.handlers.graphql server.handlers.playground ``` Users can use these to response to requests in a serverless environment. ```ts import { server } from 'nexus' export default (req, res) => { server.handlers.graphql(req, res) } ```
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Hey @kristoferma, thanks for the kind words. Ah, I think I know why yes. We'll fix that soon, maybe tomorrow. If you file a bug issue for it that would be great too. @Weakky We'll need to not assume that all plugin settings are JSON serializable. I kind of saw this coming but now here we are. |
Some additional thoughts came up with @Weakky today while sprint planning.
|
Next.js encourages users to fetch initial props for apps via getServerSideProps method of each page component. They encourage users not to use api routes but to "write server side code directly" docs. This would require a new way of interfacing with nexus without launching a server. The easiest way to do this is to expose a method to execute graphql queries without starting a server. Something like this: import { execute } from 'nexus'
export const getServerSideProps = async ({ params }) => {
const response = execute(params.query, params.variables)
return JSON.stringify(response)
} |
Hey @kristoferma, yeah we're aware, from the docs:
This means that one should be using, for example, and generally, Prisma Client directly, not an API at all. Of course, that's the general idea. A user in should do what they need to in their scenario.
Using Nexus without a server is already possible https://www.nexusjs.org/#/guides/serverless |
Hey @kristoferma sorry missed your post before, about it:
This was a bug, its fixed now in latest canary.
Plugin settings reflection was enhanced to support non-serializable settings data. So again, latest canary this is fixed. |
Thanks, this fixed the issue for me
I should have explained my use case better. I am using Relay with Next.js and I want to server side render my page and pass on the Relay Store caching from the server to the client. To do this I must fetch the data with relay on the server, stringify it as json and pass it on as props via GetServerSideProps. If I use Prisma Client directly, I lose the ability to pass the Relay store from the server to the client. Currently I fetch the data from the graphql endpoint and it works fine, but it adds an extra step that could be bypassed by executing the graphql query from the GetServerSideProps |
@kristoferma Ah my mistake, you were talking about
It seems like what you need is the layer right below the handler. You might be able to hack a solution right now with Nexus' current serverless support. Your use-case is interesting. If you can create a new issue for that'd be great. |
Hello @jasonkuhrt, I am enjoying getting to grips with nexus and would like to deploy with lambda. If this is already possible then it would be useful to reference an example lambda handler function. Perhaps I am jumping ahead slightly though. Thanks |
Hey, yeah slightly. You're kind of on your own right now. I actually think it might be possible now with the primitives we've shipped but, not sure. Check out https://www.nexusjs.org/#/guides/serverless. Now that we have an integrated bundle step, it means you should be able to zip the build and ship to AWS Lambda. But again we haven't explicitly made this a feature/goal yet, its on the roadmap. |
I'm trying to use with Serverless AWS but I've problem with the export handlers because the graphQL handler cant load all the schema files.
If we access the playground using the In serverless it works too, but It cant find any of the schema files. The playground works but empty. Manually changing the deployed files and moving the There is a copy of the // app.ts
import app, { use, server } from 'nexus'
import { prisma } from 'nexus-plugin-prisma'
import serverless from 'serverless-http'
use(prisma())
app.assemble()
export const graphql = serverless(server.handlers.graphql, {
request(request: any, event: any, context: any) {
const { body } = request as any
request.context = event.requestContext;
request.body = JSON.parse(body.toString()) // parsing body bc body is some weird buffer thing
return request;
}
})
export const playground = serverless(server.handlers.playground) Is it somehow possible to bundle the schema files into the built |
This happens for me because there are two instances of Prisma, one in nexus-plugin-prisma node_modules and another one in the root project node_modules. I fix this by deleting This is probably a bug but I have not submitted an issue on this |
This not solve my issue, sadly. In my environment I don't have this duplicated Prisma. Pretty sure is because we are missing the schema required files on the handler call. In the non- |
Nexus Prisma apps depending on prisma deps directly is not supported.
That's what |
@jasonkuhrt the necessary schema files are bundled into index.js, which does not contain any of the exported handlers from app.ts. So in order to use nexus with the serverless framework, currently my understanding is that we need to copy all the require statements into the built app.js (manual retouching of built files). |
@kldzj will have to look into it. Like I mentioned to toddpla you're a bit ahead of us. If you want to contribute a serverless example to examples repo that might be a good place to explore the issue more precisely. |
Hallo @jasonkuhrt, thank you for your quick response. https://github.com/zapbr/nexus-prisma-aws-serverless-demo |
This is a hack, but if you just import your schema files, you'll force it into the bundle.
Hoping for a better solution soon! |
@AaronBuxbaum great find, but seems very ugly when you have a lot of models. We decided to just migrate back to @nexus/schema. |
@AaronBuxbaum that's with nextjs correct? @kldzj I'm assuming there was another reason than that since you'll have to import modules just the same with |
Currently, no (I'm playing with serverless -> AWS Lambda), but I suspect it would be easy to put this on NextJS if desired |
@jasonkuhrt wanting to use federation was another reason, but mainly for ease of serverless deployment. |
@AaronBuxbaum If you can contribute an example or recipe that would be great. It seems that your technique is similar to our nextjs recipe. |
I made it work with Webpack + Serverless + Lambda but I am not sure if the solution is feasible. Basically, like the #109 issue says, you get a lot of warnings if you use sls and webpack, because of the usage of Note: I could not make the typescript serverless plugin to work so I run tsc, prisma generate and nexus build before deploy.
Example that I had to change in typegenAutoConfig.js
I also had to make similar changes on files like manifest.js, linkable.js, couple of utils.js, import.js, etc. After this, it will complain that it cannot find the
After this, As I said, this does not work just yet on deployment. It will complain about the plugin not being able to find because I have to assume sls is just doing yarn and getting the npm module which does not have the fix. I'll try to work on that next. |
Dropping by to say I have a blast combining NextJS, Prisma and Nexus with the experimental serverless API. My // pages/api/graphql.ts
import app, { settings } from "nexus";
import nextConnect from "next-connect";
import { sessionMiddleware, randomMiddleware } from "../../lib/middleware";
require("../../graphql/schema");
settings.change({
server: {
path: "/api/graphql", // for playground
},
});
app.assemble();
export default nextConnect()
.use(sessionMiddleware)
.use(randomMiddleware)
.use(app.server.handlers.graphql); Thank you for your hard and much appreciated work on Nexus |
I tried all of code above but I can not run my serverless. Does Nexus support serverless? |
@heibel Could you please share the rest of your setup? I am still trying to deploy to lambda and while it works locally, it is because of the manual changes that I did to the code and I could not make the setup to work effortlessly. Thanks |
@sfratini I forgot to mention I deploy to/with Vercel. Which works with the above code. Maybe you can share your code/lambda errors? |
Sure, so basically it is not finding the prisma plugin. Now, the plugins are loaded using require.resolve which webpack does not like. I "solved" that locally by replacing all the places nexus uses that, with eval() calls which are executed at runtime (you can see my changes a couple of comments above). The issue however, is that serverless does an install which, obviously installs the version without the change so on the cloud, the plugins won't work. (with webpack) I need to use webpack (or any other packager/compression tool), because lambda has a 250MB limit.
|
I've been having a blast playing around with Nexus + Serverless for the last few days, thought I'd throw my solution out there in case it helps anyone. Still a WIP, but I'm pretty happy with what I've got so far (Prisma client operational on AWS Lambda, doesn't require webpack or any request hacking). api/app.ts
prisma/schema.prisma
serverless.yaml
I'm still trying to wrap my head around injecting a different DATABASE_URL in different environments, and running migrations/seeds post-deployment, but I think the broad strokes are there! |
This is very interesting. As for the URL, I would use Lambda environment variables or WKS. I never understood why the env variables in lambda cannot be protected a little more. Anyone with read access to the function will see those. So every dependency that nexus needs is in there? What about prisma client? resolvers? The nexus build actually works as webpack and generates an isolated folder? |
Yup, everything nexus needs should be in that .nexus/build/ directory. My deploys to AWS were failing due to size constraints, and I noticed node_modules at the root of the Lambda, and node_modules in .nexus/build/; turns out you only need one set! The Prisma Client should also be in .nexus/build/node_modules, under .prisma. As long as you run Yeah my solution for the DATABASE_URL was as follows, seems ok but it's in plaintext in the AWS Console so still not ideal :(
With the above everything is working (and also allows for migrations in the GitHub deploy action). I can access the GraphQL playground and query the DB in AWS. Eventually should maybe use AWS SSM for the DB URL though. Hope that helps! |
Hello, I've been playing with Nexus + Prisma + Serverless for a few days as well, I want to share my working solution graphql.ts
app.ts
Serverless.yml
|
Perceived Problem
Ideas / Proposed Solution(s)
Nexus needs to expose a "request event" handler. This is what the host server platform will call.
Many Node http server APIs have request handlers with request and response parameters. However it seems a lot more intuitive to have request as the input and response as asynchronous output.
...But what does a user do when they want to code against their deployment platform of choice. For example from a comment in the nextjs integration issue:
server.platformHandle
orserver.handle.fromPlatform
but it is unclear why we need the indirection, why we need both. It seems right now that we should just makeserver.handle
be that.The request handler should be exported for use by the host platform. Example with nextjs (with vercel):
The inability to export an import directly seems bad. But one could say either way is boilerplate and wht's really bad is doing any of that in the first place.
several things should change in nexus between serverful and serverless modes
server.start
server.stop
APIs should only appear in serverful modeserver
jsDoc should reflect the current server modeserver.express
API should not appear in serverless mode. Express should not even be in the final built bundle.port
andhost
should only appear in serverful modepath
is for configuring the graphql endpoint path. The concept of path control applies to both serverful and serverless systems but its configuration/mental model is very different. In serverless the path may be configuration within terraform, yaml, cloud formation, file name/location (nextjs), etc. To the extend that Nexus can automate this thepath
configuration makes sense in serverless mode, however it stops making sense once a user needs to manually configure path in another system.port
?settings.server.platform.port
?settings.dev.server.platform.port
? Conceptually, configuring the platform that runs the app in the app makes no sense, so...package.json#nexus.serverless.port
? Or the conceptual nonsense is acceptable for the simplicity it gives for dev and transition between serverless/serverful?playground.path
has the same issues as described forpath
. Additionally, if users expect to deploy playground in serverless mode, it raises the question of multiple endpoints, which in serverless, each constitutes its own app.Some things should not change between serverful and serverless modes
Server middleware server middleware #523 should remain abstracted from the host platform so that plugins can provide server middleware without concern for the server in use.
This is non-trivial because certain http features are simply not possible on certain serverless platforms. How can a plugin author design their plugin for maximum portability, needing some server features, but not knowing if the plugin will be used in an environment that has that capability?
The design problems here are not unlike prisma which abstracts different databases.
Maybe some kind of capability modelling/matching system will need to be designed.
This is a whole topic unto itself.
Some of the points above (
settings.server.path
, server middleware, ...) make pretty clear that a serverless mode is not enough, but a sererless platform mode is needed, wherein the particulars of a server platform are taken into account, adapted for.References
The text was updated successfully, but these errors were encountered: