Structuring your code is probably the first task you will have to do when starting a new project. Of course, if you’re using a framework, you will probably get offered a default structure. This is because “convention over configuration” principle generally helps to get started a lot faster. However, when writing micro/small services in Node.js, I find frameworks too bloated because they come with many things that we either don’t need (ex: routing) or that we will swap with another lib at some point (ex: security). It’s also great to get to the basics to start your new app without the bloat and to handpick every dependency that we’re going to add. This way, if we’re writing multiple services with the same libraries, we come up with our own kind of framework that is perfectly suited for us. What a beautiful thing!
Apollo Server is often paired with the express web server but also include its own production-ready server (which is just a spin of Node’s http.Server). This is perfect for us, considering we can add a different web server like express or koa if we need it later. However, starting vanilla also means we are faced with no enforced patterns to structure our code. To the inexperienced developer, this can be daunting. How are we going to decide the structure of our code? Well, sweat no more, we’re going to explore three different architectures so we can pick the best one for us.
In this article, every example comes from the betaflag/graphql-server-scaffolding Github repository where we can find a working application implementing each structure.
From that repo, the only dependencies are Apollo Server and GraphQL.
npm install apollo-server graphql
This structure reflects the pure architectural simplicity of writing a server in a single file. Of course, this is unsuitable for large projects, but I can justify its usage in a micro or small service. First of all, not all APIs require a lot of code for their server.
Consider this example: you want to integrate sentiment analysis to your messages in your chat application. You decided that this shouldn’t be part of your core application and should be externalized into a separate service. It would act as a black box: a message comes in, an analysis comes out. You can start working right away with an open source library called “Sentiment” that gives you this simple interface “sentiment.analyse(message)”. Writing your sentiment analysis micro service will only require to wrap it inside a resolver and would fit nicely into a single file.
.├── package.json└── src└── index.js
Pros
Cons
This is what you usually get when creating or scaffolding a project using a framework. It’s an easy structure to get started and fits applications of all sizes. This structure is about putting files where they belong according to their respective role. The GraphQL type definitions are found in the “typeDefs” folder, and the resolvers are located in the (you guessed it) “resolvers” folder.
Here’s an inexhaustive list of roles you can find in a GraphQL API: data, models, migrations, validators, typeDefs, resolvers, services, routes, config, utilities, etc.
.├── package.json└── src├── data│ └── index.js├── models│ ├── Book.js│ └── index.js├── resolvers│ ├── booksResolvers.js│ └── index.js└── typeDefs├── index.js├── query.js└── types├── bookType.js└── index.js
Extracted from betaflag/graphql-server-scaffolding on Github
Pros:
Cons:
If you want to add an extra modular touch to your app, this structure is for you. In this structure, the top-level folders represent domain areas. It is modular because of the natural boundaries between these. We can even achieve extreme modularity by externalizing domains into their own NPM modules that could then be shared across applications. However, it’s not because you can that it always makes sense to do it.
Defining your domain isn’t always easy when starting a new application. Domains like users, permissions and profiles are quite natural, however, you will probably have some overlapping sub-domain at some point and this is where it gets difficult.
On the other hand, it’s great to separate your domain with a clean interface and to decide once and for all where a sub-domain lives. In large applications, teams generally form organically around domain areas. Think of data, reporting, security, etc.
.├── package.json└── src├── books│ ├── Book.js│ ├── data.js│ ├── index.js│ ├── resolvers.js│ └── typeDef.js└── index.js
Pros:
Cons
Choosing the right structure for you is your choice and it’s always possible to change it later. However, choosing the right one from the start is a good way to avoid future headaches.
If you know other structures that I haven’t covered, I’m looking for help to add them to my repository at betaflag/graphql-server-scaffolding. You can also add it in the comments below. Discuss with me on Twitter @betaflag
Photo by Nicolas I. on Unsplash