Skip to content

Marcel-MD/rooms-go-api

Repository files navigation

Rooms API

Description

Multi-room chat application developed with Gin, GORM, Go Redis and Gorilla WebSocket.

Deployment on Google Cloud

Deployment Diagram

Server is deployed on Google Cloud using Cloud Run and can scale to multiple instances. Memorystore (Redis) is primary used for it's pubsub feature to broadcast messages to all server instances. It's also used for storing temporary data like one time passwords, login attempts and rate limiting. Cloud SQL is used for storing persistent data like users, rooms and messages. Cloud Build is used for building and deploying the application.

Components Diagram

Components Diagram

This component diagram gives a general representation of how the backend’s main components depend on each other. For the server was chosen, a layered architecture which gives enough structure without being overly complicated. The three main layers are Handlers, Services, and Repositories. Handlers and Web sockets receive requests from the front end application. Services hold all the business logic. Repositories are responsible for data persistence in our PostgreSQL database. And Redis is used for its pubsub feature that allows to connect and send messages between a lot of clients. Redis is also used for storing temporary passwords as well as IP addresses for DDoS protection.

Environment Variables

Create a .env file in the root directory. And add these default values:

DATABASE_URL=postgres://postgres:password@postgres:5432/rooms
REDIS_URL=redis://:password@redis:6379/0
API_SECRET=SecretSecretSecret
TOKEN_HOUR_LIFESPAN=12
ENVIRONMENT=dev
PORT=8080
CORS_ORIGIN=*

RATE_LIMIT=30
RATE_WINDOW=1s
LOGIN_ATTEMPTS=5
LOGIN_WINDOW=10m
OTP_EXPIRY=10m

If you want to use SMTP for one time password emails. Add your SMTP credentials:

SENDER_NAME=Rooms 💬
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
EMAIL_PASSWORD=password

Run Application with Docker

More information about Docker. To run the application type this command in the root folder.

$ docker compose up

You might have to run this command twice if it doesn't work the first time :)

API Endpoints

For authentication are used bearer tokens.

  • User /api/users

    • [GET] / - Get all users

    • [GET] /:id - Get user by ID

    • [GET] /current - Get current user

    • [POST] /send-otp - Send OTP email

      {
        "email": "[email protected]"
      }
    • [POST] /register - Register user

      {
        "firstName": "First",
        "lastName": "Last",
        "email": "[email protected]",
        "password": "password"
      }
    • [POST] /register-otp - Register user with OTP

      {
        "firstName": "First",
        "lastName": "Last",
        "email": "[email protected]",
        "phone": "123456789",
        "password": "password",
        "otp": "123456"
      }
    • [POST] /login - Login user

      {
        "email": "[email protected]",
        "password": "password"
      }
    • [POST] /login-otp - Login user with OTP

      {
        "email": "[email protected]",
        "password": "password",
        "otp": "123456"
      }
    • [GET] /email/:email - Search user by email

    • [PUT] /update - Update user

      {
        "firstName": "First",
        "lastName": "Last",
        "email": "[email protected]",
        "phone": "123456789"
      }
    • [PUT] /update-otp - Update user with OTP

      {
        "firstName": "First",
        "lastName": "Last",
        "email": "[email protected]",
        "phone": "123456789",
        "otp": "123456"
      }
    • [POST] /:id/roles/:role - Add role to user

    • [DELETE] /:id/roles/:role - Remove role from user

  • Room /api/rooms

    • [GET] / - Get all rooms

    • [GET] /:id - Get room by ID

    • [POST] / - Create room

      {
        "name": "room"
      }
    • [PUT] /:id - Update room by ID

      {
        "name": "updated room"
      }
    • [DELETE] /:id - Delete room by ID

    • [POST] /:room_id/users/:user_id - Add user to room

    • [DELETE] /:room_id/users/:user_id - Remove user from room

  • Message /api/messages

    • [GET] /:room_id?page=1&size=10 - Get paginated messages by room ID

    • [POST] /:room_id - Create message

      {
        "text": "Hello World!"
      }
    • [PUT] /:id - Update message by ID

      {
        "text": "Goodbye World!"
      }
    • [DELETE] /:id - Delete message by ID

  • WebSocket /api/ws

    • [GET] / - Connect to all user's rooms

WebSocket

  • Create Message

    {
      "text": "Hello World!",
      "command": "CreateMessage",
      "targetId": "room_id",
      "roomId": "room_id"
    }
  • Update Message

    {
      "text": "Goodbye World!",
      "command": "UpdateMessage",
      "targetId": "message_id",
      "roomId": "room_id"
    }
  • Delete Message

    {
      "text": "anything",
      "command": "DeleteMessage",
      "targetId": "message_id",
      "roomId": "room_id"
    }
  • Add User to Room

    {
      "text": "anything",
      "command": "AddUser",
      "targetId": "user_id",
      "roomId": "room_id"
    }
  • Remove User from Room

    {
      "text": "anything",
      "command": "RemoveUser",
      "targetId": "user_id",
      "roomId": "room_id"
    }
  • Create Room

    {
      "text": "Room Name",
      "command": "CreateRoom",
      "targetId": "anything",
      "roomId": "anything"
    }
  • Update Room

    {
      "text": "New Room Name",
      "command": "UpdateRoom",
      "targetId": "room_id",
      "roomId": "room_id"
    }
  • Delete Room

    {
      "text": "anything",
      "command": "DeleteRoom",
      "targetId": "room_id",
      "roomId": "room_id"
    }