Skip to content

The all in one hono api template with prisma, postgress and minio s3 bucket setup. Includes a CI/CD pipeline to deploy to a VPS via a docker compose.

Notifications You must be signed in to change notification settings

Aditya-Jyoti/Hono-API-Template

Repository files navigation

Hono API Template

The all in one hono api template with prisma, postgresql and minio s3 bucket setup. Includes a CI/CD pipeline to deploy to a VPS via a docker compose.

Tech stack

Project Structure

.
├── docker-compose.yml
├── Dockerfile
├── eslint.config.js
├── init.sh
├── lint-staged.config.js
├── package.json
├── pnpm-lock.yaml
├── prisma
│   ├── migrations
│   │   └── migration_lock.toml
│   └── schema.prisma
├── README.md
├── src
│   ├── index.ts
│   ├── lib
│   │   ├── prisma-client.ts
│   │   └── s3-client.ts
│   ├── routes
│   │   └── auth
│   │       ├── index.ts
│   │       └── routes.ts
│   └── utils
│       └── passwords.ts
└── tsconfig.json

Whats included

Swagger Docs served at /docs

  1. Each route should be inside /src/routes/<route-folder>/

  2. Each /<route-folder>/ should include 2 files

    1. routes.ts

      • here define the openapi specs for all your routes in this format

        export const <route-name> = createRoute({
          method: "",
          path: "/<route-name>",
          request: {
            query: z.object({
            }),
          },
          responses: {
            200: {
              description: "",
              content: {
                "application/json": {
                  schema: z.object({}).openapi("<route-name>Response"),
                },
              },
            },
            ...
          },
        });
    2. index.ts

      • import your route specs here and define functionality

        const <main-router-name>Router = new OpenAPIHono();
        
        <main-router-name>Router.openapi(<imported-router>, async (ctx) => {
          const {  } = ctx.req.valid("query");
        
          return new Response("<description>", {
            status: ,
          });
        });
  3. include defined router in /src/index.ts

Prisma Role Base Auth

The project includes a pre-configured Prisma schema for role-based authentication and user management. The schema defines two main models:

  1. Auth: Handles authentication details.
  • id: Unique identifier (UUID).
  • email: Unique email for login.
  • password: Encrypted password.
  • createdAt: Timestamp when the record is created.
  • updatedAt: Auto-updated timestamp when the record is modified.
  • user: Relation to the User model (optional).
  1. User: Represents user information and roles.
  • id: Unique identifier (UUID).
  • authId: Relation to the Auth model (UUID).
  • name: User's name.
  • role: Enum field representing the user role (ADMIN or USER).

example auth record

{
  "id": "uuid",
  "email": "[email protected]",
  "password": "encrypted-password",
  "createdAt": "2024-01-01T00:00:00.000Z",
  "updatedAt": "2024-01-02T00:00:00.000Z",
  "user": {
    "id": "uuid",
    "authId": "uuid",
    "name": "John Doe",
    "role": "USER"
  }
}

S3 Object Storage

Functions

  1. createDocument(file: File): Promise<string>

Uploads a document to the MinIO server and returns a unique document ID.

  • Parameters:
    • file (File): The document to upload.
  • Returns:
    • Promise<string>: A unique document ID (UUID) associated with the uploaded file.
const file = new File(["Hello, world!"], "example.txt", { type: "text/plain" });
const docId = await createDocument(file);
console.log("Uploaded document ID:", docId);
  1. readDocument(docId: string): Promise<{ data: Buffer; contentType: string; }>

Retrieves a document from the MinIO server using its unique document ID.

  • Parameters: docId (string): The unique ID of the document.

  • Returns:

    • Promise<{ data: Buffer; contentType: string; }>: An object containing:

      • data (Buffer): The document's content.
      • contentType (string): The MIME type of the document.
      const doc = await readDocument(docId);
      console.log("Document content type:", doc.contentType);
      console.log("Document data:", doc.data.toString());
  1. deleteDocument(docId: string): Promise<void>

Deletes a document from the MinIO server using its unique document ID.

  • Parameters:

    • docId (string): The unique ID of the document to delete.
  • Returns:

    • Promise<void>: Resolves once the document is successfully deleted.

      await deleteDocument(docId);
      console.log("Document deleted successfully");

Auth Routes

The authentication module provides routes for user login and registration, utilizing JWT for secure token generation and Prisma for database interactions.

POST /login

Authenticates a user and returns a JWT for accessing protected resources.

  • Request Body (JSON)

    • email (string): The user's email. Must be a valid email address.

    • password (string): The user's password. Must be at least 8 characters.

      {
        "email": "[email protected]",
        "password": "securepassword"
      }
  • Responses

    • 200 OK
      • token: JWT for authenticated access.
      • userId: Unique identifier of the authenticated user.
    • 404 Not Found: User with the provided email does not exist.
    • 403 Forbidden: Password is incorrect.
    • 500 Internal Server Error: JWT secret is not set.

POST /register

Registers a new user by creating entries in the Auth and User models.

  • Request Body (JSON)

    • email (string): The user's email. Must be a valid email address.

    • password (string): The user's password. Must be at least 8 characters.

    • name (string): Full name of the user.

    • role (string): Role of the user (ADMIN or USER).

      {
        "name": "John Doe",
        "role": "USER",
        "email": "[email protected]",
        "password": "securepassword"
      }
  • Responses

    • 201 Created
      • message: Confirmation of successful registration.
      • user: Basic user details (id and email).
    • 409 Conflict: User with the provided email already exists.

Local Development

  1. Create the .env file
JWT_SECRET=

POSTGRES_DB=
DATABASE_URL=postgres://postgres:postgres@localhost:5432/${POSTGRES_DB}?schema=public

MINIO_USE_SSL=false
MINIO_ROOT_USER=
MINIO_ROOT_PASSWORD=
MINIO_ACCESS_KEY= # openssl rand -base64 20
MINIO_SECRET_KEY= # openssl rand -base64 40
MINIO_BUCKET=
  1. run pnpm install
  2. run pnpm run dev

Deployment

  1. Create the .env file
JWT_SECRET=

POSTGRES_DB=
POSTGRES_USER=
POSTGRES_PASSWORD=
DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?schema=public

MINIO_USE_SSL=false
MINIO_ROOT_USER=
MINIO_ROOT_PASSWORD=
MINIO_ACCESS_KEY= # openssl rand -base64 20
MINIO_SECRET_KEY= # openssl rand -base64 40
MINIO_BUCKET=

HONO_PORT=
MINIO_API_PORT=
MINIO_WEB_PORT=
POSTGRES_PORT=

The project comes with a docker compose file that can be put up on any container management provider or just straight docker compose up -d

For auto deployment via CI/CD

  1. Set up a self hosted github runner and follow the instructions
  2. Set up repository environment variables
    • copy the entire contents of .env into a single ENV titled repo environment variable, not individual variables (referenced here echo "${{ secrets.ENV }}" > .env which creates the env file on VPS for docker compose)

Now it should auto deploy every time something is pushed

About

The all in one hono api template with prisma, postgress and minio s3 bucket setup. Includes a CI/CD pipeline to deploy to a VPS via a docker compose.

Resources

Stars

Watchers

Forks