SERVER ~ OCTOBER 20 2024
I am used to working with GraphQL to build servers using what you might consider to be raw elements, especially when it comes to creating the schemas, resolvers, custom types etc. I wanted to try something different, so I've been using Apollo Server to serve a project recently in order to learn how much easier it makes working with GraphQL and where its Open Source limits are.
Apollo documentation is quite comprehensive and as with most packages and frameworks, it is enough to get you up and running and working with the software. When you want to deploy it to the wild though, things often get more interesting. This is a common issue across many software packages so let me fill in a gap or two.
First up, we need a strong server to start with. A good foundation for GraphQL is below. Combine this with the Apollo documentation for creating a server and you'll get a good sense of all of the elements and things going on here. I also have subscriptions running in GraphQL, so this setup is a little bit more elaborate than just for queries and mutations. Next up, I'll explain the concepts at play and the 'flaws' that make it less than ideal for a production environment.
Lots going on here, lets start with what is being imported..
I recently upgraded this setup in line with the latest version of Apollo Server, which now includes everything you need to setup the initial server. Previous to this, developers were required to import various third party packages to support the server setup. Apart from the usual foundational elements like the underlying server itself (express
) and extra tooling that supports that, plus the less used features of GraphQL (WebSocketServer
), all the Apollo specifics are straight from Apollo in the top three lines.
I use express because I don't just want Apollo Server running GraphQL within my server instance. I also have a good deal of seperate API services that manage things like Authentication, third party services like AWS & quite a nifty feature dealing with media rendering. That is all for another time though. You certainly don't have to use express if all you want is a GraphQL server, indeed, you could use the built in startStandaloneServer
method that comes with Apollo Server to fire up a simple server just for GraphQL.
The last few imports gather together the meat of any GraphQL server, the data sources, type definitions & resolvers. This isn't a blog about that but if you're here wanting to learn about the nuances of putting a GraphQL server into production, you probably know a bit about that already ;)
The code itself starts with setting up a base server that everything else sits in. Lines 19 and 20 create an express instance and inject it into a standard http server. Separate to that, I'm setting up an executable schema from the inner working elements on line 22, line 28 is the extra step I've taken using a combination of the above setup instructions from Apollo. This allows the WebSocket server to be created and start listening. On line 41 we get to put all of this together & instantiate the ApolloServer
itself. There's another extra piece of functionality in here which will shut everything down properly when required.
The last step is to envoke the server. We do this asyncronously since version 4. A lot of examples use a top level await
in order to do this but you need to be working in ES2022 or more. There are a few caveats to that but it is relatively straighforward to include an async
function and initialise this straight away. You'll see here that we're setting up other vital elements such as cors and middleware which houses data sources vital to the correct function of the server.
A seasoned Developer may already know the many and varied issues that can arise between a local dev environment (where all is disneyland) and on into production (where it meets 'the real world'). Security is a growing concern online and we can't really do without an application that has an ssl certificate anymore. Rarely does any documentation explain how to navigate the right setup to deal with this but if I wanted to get this project in front of the world, it was a necessity.
With some huffing and puffing & a few trials and errors, I couldn't see a more efficient way of doing this than that below. Have a look, it's actually fairly straightforward, more so than it was to get to this point. I omitted any areas that were unchanged so compare to the original server setup. I'm about to explain though, so read on.
Essentially all we really need to do beyond the original setup is to include an additional server, but this time it's an https server. Added to the imports are the https
module and the server certificates it needs, created and gathered together in the credentials
object. This tutorial isn't about creating the https server itself so going into generation of certificates is something I'll write about in another blog some day.
A new https server is created thanks to this but for optimization, only the correct server for the environment is used during deployment. An earlier version of this setup created both servers running in parallel. I knew it felt wrong to do that but it wasn't causing any issues during deployment. This way however is just better practice and easier to manage. The evokation code is now dynamic & includes one liner feedback in the console thanks to this.
Follow the above and you should have a reliable server that spins up the right way everytime!