Transformer
Morphis transformers are HTTP middleware components that reshape request data before the handler runs, and optionally reshape the returned value after the handler runs.
The feature is implemented by TransformerMiddleware and the Transform(...) helper.
Generate a transformer
Morphis includes a dedicated generator for transformer classes:
morphis new:transformer PostResponseTransformerThis creates src/transformers/PostResponseTransformer.ts:
import { Transformer } from 'morphis';
export class PostResponseTransformer extends Transformer<any, any> {
transform(data: any) {
return data;
}
}Transformer class names must be PascalCase and end with Transformer.
Core idea
Each transformer class extends the base Transformer<TIn, TOut> type and implements one method:
import { Transformer } from 'morphis';
export class PostResponseTransformer extends Transformer<any, any> {
transform(data: any) {
return data;
}
}Transform({ ... }) then attaches those classes to a route.
What can be transformed
The current TransformMap supports these keys:
headerstransforms request headers before the handlerbodytransforms the parsed request body before the handlerparamstransforms route params before the handlerquerytransforms query values before the handlerrestransforms the value returned by the handler
Actual execution order
From the source code, TransformerMiddleware.handler() behaves like this:
- instantiate and run each configured request-side transformer
- mutate
req.headers,req.body,req.params, orreq.query - call
next(req) - if
resexists, transform the returned value - return the transformed result
So transformers are not passive serializers. They actively rewrite the request object that the controller receives.
Decorator usage
The intended public API is the method decorator form:
import { Post, Request, Transform } from 'morphis';
@Post()
@Transform({ body: PostBodyTransformer, res: PostResponseTransformer })
async create(req: Request) {
return postService.create(req.body);
}@Transform(...) wraps the controller method so the middleware runs around the handler.
Request transformation example
Use request transformers when you want controller code to work with a normalized shape.
import { Transformer } from 'morphis';
export class PostBodyTransformer extends Transformer<any, { title: string; body: string }> {
transform(data: any) {
return {
title: String(data.title ?? '').trim(),
body: String(data.body ?? '').trim(),
};
}
}With this transformer in place, req.body inside the controller becomes the transformed object.
Response transformation example
Use a response transformer when you want to reshape domain objects before the router serializes them to JSON.
import { Transformer } from 'morphis';
export class PostResponseTransformer extends Transformer<any, any> {
transform(post: any) {
return {
id: post.id,
title: post.title,
preview: String(post.body ?? '').slice(0, 120),
};
}
}If the handler returns a plain value, the transformed output is what Morphis later wraps in Response.json(...).
Validation and transformation together
Transformers are often paired with validation.
The router composes route middleware so validation wraps transformation, and transformation wraps connection resolution and the final handler. In practice, that means:
- validation runs first
- transformation runs after validation succeeds
- the controller receives validated and then transformed request data
This is why transformers are a good place for normalization and output shaping, while validators remain responsible for correctness checks.
Async transformers are supported
The base Transformer contract allows transform() to return either a value or a Promise, so asynchronous transformation is supported.