npm package: @lintangoao/soulcode-api-http
Description: Reusable HTTP server wrapper for Soulcode API
Author: Soulcode API Team
Latest version: 1.0.3

# @lintangoao/soulcode-api-http

Reusable HTTP server wrapper untuk Soulcode API. Package ini menyediakan abstraksi yang mudah untuk membuat HTTP server dengan Express.

## Installation

```bash
pnpm add @lintangoao/soulcode-api-http
```

## Usage

### Basic Server

```typescript
import { HttpServer } from "@lintangoao/soulcode-api-http";

const server = new HttpServer({
  port: 3000,
  onReady: (port) => {
    console.log(`Server ready on port ${port}`);
  },
});

// Setup routes
server.app.get("/", (req, res) => {
  res.json({ message: "Hello World" });
});

// Start server
await server.start();
```

### Auto-Load Routes

Package ini menyediakan fitur **auto-loading** untuk routes. Semua file dengan pattern `*.routes.ts` akan otomatis di-load.

```typescript
import { HttpServer, autoLoadRoutes } from "@lintangoao/soulcode-api-http";
import { fileURLToPath } from "url";
import { dirname } from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const server = new HttpServer({ port: 3000 });

// Auto-load semua routes dari directory
await autoLoadRoutes(server.app, {
  baseDir: __dirname,
  pattern: "**/*.routes.{ts,js}", // optional, default value
});

await server.start();
```

**File structure example:**
```
src/app/http/
├── index.ts
├── home/
│   └── home.routes.ts      -> akan di-load ke "/"
└── users/
    └── users.routes.ts     -> akan di-load ke "/users"
```

**Example route file (home.routes.ts):**
```typescript
import { Router, requestHandler } from "@lintangoao/soulcode-api-http";
import { HomeController } from "@src/app/http/home/home.controller";

const router = Router();
const homeController = new HomeController();

// Gunakan requestHandler untuk auto error handling
router.get("/", requestHandler(homeController.index));

// IMPORTANT: harus export default
export default router;
```

**Example controller (home.controller.ts):**
```typescript
import { TRequest, TRequestFunction } from "@lintangoao/soulcode-api-http";

export class HomeController {
  // Gunakan arrow function untuk auto-bind
  index: TRequestFunction = async (req) => {
    // Tidak perlu try-catch, requestHandler akan handle errors
    const data = await someAsyncOperation();
    
    // Return standard response format
    return {
      // statusCode: 200, // optional, default 200
      // message: "Success", // optional, default "Success"
      result: data,
    };
  };
}
```

### Configuration Options

```typescript
interface HttpServerConfig {
  port?: number;          // Default: 3000
  host?: string;          // Default: "0.0.0.0"
  cors?: boolean;         // Default: true
  helmet?: boolean;       // Default: true
  onReady?: (port: number) => void;
  onError?: (error: Error) => void;
}

interface AutoLoadOptions {
  baseDir: string;        // Directory untuk search routes
  pattern?: string;       // Glob pattern (default: **/*.routes.{ts,js})
}
```

### Advanced Example

```typescript
import { HttpServer } from "@lintangoao/soulcode-api-http";
import { log } from "@lintangoao/soulcode-api-core";

const server = new HttpServer({
  port: 8080,
  host: "localhost",
  cors: true,
  helmet: true,
  onReady: (port) => log.info(`Server running on port ${port}`),
  onError: (error) => log.error("Server error:", error),
});

// Access Express app directly
server.app.use((req, res, next) => {
  log.info(`${req.method} ${req.path}`);
  next();
});

// Define routes
server.app.get("/api/users", (req, res) => {
  res.json({ users: [] });
});

server.app.post("/api/users", (req, res) => {
  const user = req.body;
  res.status(201).json({ user });
});

// Start server
await server.start();

// Later, stop the server
await server.stop();
```

## Request Handler

Package ini menyediakan `requestHandler` (alias: `catchAsync`) untuk wrap async controller methods dengan automatic error handling.

```typescript
import { Router, requestHandler, TRequestFunction } from "@lintangoao/soulcode-api-http";

class UserController {
  // Gunakan arrow function untuk auto-bind
  getUsers: TRequestFunction = async (req) => {
    // Jika error, otomatis di-catch dan di-pass ke error middleware
    const users = await db.users.findMany();
    
    return {
      message: "Users retrieved successfully",
      result: users,
    };
  };
}

const controller = new UserController();
const router = Router();

// Wrap dengan requestHandler (tidak perlu .bind lagi)
router.get("/users", requestHandler(controller.getUsers));
```

**Standard Response Format:**
```json
{
  "statusCode": 200,
  "message": "Success",
  "result": { ... }
}
```

### Custom Types

Tidak perlu import dari `express` lagi:

```typescript
import type { TRequest, TResponse, TNextFunction } from "@lintangoao/soulcode-api-http";
// Bukan: import { Request, Response } from "express";
```

## Features

- ✅ Express.js wrapper dengan konfigurasi yang clean
- ✅ Built-in CORS support
- ✅ Built-in Helmet security headers
- ✅ JSON body parsing
- ✅ URL-encoded body parsing
- ✅ **Auto-loading routes** dengan glob pattern
- ✅ **Request handler wrapper** dengan auto error handling
- ✅ **Custom types** untuk menghindari import express di setiap file
- ✅ Graceful shutdown
- ✅ TypeScript support
- ✅ Logger integration dengan @lintangoao/soulcode-api-core

## API Reference

### `HttpServer`

#### Constructor
```typescript
new HttpServer(config?: HttpServerConfig)
```

#### Properties
- `app: Application` - Express application instance

#### Methods
- `start(): Promise<void>` - Start the HTTP server
- `stop(): Promise<void>` - Stop the HTTP server gracefully
- `getPort(): number` - Get the current port number

### `autoLoadRoutes`

```typescript
async function autoLoadRoutes(
  app: Application,
  options: AutoLoadOptions
): Promise<void>
```

Auto-load semua file routes berdasarkan pattern. File harus export `default` router.

### `requestHandler` / `catchAsync`

```typescript
function requestHandler(
  handler: TAsyncRequestHandler
): TRequestHandler
```

Wrap async controller methods untuk automatic error handling. Errors akan otomatis di-catch dan di-pass ke error middleware.

**Parameters:**
- `handler: (req: TRequest, res: TResponse) => Promise<void>` - Async controller method

**Returns:**
- Express-compatible request handler dengan error handling

**Example:**
```typescript
router.get("/users", requestHandler(controller.getUsers));
```

**Response Examples:**
```typescript
// Default (statusCode: 200, message: "Success")
return { result: data };

// Custom message
return { 
  message: "User created successfully",
  result: newUser 
};

// Custom status code
return { 
  statusCode: 201,
  message: "Resource created",
  result: newResource 
};

// No data
return { 
  message: "Operation completed" 
};
```

**Tips:** Gunakan arrow functions di controller untuk auto-binding:
```typescript
class MyController {
  // ✅ Arrow function dengan type annotation - auto-bind, clean syntax
  myMethod: TRequestFunction = async (req) => {
    // this.service works!
    return { result: data };
  };
  
  // ❌ Regular method - perlu .bind(this)
  async myMethod2(req: TRequest): Promise<ApiResponse> {
    // this.service might be undefined
  }
}
```

### Types

- `TRequest` - Alias untuk Express `Request`
- `TResponse` - Alias untuk Express `Response`
- `TNextFunction` - Alias untuk Express `NextFunction`
- `TRequestFunction<T>` - **Main type untuk controller methods**
  ```typescript
  type TRequestFunction<T = any> = (req: TRequest) => Promise<ApiResponse<T>>
  
  // Usage:
  myMethod: TRequestFunction = async (req) => { return {...} }
  ```
- `TRequestHandler<T>` - Alias untuk `TRequestFunction`
- `TAsyncRequestHandler<T>` - Alias untuk `TRequestFunction`
- `ApiResponse<T>` - Standard response format
  ```typescript
  interface ApiResponse<T = any> {
    statusCode?: number;  // default: 200
    message?: string;     // default: "Success"
    result?: T;          // data payload
  }
  ```

## License

MIT