Server

Request & Response

Understanding mion's request and response objects.

The MionRequest and MionResponse objects are available to every middleFn/route within the CallContext (the first parameter of every middleFn/route).

mion does not use the standard Request and Response objects from the Fetch API. Instead, it uses its own abstractions to better support multiple platforms that don't use these standards—such, ie: Node.js, AWS lambda...

Example:@mionkit/node uses node's native IncomingMessage and ServerResponse while @mionkit/aws uses APIGatewayEvent and APIGatewayProxyResult. But routes and middleFns will always receive a standard MionRequest & MionResponse.

Passing parameters to routes and middleFns is automatically managed by mion so accessing the Request and Response objects is almost never required. Developers just need to take care of declaring the route/middleFn parameters and their types.

How Data is Sent and Received

When making a route call the URL.path is the route's id and is used for the route lookup. The HTTP request body is a JSON object where keys are the route or middleFn ids and the values are Arrays containing the parameters for each respective route or middleFn.

The HTTP response follows the same format where the body is a JSON object where the keys are the ids and the values are the return values from the remote methods.

This format is an important design decision that allows multiple subrequests (routes and middleFns) to be called in a single HTTP request. For example, authentication middleFns can send/receive their own data alongside the main route, all within the same request-response cycle.

| Request Path | Request Body                      | Response Body                          |
| ------------ | --------------------------------- | -------------------------------------- |
| `/sayHello`  | `{"sayHello": ["John"] }`         | `{"sayHello": "Hello John."}`          |
| `/greetings` | `{"greetings": ["Adan", "Eve"] }` | `{"greetings": "Hello Adan and Eve."}` |
The underlying logic to format request & parse response data is handled transparently by the Client. Developers should only care about declaring the route/middleFn parameters and their types.

Error Handling in Responses

Errors in mion are handled differently depending on whether they are returned or thrown:

  • Returned errors (strongly typed): Appear under the route id in the response body, preserving full type information
  • Thrown errors (untyped): Collected in the special @thrownErrors field of the response body

Thrown errors are typically unexpected, non-application-logic errors such as validation failures, serialization errors, database connection issues, or unhandled exceptions. Since they are not strongly typed, they can be produced by any middleFn or route—including internal middleFns that are not part of the public API.

{
    "getUser": {"id": "123", "name": "John"},
    "@thrownErrors": {
        "mionDeserializeRequest": {
            "type": "parsing-json-request-error",
            "publicMessage": "Invalid json request body ..."
        }
    }
}
All thrown errors are returned in response.body['@thrownErrors']. The logic for correctly serializing and deserializing these errors is handled by the mion client, so you don't need to manually parse this field when using the client.
Thrown errors should be (unexpected or unrecoverable), When an error is expected and should be handled (ie: user not found) it should be returned as a strongly typed error instead of being thrown.

For more details on error handling patterns, see Error Handling.


Type Reference

MionRequest

mion's Request object, does not depend on the underlying native request.

/** Router's own request object, do not confuse with the underlying raw request */
export interface MionRequest {
    /** parsed headers */
    readonly headers: Readonly<Omit<MionHeaders, 'append' | 'set' | 'delete'>>;
    /** Raw request body, can be string for json, arrayBuffer for binary or a javascript object in the case of pre-parsed body */
    readonly rawBody: RawRequestBody;
    readonly bodyType: SerializerCode;
    /** parsed request body */
    readonly body: Readonly<AnyObject>;
    /**
     * Unexpected or thrown errors that are not part of the route/handler return type.
     * This includes:
     * - Validation errors (params, headers)
     * - Deserialization/serialization errors
     * - Errors thrown by user code (not returned)
     * - Route not found errors
     * - Any other errors thrown during execution
     *
     * These errors are serialized separately from the route response and sent to the client
     * in the thrownErrors middleFn response, allowing them to be properly deserialized
     * without being part of the route's type signature.
     */
    readonly thrownErrors?: Readonly<Record<string, RpcError<string>>>;
}

MionResponse

mion's Response object, does not depend on the underlying native response.

/** Router's own response object, do not confuse with the underlying raw response */
export interface MionResponse {
    /** response http status code */
    readonly statusCode: number;
    /** response headers */
    readonly headers: Readonly<MionHeaders>;
    /** Raw response body, can be string for json or an arrayBuffer for binary. */
    readonly rawBody: RawResponseBody;
    readonly serializer: SerializerCode;
    /** the router response data, body should not be modified manually so marked as Read Only */
    readonly body: Readonly<ResponseBody>;
    /** response errors: empty if there were no errors during execution */
    readonly hasErrors: boolean;
    readonly binSerializer?: DataViewSerializer | undefined;
}

MionHeaders

mion's headers object, similar to the Fetch API Headers.

export interface MionHeaders {
    append(name: string, value: string): void;
    delete(name: string): void;
    set(name: string, value: string): void;
    get(name: string): string | undefined | null;
    has(name: string): boolean;
    entries(): IterableIterator<[string, string]>;
    keys(): IterableIterator<string>;
    values(): IterableIterator<string>;
}

ResponseBody

The response body structure containing results and any thrown errors.

/** Response body, a record containing the result of each handler or an error. */
export interface ResponseBody extends Record<string, any> {
    '@thrownErrors'?: Record<string, RpcError<string>>;
}