A realworld app micro-services implementation, using the following tech stack:
- NX.dev Monorepo
- Nest.js for BE services
- Mongoose using
@nestjs/mongoosemodule for persistence - GraphQL using
@nestjs/graphqlmodule for gateway GraphQL API - Auth with passport-jwt using
@nestjs/jwtand@nestjs/passportmodules - Global config using
@nestjs/configmodule - Swagger OpenAPI route documentation using
@nestjs/swaggermodule - TypeScript
- MongoDB - for service persistence layer running in a docker container
- Redis - Queue implementation over Bull and Redis as a service message bus using
@nestjs/bull
- Run
yarn predeployto build services and create docker containers - Run
docker-compose upto start containers - Create the mongo db: SSH into the mongo container:
docker exec -it realworld-mongo sh
Once SSHed into it:
mongo
use realworld
quit()
- Use PostMan exported collection
realworld.postman_collection.jsonfor calling APIs - Use Apollo Studio and point the sandbox to
http://localhost:3330/graphqlfor executing GraphQL queries and Mutations. - Run
nx serve frontendif you would like to use the (not complete) frontend application.
feature-useris responsible for/api/userfunctionality and endpoints.feature-tagis responsible for/api/tagsfunctionality and endpoints.feature-profileis responsible for/api/profiefunctionality and endpoints.feature-articleis responsible for/api/articlesfunctionality and endpoints.
All feature services expose OpenApi Swagger definitions under the /api route.
realworld-examples-appis the GraphQL gateway for the above services. Code-First GraphQL autogenerated schema is saved underschema.graphql.
The playground is accessible via Apollo Studio, point the sandbox to http://localhost:3330/graphql.
For example, getting the current logged-in user details, along with her feed and the list of articles she wrote (with comments for each article returned in feed/articles if they exist):
fragment userFragment on User {
_id
email
username
}
fragment articleFragment on Article {
_id
body
description
favoritesCount
tagList
title
comments {
_id
body
author {
...userFragment
}
}
author {
...userFragment
}
}
query {
me {
...userFragment
feed {
...articleFragment
}
articles {
...articleFragment
}
}
}
For using the GraphQL gateway with authenticaed routes:
- First call the login mutation with
username(email) andpassword-> get theaccess_token. - Add
{"token": <JWT token>}to the headers.
See data-access lib for predefined Queries, Mutations and Fragments and their respective autogenerated Types and React hooks.
Feature services and the GraphQL gateway use the following libs:
authis responsible for user login and issueing the JWT token, as well as exporting theJwtAuthGuardused on protected routes in all feature services.modelsexposes DTOs and ENUMs used by feature services.sharedexposes reusable services used by feature services.data-accessexposes auto-generated types and react hooks based on schema types and queries/mutations. Generated code is the result of runningyarn codegenoryarn codegen:watch. Codegen config iscodegen.yaml.
We use Redis as the queue persistence layer and Bull & @nestjs/bull for the queue implementation.
The purpose of this is for feature services to be able to notify something happened in the system, and other feature services can react and complete the flow.
One flow that uses this is:
- User creates an article, with
tagListthat includes some new tags and some existing tags feature-articleservice publishes a message with thetagListon theEvaluateTagstopic to theTagsqueue and saves the new article.feature-tagimplements a consumer that processes messages under theEvaluateTagstopic on theTagsqueue and creates the new tags in DB.
Another exaple is:
- User is created or updated
feature-userservice publishesuserUpdatedevent on theUsersqueue and saves the new/updated user.feature-profileservices implements aUserConsumerconsumer that processes messages underuserUpdatedtopic on theUsersqueue and creates/updates the relevant profile in DB.
See Real World App spec here.
