GraphQL server for enterprise development

Tom Yitav
Castory-ai
Published in
4 min readJan 29, 2018

Designing a GraphQL server architecture can be tricky. Although it is a fairly new concept, there exist many best-practices and tools setting up a server. In this post, I am going to describe the Graphql server implementation that best suited our team needs. The Source code for the project is available at- https://github.com/tomyitav/graphql-server-typed

Instructions on how to run the server are available in the repository description.

Background

Coming from a Java based background, I used numerous frameworks that allowed me to create an enterprise level server implementations. Most notably, I found Spring boot opinionated philosophy of design for your server architecture, very elegant. The greatest benefits I had were:

  • Layered architecture that separated the Controller, business logic (or model) layer and DB (or repository) layer, thus allowing us to have great separation of concerns. For Example, One can decide to switch their DB system with minimal change to other layers implementation:
Spring architecture- taken from Petri Kainulainen great article
  • Inherent use of Dependency Injection, for developing a modular, testable code
  • I was comfortable using Java static nature compared to dynamic-language frameworks such as Express or Django.

GraphQL core concepts and advantages over REST

About two years ago, I came across the very innovative concept of GraphQL, as a possible alternative to traditional REST Api server.

If you are not familiar with the concept of GraphQL, read the following article first. I will briefly review some of GraphQL core concepts:

  • A GraphQL server has schema. That means that a client can introspect the server types, queries and fields.
GraphQL introspection
  • A client can query and subscribe to a subgroup of type fields, and therefore extract the fields of interest. In the next example from our server, The type Car is queried against the ‘name’ field only.
Fields extraction
  • In GraphQL it is easy to resolve a query, from possibly multiple data sources, in a single round trip to the server. The following post shows how GraphQL can be used as API gateway for resolving data from multiple micro services.

Seed project architecture overview

Although the GraphQL benefits were very clear for me, I found it difficult to design the server in Spring- like architecture, to enjoy its advantages. After some work in our team, we have created a seed project for creating a modular server instance for our needs. The server is implemented in NodeJS, using TypeScript.

We will now walk through some of the main features of the project. (The source code is available here.)

  • Use of TypeScript- The TypeScript compiler will show errors and warnings on potential problems, before running the server. This is made possible by specifying variables and parameters types-
private async initializeGraphqlServer(graphQLServer: Express, GRAPHQL_PORT: number) {
await graphQLServer.listen(GRAPHQL_PORT);
this.logger.instance.info('Server started on port - ' + GRAPHQL_PORT);
}
  • Modular schema design, by allowing separated files for types. Instead of passing one large string for our schema, we split our types and resolvers to multiple files, located in graphql directory, in types and resolvers sub-directories. This way, we avoid schema complexity by using merge-graphql-schema library. So as your project grows- you can extend the schema by adding new type in types directory, and adding matching resolver file in resolvers directory. The schema is updated automatically.
import * as path from "path";
import {makeExecutableSchema} from "graphql-tools";
import {fileLoader, mergeTypes, mergeResolvers} from "merge-graphql-schemas";
import {GraphQLSchema} from "graphql";

const typesArray = fileLoader(path.join(__dirname, '../types'),
{ recursive: true });
const resolversArray = fileLoader(path.join(__dirname,'../resolvers'));
const allTypes = mergeTypes(typesArray);
const allResolvers = mergeResolvers(resolversArray);
let schema: GraphQLSchema;
schema= makeExecutableSchema({
typeDefs: allTypes,
resolvers: allResolvers
});

export default schema;
  • Use of graphql-code-generator library, for generating TypeScript definitions. These definitions are created from the graphql schema type definitions, and will be set in interfaces/types.d.ts file. Type generation is executed in every build.
const resolveFunctions = {
Query: {
car (_, args: CarQueryArgs, context: AppContext) : Promise<Array<Car>>{
const carsModel: AbstractCarsModel = context.carsModel;
return carsModel.getCars(args.name);
}
},

CarQueryArgs and Car are auto-generated types, inferred from the schema.

  • Resolver functions fit perfectly as the server controllers. They should be designed as a thin layer, where no business logic is implemented. The model services should perform the core logic, and are accessed from the resolvers by using the GraphQL context. (see previous paragraph for example of using AppContext).
  • Use of injection-js library, for angular-style dependency injection. Using DI makes our code more testable and configurable.
@Injectable()
export class PubsubManager extends AbstractPubsubManager {

constructor(private logger: AbstractLogger) {
super();
}

public getPubSub(): PubSub {
return this.pubsub;
}

public publish(topic: TopicName, entity: any) {
this.logger.info('Publishing on topic- ' + topic);
this.pubsub.publish(topic, entity);
}
}

The logger is injected via constructor-injection. The injector configuration is initialized in injector.ts file.

Conclusion

In this post, We have walked through some guidelines that would hopefully help other teams to create their GraphQL server implementation. I feel that the seed project can be used for leveraging some libraries and tools for easy and efficient setup. Pull requests and issues for the repository would be greatly appreciated.

If you liked the post, please feel free to waste a few seconds to give it 50 claps :-)

--

--

Tom Yitav
Castory-ai

Experienced software developer, passionate about creating new things