granate
v1.10.0
Published
Granate container for annotated GraphQL
Downloads
27
Maintainers
Readme
granate
Granate container for annotated GraphQL
Introduction
GraphQL is an amazing technology that allows to build application APIs in a much better way than by implementing REST services. On top of this, GraphQL can be defined using a textual representation (schema language) which offers a lot of really useful possibilities. Granate leverages these possibilities.
Usage
To understand better how to use granate, please have a look at the examples in granate-showcase
Installation
In order to use granate from the CLI, install granate-cli with the following command:
> npm i -g granate-cli
If you prefer to use granate as an API, install granate and graphql (peer dependency of granate) in your application with the following command:
> npm i granate graphql --save
Where does granate come from? (TL;DR)
Imagine that you want to implement a Todo application and you have drafted a GraphQL schema which looks as follows:
# Domain entity which represents a Todo object
type Todo {
id: ID!
title: String!
completed: Boolean!
}
# Query model for Todos
type Query {
# Returns the collection of Todos filtered by completed status (optional)
todos(completed: Boolean): [Todo]
}
# Mutations for Todos
type Mutation {
# Adds an uncompleted Todo with the given description
addTodo(title: String!): Todo!
# Removes a Todo by id
removeTodo(id: ID!): Todo!
# Toggles the completed state of a Todo by id
toggleTodo(id: ID!): Todo!
}
As of [email protected], by
using the buildSchema()
and graphql()
functions together with an object like the one below as
rootValue
, it is then possible to execute GraphQL queries and mutations against the object as if it were a
full-fledged GraphQL endpoint.
export class Todos {
constructor() {
this.nextId = Date.now();
this.todos = [];
}
todos({completed}) {
return this.todos.filter(completedFilter);
function completedFilter(todo) {
return completed === undefined ? todo : todo.completed === completed;
}
}
addTodo({title}) {
const todo = {
id: String(this.nextId++),
title,
completed: false
};
this.todos.push(todo);
return todo;
}
removeTodo({id}) {
const todo = this.todos.filter(todo => todo.id === id)[0];
todos.splice(this.todos.indexOf(todo), 1);
return todo;
}
toggleTodo({id}) {
const todo = this.todos.filter(todo => todo.id === id)[0];
todo.completed = !todo.completed;
return todo;
}
}
Then you can use this as:
import { buildSchema } from 'graphql';
import { Todos } from './todos';
const schemaText = `
# Domain entity which represents a Todo object
type Todo {
... content skipped
`;
const query = `
{
todos {
title
completed
}
}`;
const todos = new Todos();
graphql(buildSchema(schemaText), query, todos).then(result => console.log(result)); // prints the query result
And if you want to make this API available through HTTP:
import express from 'express';
import graphqlHTTP from 'express-graphql';
import { buildSchema } from 'graphql';
import { Todos } from './todos';
const PORT = 4000;
const schemaText = `
# Domain entity which represents a Todo object
type Todo {
... content skipped
`;
const todos = new Todos();
const graphqlHTTPConfig = createGraphQLHTTPConfig(buildSchema(schemaText), todos);
express()
.use('/graphql', graphqlHTTP(graphqlHTTPConfig))
.listen(PORT, () => console.log(`Listening on port: '${PORT}'...`));
function createGraphQLHTTPConfig(schema, rootValue) {
return {
schema,
rootValue,
graphiql: true
};
}
Wouldn't it be cool if we could avoid defining the rootValue
implementation and use instead mock data like the one
generated by casual or faker.js?
This would allow to mock an API just by using a GraphQL schema text file.
Well, we easily can if we use the package graphql-tools
as explained in Mocking your server with just one line of code.
- But, wouldn't it be better if we could start with a schema file and default mock data and incrementally
refine the mock data or even the implementation to use as
rootValue
? - And what if we could use mock data where the root value provides no implementation?
- Couldn't we eventually use a legacy REST API to implement part of the schema?
- And if we could reuse not only existing REST APIs but also GraphQL endpoints?
- Even better, what if I could just install a library and do all this from the CLI without writing any code?
###... enter Granate!