# Parameter Handling

The Interface API provides a parameter injection system for controller methods. Parameters are automatically extracted from various request sources and processed before being passed to handler methods.

## Parameter sources

The API extracts parameters from the following sources:

- **Route parameters** - Segments of the URL path marked with `:paramName`
- **Query parameters** - Values from the URL query string
- **HTTP headers** - Request header values
- **Request body** - Data submitted in the request body
- **Request context** - The complete request context object

## Parameter decorators

### `@Parameter`

The `@Parameter` decorator extracts a single value from route parameters, query strings, or headers.

```typescript
import { Controller, Get, Parameter } from "@antelopejs/interface-api";

class UsersController extends Controller("/users") {
  @Get(":id")
  async getUser(@Parameter("id") id: string) {
    return { id, name: "Example User" };
  }

  @Get()
  async listUsers(@Parameter("page", "query") page: string) {
    // For a request to /users?page=2, page is "2"
    return { users: ["user1", "user2"], page };
  }

  @Get(":userId/posts/:postId")
  async getUserPost(
    @Parameter("userId") userId: string,
    @Parameter("postId") postId: string,
  ) {
    return { userId, postId };
  }
}
```

The second argument specifies the source:

| Source     | Description                       | Example                                 |
| ---------- | --------------------------------- | --------------------------------------- |
| `"param"`  | Route parameters (default)        | `/users/:id` extracts `id`              |
| `"query"`  | URL query parameters              | `/users?page=2` extracts `page`         |
| `"header"` | HTTP request headers              | Extracts `Authorization` header value   |

### `@MultiParameter`

The `@MultiParameter` decorator extracts multiple values for a parameter as an array. This is useful for query parameters or headers that appear more than once.

```typescript
import { Controller, Get, MultiParameter } from "@antelopejs/interface-api";

class ProductsController extends Controller("/products") {
  @Get("search")
  async searchProducts(
    @MultiParameter("tag") tags: string[],
  ) {
    // For /products/search?tag=js&tag=api, tags is ["js", "api"]
    return { tags, results: ["product1", "product2"] };
  }
}
```

The `@MultiParameter` decorator accepts a source argument of `"query"` (default) or `"header"`.

### `@RawBody`

The `@RawBody` decorator provides the raw HTTP request body as a `Buffer`.

```typescript
import { Controller, Post, RawBody } from "@antelopejs/interface-api";

class PostsController extends Controller("/posts") {
  @Post()
  async createPost(@RawBody() postData: Buffer) {
    const parsed = JSON.parse(postData.toString());
    return { id: "new-post-id", ...parsed };
  }
}
```

### `@JSONBody`

The `@JSONBody` decorator parses the HTTP request body as JSON and provides the resulting object.

```typescript
import { Controller, Post, JSONBody } from "@antelopejs/interface-api";

class UsersController extends Controller("/users") {
  @Post()
  async createUser(@JSONBody() userData: { name: string; email: string }) {
    return { id: "new-user-id", ...userData };
  }
}
```

### `@Context`

The `@Context` decorator provides access to the complete `RequestContext` object.

```typescript
import { Controller, Get, Context, RequestContext } from "@antelopejs/interface-api";

class InfoController extends Controller("/info") {
  @Get()
  handleRequest(@Context() ctx: RequestContext) {
    const clientIP = ctx.rawRequest.socket.remoteAddress;
    const requestUrl = ctx.url.toString();
    return { ip: clientIP, url: requestUrl };
  }
}
```

### `@Result`

The `@Result` decorator provides access to the `HTTPResult` response object. This is typically used in postfix handlers to modify the response.

```typescript
import { Controller, Get, Postfix, Result, HTTPResult } from "@antelopejs/interface-api";

class ResponseController extends Controller("/api") {
  @Get("data")
  async getData() {
    return { data: "example" };
  }

  @Postfix("get", "data")
  async addMetadata(@Result() result: HTTPResult) {
    result.addHeader("X-Timestamp", new Date().toISOString());
  }
}
```

### `@WriteStream`

The `@WriteStream` decorator provides a writable stream for sending data to the client. This is useful for streaming responses or server-sent events.

```typescript
import { Controller, Get, WriteStream, Context, RequestContext } from "@antelopejs/interface-api";
import { PassThrough } from "node:stream";

class StreamController extends Controller("/stream") {
  @Get()
  async streamData(
    @Context() context: RequestContext,
    @WriteStream("text/event-stream") stream: PassThrough,
  ) {
    stream.write("data: Hello\n\n");

    setTimeout(() => {
      stream.write("data: World\n\n");
      stream.end();
    }, 1000);

    return context.response;
  }
}
```

### `@Connection`

The `@Connection` decorator provides access to the WebSocket connection object. It can only be used with `@WebsocketHandler`.

```typescript
import { Controller, WebsocketHandler, Connection } from "@antelopejs/interface-api";

class ChatController extends Controller("/chat") {
  @WebsocketHandler()
  handleChat(@Connection() connection: any) {
    connection.on("message", (data: string) => {
      connection.send("Received: " + data);
    });
  }
}
```

## Use decorators on class properties

Both `@Parameter` and `@MultiParameter` (as well as `@RawBody`, `@JSONBody`, `@Context`, and `@Connection`) can be applied to class properties. The property values are automatically populated from the request for each handler invocation.

```typescript
import { Controller, Get, Parameter, MultiParameter } from "@antelopejs/interface-api";

class ConfigurableController extends Controller("/config") {
  @Parameter("apiKey", "header")
  private apiKey!: string;

  @MultiParameter("tags", "query")
  private tags!: string[];

  @Get()
  async getConfig() {
    return {
      authenticated: Boolean(this.apiKey),
      appliedTags: this.tags,
    };
  }
}
```

## Combine multiple parameters

Handler methods can accept multiple decorated parameters from different sources.

```typescript
import { Controller, Put, Parameter, JSONBody } from "@antelopejs/interface-api";

class ArticlesController extends Controller("/articles") {
  @Put(":id")
  async updateArticle(
    @Parameter("id") id: string,
    @JSONBody() data: { title: string; content: string },
  ) {
    return { id, ...data, updated: true };
  }
}
```

> **Note:** Each parameter should have exactly one provider decorator. Do not apply `@Parameter` to a parameter that already has `@RawBody`, `@JSONBody`, or another provider.

## Parameter providers and modifiers

The API uses a system of **providers** and **modifiers** to process parameters.

### Parameter providers

A parameter provider extracts the initial value from the request. The `SetParameterProvider` function registers a custom provider.

```typescript
import {
  SetParameterProvider,
  ReadBody,
  RequestContext,
} from "@antelopejs/interface-api";
import { MakeParameterDecorator } from "@antelopejs/interface-core/decorators";

const RawBody = MakeParameterDecorator((target, key, param) =>
  SetParameterProvider(target, key, param, (context: RequestContext) => {
    return ReadBody(context);
  }),
);
```

### Parameter modifiers

A parameter modifier transforms the value after the provider runs. Unlike providers, you can chain multiple modifiers on a single parameter. The `AddParameterModifier` function registers a modifier.

```typescript
import {
  AddParameterModifier,
  RequestContext,
} from "@antelopejs/interface-api";
import { MakeParameterDecorator } from "@antelopejs/interface-core/decorators";

const EnsureNumber = MakeParameterDecorator((target, key, param) =>
  AddParameterModifier(target, key, param, (context: RequestContext, value: unknown) => {
    const num = Number(value);
    return isNaN(num) ? 0 : num;
  }),
);
```

Use custom modifiers alongside built-in decorators:

```typescript
import { Controller, Get, Parameter } from "@antelopejs/interface-api";

class ExampleController extends Controller("/example") {
  @Get(":id")
  async getExample(@Parameter("id") @EnsureNumber() id: number) {
    return { id, doubled: id * 2 };
  }
}
```

### The `@Transform` decorator

The `@Transform` decorator applies a transformation function to any parameter value.

```typescript
import { Controller, Get, Parameter, Transform, RequestContext } from "@antelopejs/interface-api";

function parseId(context: RequestContext, value: unknown): number {
  return parseInt(value as string, 10);
}

class ItemController extends Controller("/items") {
  @Get(":id")
  getItem(@Parameter("id") @Transform(parseId) id: number) {
    return { id };
  }
}
```

## Processing chain

Parameters follow a processing chain from extraction to injection:

```
Provider => [Modifier 1] => [Modifier 2] => ... => Parameter/Property
```

The provider runs first to extract the raw value, then each modifier transforms the value in sequence before the final result is passed to the handler.
