Example of Relay Cursor Connections with MongoDB and Apollo Server 2. Ported from reindexio/graphql-relay-mongodb-pagination that provided the code accompnaying the article Relay-compatible GraphQL pagination with MongoDB.
The example has been enhanced so that the ArticleConnection
objects
also support a nodes
object like GitHub's GraphQL API does.
Also added are mutation and subscription with redis examples.
Install npm dependencies:
yarn install
Start MongoDB and redis (unless you have them running locally already):
docker-compose up mongodb redis
Load sample data directly into MongoDB:
yarn load:mongo
This will load 1,000 articles into the Articles
collection of the
relaypagination
database.
Install MongoDB Compass:
brew cask install mongodb-compass
Start the server:
yarn start:dev
Install GraphQL Playground:
brew cask install graphql-playground
Here is the text for the query highlighted in the screenshot:
query Last {
viewer {
id
}
articles(last: 2) {
nodes {
text
}
edges {
cursor
node {
text
id
createdAt
updatedAt
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
{
viewer {
id
username
articles(last: 2) {
nodes {
id
text
}
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
}
}
}
{
"data": {
"viewer": {
"id": "5e00fcad8700880af081ab7b",
"username": "janesmith",
"articles": {
"nodes": [
{
"id": "5e00fcad8700880af081ab8f",
"text": "19 - Corporis voluptates magnam inventore sunt non itaque molestias."
},
{
"id": "5e00fcad8700880af081ab90",
"text": "20 - Sed harum nostrum nobis dolorum nesciunt."
}
],
"pageInfo": {
"startCursor": "NWUwMGZjYWQ4NzAwODgwYWYwODFhYjhm",
"endCursor": "NWUwMGZjYWQ4NzAwODgwYWYwODFhYjkw",
"hasNextPage": false,
"hasPreviousPage": true
}
}
}
}
}
This repository contains an example of calling a mutation with the graphql-request to load sample data:
You can run this script with the following command:
yarn load:apollo-client
Here is an example of using graphql-request
to add a single article.
import { request } from 'graphql-request';
const endpoint = 'http://localhost:4001/graphql';
const query = `
mutation AddArticle($article:AddArticleInput!) {
addArticle(input:$article){
article{
id
text
createdAt
updatedAt
}
}
}
`;
const variables = {
article: {
text: 'graphql-request mutation',
},
};
// using request
//
request(endpoint, query, variables)
.then(data => console.log(JSON.stringify(data, undefined, 2)))
.catch(error => console.error(error));
There are two mutations in the GraphQL schema that perform file uploads,
singleUpload
and multipleUpload
. The following scripts can be used
to test singleUpload
and multipleUpload
respectively:
scripts/singleUpload.sh
scripts/multipleUpload.sh
$ scripts/singleUpload.sh | jq
{
"data": {
"singleUpload": {
"filename": "yarn.lock",
"mimetype": "application/octet-stream",
"encoding": "7bit"
}
}
}
$ scripts/multipleUpload.sh | jq
{
"data": {
"multipleUpload": [
{
"filename": "package.json",
"mimetype": "application/octet-stream",
"encoding": "7bit"
},
{
"filename": "nodemon.json",
"mimetype": "application/octet-stream",
"encoding": "7bit"
}
]
}
}
This project uses redis for subscriptions by utilizing the
davidyaha/graphql-redis-subscriptions
PubSub
implementation.
Open two terminal windows and run
docker compose up --build
in one andyarn start:dev
in the other. This will result in two instances of the Node.js GraphQL server running.
docker-compose up --build
yarn start:dev
Now open two GraphQL Playgroud IDE
instances. One to http://localhost:4001/graphql
and
the other to http://localhost:4001/graphql
.
Note that the Node.js graphql app running on port
4002
(fromdocker-compose
) does not supportplayground
sinceNODE_ENV
is set to production. Thus the use of theGraphQL Playground IDE
client.
In the first GraphQL Playground IDE
instance enter this query and execute it:
subscription Articles {
articleAdded {
id
text
createdAt
updatedAt
}
}
In the second GraphQL Playground
instance enter and execute this query:
mutation AddArticle($article: AddArticleInput!) {
addArticle(input: $article) {
article {
id
text
createdAt
updatedAt
}
}
}
With query variables
:
{
"article": {
"text": "hello there"
}
}
Montioring subscriptions with redis-cli
:
$ redis-cli
127.0.0.1:6379> monitor
OK
1576084903.219562 [0 172.27.0.1:45834] "unsubscribe" "ARTICLE_ADDED"
1576084903.219608 [0 172.27.0.1:45834] "punsubscribe" "ARTICLE_ADDED"
1576084905.559995 [0 172.27.0.1:45834] "subscribe" "ARTICLE_ADDED"
1576084910.945354 [0 172.27.0.1:45830] "publish" "ARTICLE_ADDED" "{\"articleAdded\":{\"text\":\"hello there\",\"createdAt\":\"2019-12-11T17:21:50.919Z\",\"updatedAt\":\"2019-12-11T17:21:50.919Z\",\"_id\":\"5df125ae87f96d1c3a7d25bc\"}}"
The docker-compose.yaml
file will by default build and use a container
for the Node.js app. This can be time consuming during development.
Running docker-compose up mongodb
will just start a MongoDB container
that can be used with yarn start:dev
during development.
To start the Node.js app and MongoDB together do:
docker-compose up --build
It is important to include --build
if there have been changes to the
source code.
The Node.js app is available on localhost:4002
when running via docker-compose
. Note that the playground is not available
as the environment is set as production. Use
GraphQL Playground
to interact with GraphQL in this case.
Node.js doesn't like running as pid 1. Use --init
with docker run
or Tini if your containers are headed
to Kubernetes, since the --init
flag isn't supported there.
- Relay-compatible GraphQL pagination with MongoDB
- Apollo Server 2
- Avoid running NodeJS as PID 1 under Docker images
- GraphQL Playground IDE
- jaydenseric/apollo-upload-examples
- jaydenseric/graphql-upload
- nowke/realtime-dashboard-demo
- redis-cli, the Redis command line interface
- Relay Cursor Connections
- Tini - A tiny but valid init for containers
- What is advantage of Tini?