Skip to content

Instantly share code, notes, and snippets.

@rafaell-lycan
Created November 4, 2019 11:06
Show Gist options
  • Save rafaell-lycan/b7586e41085ae5ae409d04bb679c0ee9 to your computer and use it in GitHub Desktop.
Save rafaell-lycan/b7586e41085ae5ae409d04bb679c0ee9 to your computer and use it in GitHub Desktop.
Node Microservice architecture example

Node Microservice architecture example

Just another proof of concept about how build distributed applications.


About the project

This is a quite simple application where we can create a rest API based on an initial CSV file provided by the user.

Technologies

  • Node ( >= 8.x) + Typescript
  • Express - Web server
  • MongoDB - to store data from our services (Provided by Scalingo)
  • Redis - as a queue based (Provided by Scalingo)
  • Swagger - For API documentation
  • Heroku - As our cloud platform

Microservice structure

Each module has a Core, which contains entities that are basically business rules. Also we have a service layer to handle everything that isn't related to the Core such validations, resources and so on. By providing an output such as api we'll have the normal bits such an application server and it routes+controllers with the only difference to handle logic with use cases instead, to avoid put garbage on our controllers that shouldn't know anything about our application. Finally we have our repositories, which will deal with persistence through our services and use cases.

A basic service

├── api # API specifics such web server, routes, etc.
├── common # Helpers & Utilities
├── config # Configuration
├── core # Where the business logic lives
│   ├── entities # Our domain classes
│   └── usecases # Our business rules
├── repositories # Our persistence layer
└── services # Our service layer

A simple example

// index.js
(async () => {
  const config = require('config');
  const App, { AppConfig } = require('/Application');

  // Load the configuration
  const appConfig: AppConfig = config.get('application')
  const repoConfig: DatabaseSettings = config.get('database');

  // Add repository
  const repository: Repository = require('/repositories/TaskRepository');

  const app: App = new App({
    ...appConfig,
    repository: new repository(repoConfig)
  });

  // Add use cases to event listeners
  events.on('add_task', require('/usecase/AddTask').['add']);

  // Start the application
  await app.start();

  return app;
})();
// usecase/AddTask.js
const Task = require('/entities/Task');
const Application = require('/Application');

class AddTask {
  async add(entity: Task): Task| AppError {
    const task: Task = new Task(entity);

    if(task.isValid()) {
      await Application.repository.save(task);
      return task;
    }

    throw new Error(...)
  }
}
// entities/Task.js

class Task {
  constructor(public title: string = '') {}

  isValid(): boolean {
    return this.title && this.title.trim();
  }
}
// repositories/TaskRepository.js

class TaskRepository extends Read<Task>, Write<Task> {
  constructor(private db: DatabaseSettings) {}

  getAll() { ... }

  save() { ... }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment