Dwex Logo

Your First App

Build a simple REST API with Dwex in under 5 minutes

Overview

In this tutorial, you'll build a simple task management API with the following endpoints:

  • GET /tasks - Get all tasks
  • GET /tasks/:id - Get a task by ID
  • POST /tasks - Create a new task
  • DELETE /tasks/:id - Delete a task

Step 1: Create the Project

bun create dwex task-api
cd task-api
bun install

Step 2: Define the Task Type

Create src/task.interface.ts:

export interface Task {
  id: string;
  title: string;
  completed: boolean;
}

Step 3: Create the Task Service

Create src/task.service.ts:

import { Injectable } from "@dwex/core";
import type { Task } from "./task.interface";

@Injectable()
export class TaskService {
  private tasks: Task[] = [
    { id: "1", title: "Learn Dwex", completed: false },
    { id: "2", title: "Build an API", completed: false },
  ];

  findAll(): Task[] {
    return this.tasks;
  }

  findOne(id: string): Task | undefined {
    return this.tasks.find((task) => task.id === id);
  }

  create(title: string): Task {
    const task: Task = {
      id: String(Date.now()),
      title,
      completed: false,
    };
    this.tasks.push(task);
    return task;
  }

  delete(id: string): boolean {
    const index = this.tasks.findIndex((task) => task.id === id);
    if (index === -1) return false;
    this.tasks.splice(index, 1);
    return true;
  }
}

Step 4: Create the Task Controller

Create src/task.controller.ts:

import { Controller, Get, Post, Delete, Param, Body } from "@dwex/core";
import { TaskService } from "./task.service";
import type { Task } from "./task.interface";

@Controller("tasks")
export class TaskController {
  constructor(private readonly taskService: TaskService) {}

  @Get()
  findAll(): Task[] {
    return this.taskService.findAll();
  }

  @Get(":id")
  findOne(@Param("id") id: string) {
    const task = this.taskService.findOne(id);
    if (!task) {
      return { error: "Task not found" };
    }
    return task;
  }

  @Post()
  create(@Body() body: { title: string }) {
    return this.taskService.create(body.title);
  }

  @Delete(":id")
  delete(@Param("id") id: string) {
    const deleted = this.taskService.delete(id);
    return { success: deleted };
  }
}

Step 5: Create the App Module

Create src/app.module.ts:

import { Module } from "@dwex/core";
import { TaskController } from "./task.controller";
import { TaskService } from "./task.service";

@Module({
  controllers: [TaskController],
  providers: [TaskService],
})
export class AppModule {}

Step 6: Bootstrap the Application

Create src/main.ts:

import "reflect-metadata";
import { DwexFactory } from "@dwex/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await DwexFactory.create(AppModule);

  const port = 3000;
  await app.listen(port);
}

bootstrap();

Step 7: Run Your Application

bun run src/main.ts

Test Your API

Get all tasks

curl http://localhost:3000/tasks

Response:

[
  { "id": "1", "title": "Learn Dwex", "completed": false },
  { "id": "2", "title": "Build an API", "completed": false }
]

Get a specific task

curl http://localhost:3000/tasks/1

Create a new task

curl -X POST http://localhost:3000/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Deploy to production"}'

Delete a task

curl -X DELETE http://localhost:3000/tasks/1

What We Built

Let's break down what each part does:

Service Layer

The TaskService handles business logic and data management. It's marked with @Injectable() so Dwex's DI container can manage it.

Controller Layer

The TaskController handles HTTP requests. Decorators like @Get() and @Post() define routes. The constructor receives TaskService automatically via dependency injection.

Module

The AppModule ties everything together, registering controllers and providers.

Bootstrap

DwexFactory.create() initializes the application and dependency injection container. app.listen() starts the HTTP server.

Adding Logging

Let's enhance our app with the logger module:

bun add @dwex/logger

Update src/app.module.ts:

import { Module } from "@dwex/core";
import { LoggerModule } from "@dwex/logger";
import { TaskController } from "./task.controller";
import { TaskService } from "./task.service";

@Module({
  imports: [LoggerModule],
  controllers: [TaskController],
  providers: [TaskService],
})
export class AppModule {}

Update src/task.controller.ts:

import { Controller, Get, Post, Delete, Param, Body } from "@dwex/core";
import { Logger } from "@dwex/logger";
import { TaskService } from "./task.service";

@Controller("tasks")
export class TaskController {
  private readonly logger = new Logger(TaskController.name);

  constructor(private readonly taskService: TaskService) {}

  @Get()
  findAll() {
    this.logger.log("Fetching all tasks");
    return this.taskService.findAll();
  }

  // ... rest of the methods
}

Next Steps