Node.js library for splitting SDL first GraphQL schemas into composable & idiomatic chunks.
npm install idio-graphql> This package is inspired by; Apollo Federation, GraphQL Modules & Moleculer.
$ npm install idio-graphql
`⚠
graphql is a peerDependency you may need to install this too.`
$ npm install graphql
`Usage
`javascript
const User = new GraphQLNode({
name: "User",
typeDefs: type Query {
user(id: ID!): User
}
,
resolvers: {
Query: {
user: () => ...
}
}
});
const { typeDefs, resolvers } = combineNodes([ User ]);
const server = new ApolloServer({ typeDefs, resolvers });
`
1. What is a node ?
2. How do I integrate with my Apollo Server ?
3. How do I get started with microservices ?
4. Can I use Schema Directives ?
5. How can my nodes talk with each other ?
6. Does it support graphql files or graphql tag ?
7. What is the role of the gateway ?
8. Does it support subscriptions ?
A Node is designed to modularize a ObjectTypeDefinition together with its related resolvers & properties. You can think of a node as a module.
`javascript
const User = new GraphQLNode({
name: "User",
typeDefs:
type User ...
type Query {
getUser: User
}
,`
resolvers: {
Query: {
getUser: (root, args, ctx) => { ... }
}
}
});
> You can compose nodes
`javascript
const Comment = new GraphQLNode({
name: "Comment",
...
});
const Post = new GraphQLNode({
name: "Post",
nodes: [ Comment ],
...
});
const User = new GraphQLNode({
name: "User",
nodes: [ Post ]
...
});
`
> Is it all about nodes ? There are plenty of classes to help you construct your GraphQL schema start reading about schemaAppliances here.
The result of makeExecutableSchema is returned from combineNodes & GraphQLSchema.
Using combineNodes
`javascript
const { typeDefs, resolvers } = combineNodes(nodes);
const apolloServer = new ApolloServer({ typeDefs, resolvers });
`
Using GraphQLGateway
`javascript
const gateway = new GraphQLGateway(
{
services: {
nodes: ["User"]
}
},
{
transporter: "redis://localhost",
nodeID: "gateway"
}
);
const { typeDefs, resolvers } = await gateway.start();
const apolloServer = new ApolloServer({ typeDefs, resolvers });
`
> Watch tutorial here
This package builds its microservices features on top of a package Molecular, this means you can integrate with Moleculer's features. Learn more about using microservices here.
> Molecular is a optional dependency
`javascript
const User = new GraphQLNode({
name: "User"
});
await User.serve({
transporter: "nats://localhost"
});
`
> Do not forget to create your gateway
#### Gradual Adoption
You don't need have to have all your nodes as a service. You can have some nodes hosted on the same instance as the gateway. Use locals & services in GraphQLGateway to merge all nodes together. Read more about gradual adoption here.
You can use a IdioDirective and apply it at combineNodes or GraphQLGateway.
`javascript ...
const MyDirective = new IdioDirective({
name: "...",
typeDefs: ,
resolver: SchemaDirectiveVisitor
});
const { typeDefs, resolvers, schemaDirectives } = combineNodes(nodes, { directives: [MyDirective] });
`
Inter-Schema Execution can be used to make GraphQL powered Queries & Mutations against your own or specified schema.
> Inter-Schema Execution works with your served nodes, this will allow you to accomplish GraphQL powered service-service communication.
`javascript
const Post = new GraphQLNode({
name: "Post",
typeDefs:
type Post {
title: String
}
type Query {
posts: [Post]
}
,
resolvers: { ... }
});
const User = new GraphQLNode({
name: "User",
typeDefs:
type User {
posts: [Post]
}
,
resolvers: {
Fields: {
posts: async (root, args, { injections }) => {
const { data, errors } = await injections.execute(
query {
posts {
title
}
}
);
return data.posts;
}
}
}
});
`
You can use; strings, graphql-tag or file pathsWhat is the role of the gateway ?
Remember the initial schema & keep track of services with the corresponding names. Produce a Graphql schema after introspecting each supplied service.>
GraphQLGateway acts as a reverse proxy when using Inter-Schema execution.Your gateway will;
1. Not throw if it loses connection to a service
2. Allow unlimited services, with the same name, to join the swarm
3. Load balance requests to each service
4. Not start until all services are connected
5. Ensure no other gateway has the same name but different schema
> You can spawn multiple instances of the same gateway
Does it support subscriptions ?
You can setup subscriptions in a node. Subscriptions will work with microservices.`javascript
const User = new GraphQLNode({
name: "User",
typeDefs: type Subscription {
userUpdate: User
}
,`
resolvers: {
Subscription: {
userUpdate: {
subscribe: async function* (){} // AsyncGenerator
}
}
}
});
> Subscriptions will not work service-service communication.
$ npm install idio-graphql apollo-server graphql-tag
``javascript
const {
combineNodes,
GraphQLNode
} = require("idio-graphql");const { ApolloServer } = require("apollo-server");
const gql = require("graphql-tag");
const User = new GraphQLNode({
name: "User",
typeDefs: gql
type Query {
user(id: ID!): User
}
,
resolvers: {
Query: {
user: (parent, { id }) => { ... }
}
}
});
async function main() {
const { typeDefs, resolvers } = combineNodes([ User ]);
const server = new ApolloServer({ typeDefs, resolvers });
await server.listen(4000);
console.log(http://localhost:4000/graphql);
}
main();
`Microservices Quick Start
> Requires nats-server @ nats://localhost:4222
``
$ npm install idio-graphql apollo-server graphql-tag moleculer nats
`javascript
const gql = require("graphql-tag");
const { GraphQLNode } = require("idio-graphql");
const User = new GraphQLNode({
name: "User",
typeDefs: gql
type User {
id: String
name: String
age: Int
}
type Query {
user(id: String!): User
}
,
resolvers: {
Query: {
user: (root, { id }) => { ... }
}
}
});
await User.serve({
gateway: "gateway",
transporter: "NATS"
});
`
`javascript
const { ApolloServer } = require("apollo-server");
const { GraphQLGateway } = require("idio-graphql");
const gateway = new GraphQLGateway(
{ services: { nodes: ["User"] } },
{
transporter: "NATS",
nodeID: "gateway"
}
);
const { typeDefs, resolvers } = await gateway.start();
const server = new ApolloServer({
typeDefs,
resolvers
});
await server.listen(4000);
``