/typescript-clean-architecture

This is an example of my clean architecture implementation on TypeScript

Primary LanguageTypeScriptApache License 2.0Apache-2.0

README

Game Store is an example of a TypeScript microservice that tries to respect the SOLID principles and the Clean Architecture.

Project Structure

  • @entities: enterprise business rules
  • @use-cases: application business rules
  • @interfaces: interfaces adapters (API, web GUI, cli, brokers & everything communicating from outside)
  • @frameworks: all external dependencies (libraries, database, interfaces frameworks etc...)
  • di: here we instanciate everything only with Pure DI

Dependency (inversion) workflow: @frameworks -> @interfaces -> @use-cases -> @entities

How do I get set up?

Tools dependencies

Add secrets env

Create a .env.dev.local file at the root of the project using a valid LogDNA API Key:

LOGGER_API_KEY=xxxxxxxxxxxxx

Initial setup

Build project:

yarn install && yarn build

Initialize database:

docker-compose up postgresql
env $(cat .env.dev .env.dev.local | grep -v "#" | xargs) yarn db:migrate:latest
env $(cat .env.dev .env.dev.local | grep -v "#" | xargs) yarn db:seed

How do I run it?

Run it for use

docker-compose up

Run it for development

Start postgresql & kubemq & adminer services:

docker-compose up postgresql kubemq adminer

Start app (with auto-reloading):

yarn dev

Run worker (without auto-reloading):

yarn build && env $(cat .env.dev .env.dev.local | grep -v "#" | xargs) yarn worker:updateGameReadCount

Tests

Unit tests:

yarn test

Database

Create a database migration:

db:migrate:make

Broker Workflow

To illustrate a microservice interaction workflow with a broker, we also implemented this:

  • ViewGameInteractor, ViewLibraryInteractor and ViewStoreInteractor which are responsible to return games will emit an app event display_game for each game
  • DisplayGameListener is listening to display_game event and will publish a broker event event.game_displayed each times it's triggering
  • GameDisplayedSubscriber is subscribing to broker event event.game_displayed and will add a job to broker queue queue.update_game_read_count
  • UpdateGameReadCountWorker si receiving broker queue jobs queue.update_game_read_count:
    • Wait for a response to broker command request commands.get_game_read_count
    • update the game.readCount property through GameRepository
  • GetGameReadCountReceiver is receiving broker command commands.get_game_read_count and send back a random value between 1 and 1000

To trigger this workflow, just request GET api routes returning games (readCount will change everytime)

TODOLIST

  • Write full test per layer (entities/use-cases/interfaces), also check PyramidTest
  • Add a @interfaces/web to implement vue/react web app
  • switch from kubemq-node to kubemq-js library