Implementing a good GraphQL backend to serve your database data is not an easy task, you have to implement a lot of resolvers, add authorization, pagination of the fields and use a DataLoader to not repeat your database queries during relations.
It also becomes boring after some time, especially if you do a lot of side projects with the same stack like me, you have to implement the same basically service for every project.
But i am super lazy and i wanted a reusable, fast way to build my graphql backend, so i built mongoke (https://github.com/remorses/mongoke)
Mongoke is a docker image that generates the GraphQL API to serve your Mongodb data.
It can be used directly from the frontend as it supports authorization via your
jwt
, it also can be composed with other services using Apollo Federation
(so for example you can handle the mutations in a different service).Let's create an example, a basic blog app with 2 collections: users and posts
schema: |
type User {
_id: ObjectId
username: String
email: String
}
type BlogPost {
_id: ObjectId
author_id: ObjectId
title: String
content: String
}
types:
User:
collection: users
BlogPost:
collection: posts
relations:
- field: posts
from: User
to: BlogPost
relation_type: to_many
where:
author_id: ${{ parent['_id'] }}
Here i defined the database schema with the User and BlogPost types, then i defined the associations between the types and the collections and finally i defined a to_many relation from User to BlogPost.
To deploy the above configuration we can use docker-compose
# docker-compose.yml
version: '3'
services:
mongoke:
ports:
- 4000:80
image: mongoke/mongoke
environment:
DB_URL: mongodb://mongo/db
volumes:
- ./mongoke.yml:/conf.yml
mongo:
image: mongo
logging:
driver: none
The mongoke service generates the boilerplate code every time the service starts, you can go to http://localhost:4000/graphiql to open graphiql.
An example query you can make:
{
user(where: {username: {eq: "Mike"}}) {
_id
username
email
posts {
nodes {
title
}
}
}
blogPosts(first: 10, after: "Post 1", cursorField: title) {
nodes {
title
content
}
pageInfo {
endCursor
hasNextPage
}
}
}
Give me your thoughts in the comments and leave a star on github, thanks for reading!