This codebase was created to demonstrate a distributed GraphQL schema built with idio-graphql including modules, authentication, pagination, and more.
There is a React frontend that works with this system here
Docker is the best way to start
- Setup Environment Variables
docker-compose up
- Start client here
To start, copy
./.env.example
, in each service, to./.env
.
NATS_URL=nats://host.docker.internal:4222
PORT=3000
MONGODB_URI=mongodb://host.docker.internal:27017/Conduit
DEBUG=@Conduit-Gateway-Service:*
SECRET=supersecret
NODE_ENV=develop
NATS_URL=nats://host.docker.internal:4222
MONGODB_URI=mongodb://host.docker.internal:27017/Conduit
DEBUG=@Conduit-Article-Service:*
NODE_ENV=develop
NATS_URL=nats://host.docker.internal:4222
MONGODB_URI=mongodb://host.docker.internal:27017/Conduit
DEBUG=@Conduit-Comment-Service:*
NODE_ENV=develop
The foundations of this schema were ported from rails-graphql-realworld-example-app, although changes have been made, both for simplicity & to lean on features provided by idio-graphql
such as Inter-Schema Execution.
Graphs generated from Graphql Voyager available @ http://localhost:3000/voyager
directive @Auth(input: AuthInput) on FIELD_DEFINITION
input AddCommentInput {
articleId: ID!
body: String!
}
type AddCommentPayload {
comment: Comment
errors: [UserError!]!
}
type Article {
id: ID!
author: User!
body: String!
comments: [Comment!]!
description: String!
favoritesCount: Int!
slug: String!
tagList: [String!]!
title: String!
viewerHasFavorited: Boolean!
updatedAt: DateTime!
createdAt: DateTime!
}
type ArticleConnection {
edges: [ArticleEdge]
pageInfo: PageInfo!
}
type ArticleEdge {
cursor: String!
node: Article
}
input AuthInput {
required: Boolean!
populate: Boolean = false
}
type Comment {
id: ID!
article: Article
author: User
body: String!
createdAt: DateTime!
updatedAt: DateTime!
}
input CreateArticleInput {
title: String!
description: String!
body: String!
tagList: [String!]!
}
type CreateArticlePayload {
article: Article
errors: [UserError!]!
}
input CreateUserInput {
username: String!
email: String!
password: String!
}
type CreateUserPayload {
errors: [UserError!]!
user: User
}
scalar DateTime
input DeleteArticleInput {
id: ID!
}
type DeleteArticlePayload {
article: Article!
}
input DeleteCommentInput {
id: ID!
}
type DeleteCommentPayload {
comment: Comment
}
input FavoriteArticleInput {
id: ID!
}
type FavoriteArticlePayload {
article: Article
}
type FollowersConnection {
totalCount: Int!
nodes: [User]
}
input FollowUserInput {
id: ID!
}
type FollowUserPayload {
user: User
}
type Mutation {
addComment(input: AddCommentInput!): AddCommentPayload
deleteComment(input: DeleteCommentInput!): DeleteCommentPayload
createUser(input: CreateUserInput!): CreateUserPayload
signInUser(input: SignInUserInput!): SignInUserPayload
followUser(input: FollowUserInput!): FollowUserPayload
unfollowUser(input: UnfollowUserInput!): UnfollowUserPayload
updateUser(input: UpdateUserInput!): UpdateUserPayload
pushFavoriteArticle(article: ID!): User
pullFavoriteArticle(article: ID!): User
createArticle(input: CreateArticleInput!): CreateArticlePayload
deleteArticle(input: DeleteArticleInput!): DeleteArticlePayload
updateArticle(input: UpdateArticleInput!): UpdateArticlePayload
favoriteArticle(input: FavoriteArticleInput!): FavoriteArticlePayload
unfavoriteArticle(input: UnfavoriteArticleInput!): UnfavoriteArticlePayload
}
type PageInfo {
endCursor: String
hasNextPage: Boolean
}
type Query {
articleComments(article: ID!): [Comment]
user(username: String!): User
userById(id: ID!): User
articleUserFavoriteCount(article: ID!): Int
article(slug: String!): Article
articleById(id: ID!): Article
tags: [String!]!
viewer: Viewer
articles(first: Int = 10, after: String = "1", tag: String, forUser: Boolean, feed: Boolean, ids: [String]): ArticleConnection!
}
input SignInUserInput {
email: String!
password: String!
}
type SignInUserPayload {
errors: [UserError!]!
token: String
viewer: Viewer
}
input UnfavoriteArticleInput {
id: ID!
}
type UnfavoriteArticlePayload {
article: Article
}
input UnfollowUserInput {
id: ID!
}
type UnfollowUserPayload {
user: User
}
input UpdateArticleInput {
id: ID!
title: String!
description: String!
body: String!
tagList: [String!]!
}
type UpdateArticlePayload {
article: Article
errors: [UserError!]!
}
input UpdateUserInput {
email: String!
username: String!
bio: String
image: String
password: String
}
type UpdateUserPayload {
errors: [UserError!]!
user: User
}
type User {
id: ID!
image: String
username: String!
bio: String
email: String!
followedByViewer: Boolean!
articles(first: Int = 10, after: String = "1"): ArticleConnection!
favoriteArticles(first: Int = 10, after: String = "1"): ArticleConnection!
followers: FollowersConnection!
following: FollowersConnection!
}
type UserEdge {
cursor: String!
node: User
}
type UserError {
message: String!
path: String
}
type Viewer {
feed(first: Int, after: String): ArticleConnection!
user: User
}
Its recommended to run all test's in Docker
You can run this projects test suite with $ npm run test-docker
.