> ## Documentation Index
> Fetch the complete documentation index at: https://suvidhajs.is-cool.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Action

> Examples using Default and Custom Handlers

## Using and Extending Suvidha's Default Handlers

Suvidha's default handlers offer a quick start for request/response management. They handle common tasks and can be easily extended.

### Introduction

Default handlers provide a pre-configured setup. They handle response formatting, errors, and successful requests, allowing you to focus on your logic. They're ready to use yet customizable.

### Basic Usage

```typescript theme={"system"}
import express from "express";
import { Suvidha, DefaultHandlers, Http } from "suvidha";

const app = express();
app.use(express.json());

const suvidha = () => Suvidha.create(new DefaultHandlers());

app.get(
    "/hello",
    suvidha().handler(() => {
        return Http.Ok.body({ message: "Hello, world!" });
    }),
);

// Example using a plain Protocol object:
app.get(
    "/simple",
    suvidha().handler(() => {
        return { status: 200, body: { message: "This is simple." } };
    }),
);

app.listen(3000, () => console.log("Server listening on port 3000"));
```

Default handlers are created with `new DefaultHandlers()`. `suvidha()` uses them to process requests. Your handler function contains your logic. Return data, use `Http` classes, or plain `Protocol` objects for responses.

### Extending

Extend the default handlers to customize behavior. Create a class that inherits from `DefaultHandlers` and overrides its methods.

```typescript theme={"system"}
import { Handlers, Conn } from "suvidha";
import { DefaultHandlers } from "./defaultHandlers";

export class SimpleCustomHandlers extends DefaultHandlers implements Handlers {
    override onComplete(output: unknown, conn: Conn, next: NextFunction) {
        // Add custom headers to all responses
        conn.res.setHeader("X-API-Version", "2.0");

        // Preserve default behavior
        super.onComplete(output, conn, next);
    }

    override onErr(err: unknown, conn: Conn, next: NextFunction) {
        // Simple error logging
        console.error("[Custom Handler Error]", err);

        // Custom error format
        conn.res.status(500).json({
            error: "Something went wrong",
            reference: Date.now().toString(36),
        });
    }
}
```

**User Profile Endpoint with `SimpleCustomHandlers`**

```typescript theme={"system"}
app.get(
    "/users/:id",
    Suvidha.create(new SimpleCustomHandlers())
        .params(z.object({ id: z.string().uuid() }))
        .use(async (req) => {
            const user = await getUser(req.params.id);
            if (!user) throw Http.NotFound.body("User not found");
            return { user };
        })
        .handler((req) => {
            return {
                id: req.context.user.id,
                name: req.context.user.name,
                stats: {
                    logins: req.context.user.loginCount,
                },
            };
        }),
);
```

<Tabs>
  <Tab title="Successful Response">
    ```json theme={"system"}
    {
        "status": "success",
        "data": {
            "id": "usr_987",
            "name": "Alice Smith",
            "stats": {
                "logins": 42
            }
        },
        "meta": {}
    }
    ```

    ```http theme={"system"}
    HTTP/1.1 200 OK
    X-API-Version: 2.0
    ```
  </Tab>

  <Tab title="Error Response">
    ```json theme={"system"}
    {
        "error": "Something went wrong",
        "reference": "k7gfy2"
    }
    ```

    ```http theme={"system"}
    HTTP/1.1 500 Internal Server Error
    X-API-Version: 2.0
    ```
  </Tab>
</Tabs>

### Customization

#### Logging

Override `onComplete` or `onErr`.

```typescript theme={"system"}
class MyHandlers extends DefaultHandlers {
    override onComplete(
        output: unknown,
        conn: Conn,
        next: NextFunction,
    ): Promise<void> | void {
        console.log(
            `Request completed. Output: ${JSON.stringify(output)}, URL: ${conn.req.originalUrl}`,
        );
        return super.onComplete(output, conn, next);
    }

    override onErr(
        err: unknown,
        conn: Conn,
        next: NextFunction,
    ): Promise<void> | void {
        console.error(`Error: ${err}, URL: ${conn.req.originalUrl}`);
        return super.onErr(err, conn, next);
    }
}
```

#### Setting Headers

Override `onComplete` or `onErr`.

```typescript theme={"system"}
class MyHandlers extends DefaultHandlers {
    override onComplete(
        output: unknown,
        conn: Conn,
        next: NextFunction,
    ): Promise<void> | void {
        conn.res.setHeader("Cache-Control", "no-cache");
        conn.res.setHeader("X-API-Version", "2.0");
        return super.onComplete(output, conn, next);
    }
}
```

#### Using `next(err)` (Within Suvidha Handlers)

Suvidha handlers receive the `next` function, allowing you to pass errors to Express.js error handling middleware or the default Express.js error handler. This is particularly useful if you have existing error handling logic in Express.js that you want to leverage.

```typescript theme={"system"}
import { DefaultHandlers, Conn, Http } from "suvidha";

class MyHandlers extends DefaultHandlers {
    override onErr(
        err: unknown,
        conn: Conn,
        next: NextFunction,
    ): Promise<void> | void {
        if (err instanceof Http.End) {
            return super.onErr(err, conn, next); // Default Suvidha error handling
        }

        return next(err); // Delegate to Express.js error handling
    }
}
```

#### Custom Error Handling

Override `onErr`.

```typescript theme={"system"}
import { Http } from "suvidha"; // Import Http

class MyHandlers extends DefaultHandlers {
    override onErr(
        err: unknown,
        conn: Conn,
        next: NextFunction,
    ): Promise<void> | void {
        if (err instanceof Http.NotFound) {
            return void conn.res
                .status(404)
                .send({ error: "Resource not found" });
        } else if (
            err instanceof Error &&
            err.message.includes("Database Error")
        ) {
            return void conn.res
                .status(500)
                .send({ error: "Database error occurred." });
        }
        return super.onErr(err, conn, next);
    }
}
```

#### Modifying Response Format

Override the formatter.

```typescript theme={"system"}
class MyHandlers extends DefaultHandlers {
    constructor() {
        const fmt = (status, body, meta) => {
            return {
                statusCode: status,
                data: body,
                metadata: meta,
            };
        };
        super(fmt);
    }
}
```

#### Middleware Integration

Use Suvidha's `.use()` method for middleware, which preserves type safety and allows context propagation.

```typescript theme={"system"}
import { Suvidha, DefaultHandlers, Http } from "suvidha";
import { z } from "zod"; // Import Zod

interface User {
    id: string;
    role: string;
}

declare function authenticate(req: Request): Promise<User>;

const suvidha = () => Suvidha.create(new DefaultHandlers());

const auth = () =>
    suvidha().use(async (req) => {
        const user = await authenticate(req).catch((_) => {
            throw new Http.Unauthorized();
        });
        return { user };
    });

const adminOnly = () =>
    auth().use(async (req) => {
        if (req.context.user.role !== "admin") {
            throw new Http.Forbidden();
        }
        return {};
    });

const userSchema = z.object({
    name: z.string(),
    email: z.string().email(),
});

const createUser = (user: User) => Http.Created.body(user);

app.post(
    "/users",
    auth()
        .body(userSchema)
        .handler((req) => {
            const user = req.body;
            return createUser(user);
        }),
);

const pageSchema = z.object({
    page: z.string().transform(Number),
    limit: z.string().transform(Number),
});

app.get(
    "/users",
    auth()
        .query(pageSchema)
        .handler((req) => {
            const { page, limit } = req.query;
            return Http.Ok.body({ page, limit });
        }),
);

app.listen(3000, () => console.log("Server is listening on port 3000")); // Added a port and listen call
```
