idio-graphql
v4.0.3
Published
Node.js library for splitting SDL first GraphQL schemas into composable & idiomatic chunks.
Downloads
215
Maintainers
Readme
idio-graphql
This package is inspired by; Apollo Federation, GraphQL Modules & Moleculer.
About
Node.js library for splitting SDL first GraphQL schemas into composable & idiomatic chunks.
Installation
$ npm install idio-graphql
⚠ graphql
is a peerDependency you may need to install this too.
$ npm install graphql
Usage
const User = new GraphQLNode({
name: "User",
typeDefs: `
type User {
id: ID
name: String
age: Int
}
type Query {
user(id: ID!): User
}
`,
resolvers: {
Query: {
user: () => ...
}
}
});
const { typeDefs, resolvers } = combineNodes([ User ]);
const server = new ApolloServer({ typeDefs, resolvers });
Index
Examples
- Monolith
- Microservice
- Mini examples - Some smaller examples to help demonstrate the capability's of this package.
FAQ
- What is a node ?
- How do I integrate with my Apollo Server ?
- How do I get started with microservices ?
- Can I use Schema Directives ?
- How can my nodes talk with each other ?
- Does it support graphql files or graphql tag ?
- What is the role of the gateway ?
- Does it support subscriptions ?
What is a node ?
A Node is designed to modularize a ObjectTypeDefinition together with its related resolvers & properties. You can think of a node as a module.
const User = new GraphQLNode({
name: "User",
typeDefs: `
type User ...
type Query {
getUser: User
}
`,
resolvers: {
Query: {
getUser: (root, args, ctx) => { ... }
}
}
});
You can compose nodes
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.
How do I integrate with my Apollo Server ?
The result of makeExecutableSchema
is returned from combineNodes
& GraphQLSchema
.
Using combineNodes
const { typeDefs, resolvers } = combineNodes(nodes);
const apolloServer = new ApolloServer({ typeDefs, resolvers });
Using GraphQLGateway
const gateway = new GraphQLGateway(
{
services: {
nodes: ["User"]
}
},
{
transporter: "redis://localhost",
nodeID: "gateway"
}
);
const { typeDefs, resolvers } = await gateway.start();
const apolloServer = new ApolloServer({ typeDefs, resolvers });
How do I get started with microservices ?
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
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.
Can I use Schema Directives ?
You can use a IdioDirective and apply it at combineNodes
or GraphQLGateway
.
const MyDirective = new IdioDirective({
name: "...",
typeDefs: ` ... `,
resolver: SchemaDirectiveVisitor
});
const { typeDefs, resolvers, schemaDirectives } = combineNodes(nodes, { directives: [MyDirective] });
How can my nodes talk with each other ?
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.
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;
}
}
}
});
Does it support graphql files or graphql tag ?
When specifying typedefs
You can use; strings, graphql-tag or file paths
What 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;
- Not throw if it loses connection to a service
- Allow unlimited services, with the same name, to join the swarm
- Load balance requests to each service
- Not start until all services are connected
- 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.
const User = new GraphQLNode({
name: "User",
typeDefs: `
type User ...
type Subscription {
userUpdate: User
}
`,
resolvers: {
Subscription: {
userUpdate: {
subscribe: async function* (){} // AsyncGenerator
}
}
}
});
Subscriptions will not work service-service communication.
Quick Start
$ npm install idio-graphql apollo-server graphql-tag
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 User {
id: ID
name: String
age: Int
}
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
User Service
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"
});
Gateway Service
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);