Skip to content

GalBitton/Messages-CRUD-RestAPI

Repository files navigation

Messages-CRUD-RESTAPI

Visit Root Page: Messages-CRUD-RESTAPI Root page

Visit Swagger API Docs: Messages-CRUD-RESTAPI Swagger API docs


Introduction


This project is a simple Node.js REST API that allows users to manage messages.
Each message is analyzed to check if it's a palindrome.
The service includes full CRUD operations:

  • Create a message
  • Retrieve a message
  • Update a message
  • Delete a message
  • List all messages

Everything is built using a modular architecture. This means that the code is organized into separate modules, each responsible for a specific part of the application.
Every layer has its job - routes, controllers, services, repositories, and models.
This makes it easier to maintain and extend the codebase in the future.


Table of Contents



Features

  • Simple REST API with full CRUD operations support
  • Checks if a message is a palindrome
  • MongoDB or In-memory storage (configurable)
  • Uses Dependency Injection for better testability and modularity
  • Full test coverage with Mocha, Chai, Sinon and Supertest
  • Docker support for easy deployment and local running
  • GitHub Actions for CI/CD
  • Swagger documentation for API endpoints
  • Deployed to Railway Cloud Provider

Architecture

As mentioned earlier, the project is built using a modular architecture.
In the picture below you can see the different layers of the application and how they interact with each other. Architecture


Design Patterns

In this section, I will explain the design patterns used:

  • Dependency Injection Pattern
    Instead of manually creating dependencies everywhere, the app uses the kontainer-di library (see src/container.js) to manage all dependencies in one place. This makes the code easier to test and keeps everything loosely coupled.
  • Controller-Service-Repository Pattern
    Repository's layer is a (DAL - Data Access Layer), provides an additional layer to classic Controller-Service model as following:
    • Controller - Handles incoming HTTP requests (e.g., from the client), and calls the relevant service.
    • Service - Contains the actual business logic (like creating a message or checking if it’s a palindrome), and creates the Message entity.
    • Repository - Talks to the database. It abstracts how data is stored or retrieved, so the service doesn’t need to know which database is in use.
  • Factory Pattern (via Container)
    Using the container, we can easily "swap" or create different object instances depending on the environment – for example, switching between a MongoDB connection or an In-Memory database. This gives flexibility without changing core logic.
  • Base Class Pattern (Generic,Template methods)
    The project uses base classes to promote code reuse and enforce a consistent structure across layers.
    These are similar to the Template Method Pattern in design:
    • BaseRepository: Provides shared CRUD operations (create,findAll,findById,update,delete). The MessageRepository simply extends it and passes in the correct database and schema.
    • BaseCrudService: Encapsulates common service-level logic. MessageService inherits it and overrides only what’s necessary (like the create and update methods to handle Message entity logic).
    • BaseSchema: A key abstraction for different data storage schemas.
    • BaseController and BaseDatabase also serve as a foundational layers for extension.

Tech Stack

  • Node.js
  • Express.js
  • MongoDB + Mongoose + In-memory storage
  • Joi for validation
  • Docker
  • Mocha, Chai, Sinon, Supertest for testing
  • Swagger for API documentation
  • Dependency Injection with kontainer-di
  • GitHub Actions for CI/CD
  • Railway for deployment

How to Run

Prerequisites

  • Node.js (v18 or higher)
  • MongoDB (if using MongoDB storage)
  • Docker (if using Docker)
  • Git
  • npm or yarn
  • Postman or any other API testing tool

Clone the repository

npm install
npm start

Run with Docker

docker build -t <your-image-name> .
docker run -d -p <port>:<port> --env-file .env <your-image-name>

for example:

docker build -t messages-api .
docker run -d -p 8080:8080 --env-file .env messages-api

Open your browser and go to http://localhost:8080 to see the API in action.
You can also use Postman or any other API testing tool to test the endpoints. for example:

# If you want to create a new message, use the following command:
curl -X POST http://localhost:8080/api/v1/messages -H "Content-Type: application/json" -d '{"content": "your message"}'

# To list all messages, use the following command:
curl -X GET http://localhost:8080/api/v1/messages

# To get a message by ID, use the following command:
curl -X GET http://localhost:8080/api/v1/messages/<message-id>

# To update a message, use the following command:
curl -X PUT http://localhost:8080/api/v1/messages/<message-id> -H "Content-Type: application/json" -d '{"content": "your message"}'

# To delete a message, use the following command:
curl -X DELETE http://localhost:8080/api/v1/messages/<message-id>

Generating JSdoc

To generate the documentation, run the following command:

npm run docs
# You can find the generated documentation in the src/docs folder.
# Open the index.html file in your browser to view the documentation for better readability and understanding.

API Endpoints

All the endpoints are documented using Swagger. You can access the documentation at http://localhost:8080/api-docs after running the server.

Base URL/api/v1/messages

Method Endpoint Description
GET / List all messages
GET /:id Retrieve a message by ID
POST / Create a new message
PUT /:id Update a message
DELETE /:id Delete a message

Each message is an object with the following structure:

{
  "id": "uuid",
  "content": "string",
  "isPalindrome": "boolean",
  "creationTime": "date.toISOString()",
  "lastUpdateTime": "date.toISOString()"
}

Testing

The project includes both unit and integration tests, covering:

  • Integration Tests:
    • Full CRUD flow on message routes (POST, GET, PUT, DELETE)
  • Unit Tests:
    • InMemoryDatabase: create, read, update, delete, edge cases
    • Message Entity: validation, update logic, palindrome detection
    • MessageRepository: correct interactions with the database
    • MessageService: business logic and error handling
    • Palindrome Checker: case sensitivity, numbers, edge cases

✔ All tests are written using Mocha, Chai, Sinon, and Supertest

✔ Test runner outputs:

> npm test

41 passing ✔

CLI Tool

You can interact with the API using a CLI tool.
You can find the CLI tool in the following repository: Messages-CRUD-RestAPI CLI
There you can find the instructions on how to use it. In short, Clone the repository:

>git clone https://github.com/GalBitton/Messages-CRUD-CLI.git
cd message-cli
npm install

# Start using the CLI tool (read the README file inside the CLI repository for more details):

CI/CD

The project uses GitHub Actions for CI/CD. The workflow is defined in .github/workflows/ci.yml.
It runs on every push to the main branch and on every pull request.

Deployment

The project is deployed on Railway Cloud Provider.
You can access the live API at Messages-CRUD-RESTAPI.
In order to deploy your own version:

  1. Create a new Railway project
  2. Connect your GitHub repository
  3. Set up the environment variables in Railway
  4. Deploy the project

Project Structure

Messages-CRUD-RestAPI/
├── src/
│   ├── api/
│   │   └── swagger.js                         # Swagger configuration (YAML loader)
│   ├── config/
│   │   └── config.js                          # Environment-based app configuration
│   ├── controllers/
│   │   ├── baseController.js                  # Base controller with shared logic
│   │   └── messageController.js               # Handles message-specific requests
│   ├── docs/
│   │   ├── architecture.jpg                   # System architecture diagram
│   │   └── swagger.yaml                       # Swagger OpenAPI definition
│   ├── interfaces/
│   │   ├── baseDatabase.js                    # Abstract DB interface
│   │   └── baseSchema.js                      # Abstract schema interface
│   ├── middlewares/
│   │   └── validateMessage.js                 # Joi-based input validation middleware
│   ├── models/
│   │   ├── inMemoryDatabase.js                # In-memory DB implementation
│   │   ├── messageEntity.js                   # Message domain model
│   │   ├── messageInMemorySchema.js           # In-memory schema logic
│   │   ├── messageMongoSchema.js              # MongoDB schema definition and logic
│   │   └── mongoDatabase.js                   # MongoDB connection and operations
│   ├── repositories/
│   │   ├── baseRepository.js                  # Generic repository operations
│   │   └── messageRepository.js               # Message-specific repository logic
│   ├── routes/
│   │   └── messageRoutes.js                   # Message API route definitions
│   ├── services/
│   │   ├── baseCrudService.js                 # Base service layer
│   │   └── messageService.js                  # Message service logic
│   ├── utils/
│   │   ├── logger.js                          # Winston logger with file support
│   │   └── palindromeChecker.js               # Utility to check if message is palindrome
│   ├── app.js                                 # Express app setup
│   ├── container.js                           # Dependency Injection setup (kontainer-di)
│   ├── root.html                              # Basic root page served at '/'
│   └── server.js                              # App and DB bootstrapping
├── tests/
│   ├── integration/
│   │   └── messageRoutes.test.js              # Integration tests for REST endpoints
│   └── unit/
│       ├── inMemoryDatabase.test.js           # Unit test for in-memory DB
│       ├── messageEntity.test.js              # Unit test for message entity logic
│       ├── messageRepository.test.js          # Repository logic tests
│       ├── messageService.test.js             # Service layer tests
│       └── palindromeChecker.test.js          # Palindrome checker logic
├── .github/
│   └── workflows/
│       └── ci.yaml                            # GitHub Actions workflow for CI
├── Dockerfile                                 # Docker image configuration
├── .env (ignored)                             # Environment variables (not committed)
├── .gitignore                                 # Git ignored files
├── .prettierrc.json                           # Prettier configuration
├── LICENSE                                    # Project license (MIT)
├── package.json                               # NPM dependencies and metadata
├── package-lock.json                          # Exact dependency versions
└── README.md                                  # You're reading it

Environment Variables

These variables are used to configure the application
Note: The .env file is ignored by git, so you need to create it manually. make sure you don't commit it.
Please create a .env file in the root directory with the following variables:

NODE_ENV=production
PORT=8080
ROUTE_URL=https://messages-crud.up.railway.app/
MONGODB_URI=<your-mongodb-uri>
MONGODB_COLLECTION=<your-collection-name>
LOG_LEVEL=info
LOG_CONSOLE=true
LOG_FILE=true
LOG_FILE_PATH=../../logs/
DB_SETUP=mongoDB

Note: The MONGODB_URI and MONGODB_COLLECTION variables are only needed if you are using MongoDB as your database. If you are using the in-memory database, you can just configure the DB_SETUP variable to inMemoryDB.


Contact

If you have any questions or suggestions, feel free to contact me at:
Gal Bitton
Email: galbitton22@gmail.com
LinkedIn: Gal Bitton

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published