Custom Pipes in Moost 
This guide walks you through creating a custom pipe using Moost’s metadata system, enabling parameter-specific transformations.
Key Concepts 
Metadata System:
Moost utilizes a metadata-driven approach to parameterize pipes. By decorating parameters or properties, you attach metadata that guides how pipes should process each piece of data.Pipeline Execution:
During pipeline execution, pipes read the associated metadata to determine the appropriate transformation logic. This ensures that each data element is processed according to its specific requirements.Decorator Integration:
Custom decorators are used to attach metadata to parameters or properties, which the pipes then utilize during execution.
Creating a Custom Pipe: Case Transformation Example 
Let’s create a custom pipe that transforms string values to different cases — uppercase, lowercase, camelCase, and PascalCase — based on metadata applied via decorators.
Step 1: Define the Pipe and Decorators 
First, create a file named case-pipe.ts and define the custom pipe along with decorators to specify the desired case transformation.
// case-pipe.ts
import { definePipeFn, getMoostMate, TPipePriority } from "moost";
// Define a custom metadata type to store the case-pipe option
type TCustomMeta = {
  casePipeOption?: "lower" | "upper" | "camel" | "pascal";
};
// Get the @prostojs/mate instance used in Moost
const mate = getMoostMate<TCustomMeta, TCustomMeta, TCustomMeta>();
// Define decorators for case transformations
export const Uppercase = () => mate.decorate("casePipeOption", "upper");
export const Lowercase = () => mate.decorate("casePipeOption", "lower");
export const Camelcase = () => mate.decorate("casePipeOption", "camel");
export const Pascalcase = () => mate.decorate("casePipeOption", "pascal");
// Define the case-pipe
export const casePipe = definePipeFn<TCustomMeta>((value, metas, level) => {
  const caseOption =
    metas.paramMeta?.casePipeOption ||
    metas.methodMeta?.casePipeOption ||
    metas.classMeta?.casePipeOption;
  switch (caseOption) {
    case "upper":
      return typeof value === "string" ? value.toUpperCase() : value;
    case "lower":
      return typeof value === "string" ? value.toLowerCase() : value;
    case "camel":
      return typeof value === "string"
        ? value
            .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) =>
              index === 0 ? word.toLowerCase() : word.toUpperCase()
            )
            .replace(/\s+/g, "")
        : value;
    case "pascal":
      return typeof value === "string"
        ? value
            .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => word.toUpperCase())
            .replace(/\s+/g, "")
        : value;
    default:
      return value;
  }
}, TPipePriority.TRANSFORM);Explanation:
- Metadata Definition (
TCustomMeta):
Defines a custom metadata type to store the case transformation option. 
WARNING
When defining custom metadata for your pipes, ensure that the metadata property names are unique and do not conflict with Moost's native metadata or any third-party metadata. In this example, the metadata property casePipeOption is used specifically for the custom case transformation pipe. Using unique names prevents unintended behavior and maintains compatibility within your application.
type TCustomMeta = {
  casePipeOption?: "lower" | "upper" | "camel" | "pascal";
};Note: Always choose distinctive names for custom metadata properties to avoid collisions with existing or future metadata keys used by Moost or other integrated libraries.
Decorators (
Uppercase,Lowercase,Camelcase,Pascalcase):
These decorators attach the desired case transformation option to parameters or properties.Pipe Definition (
casePipe):
ThecasePipefunction reads the metadata and applies the appropriate case transformation to the input value.
Step 2: Apply the Custom Pipe in a Controller 
Next, create a controller that utilizes the custom pipe to transform input data based on the attached decorators.
// controllers/app.controller.ts
import { Get, Query } from '@moostjs/event-http';
import { Controller, Param, Pipe } from 'moost';
import { casePipe, Pascalcase, Uppercase } from '../case-pipe';
@Pipe(casePipe) // Apply the case-pipe to the controller
@Controller()
export class AppController {
  
  @Get("hello/:name")
  greet(
    @Uppercase() // Transform the 'name' parameter to uppercase
    @Param("name") 
    name: string,
    @Pascalcase() // Transform the 'jobTitle' query parameter to PascalCase
    @Query("jobTitle") 
    jobTitle: string
  ) {
    return `Hello, ${name}!\nJob Title: ${jobTitle || "unknown"}`;
  }
}Explanation:
Controller-Level Pipe (
@Pipe(casePipe)):
Applies thecasePipeto all parameters and properties within theAppController.Parameter Decorators (
@Uppercase(),@Pascalcase()):
Attach specific case transformation metadata to individual parameters.Handler Method (
greet):
Receives transformed parameters based on the attached decorators.
Step 3: Testing the Custom Pipe 
Start your Moost application and test the custom pipe functionality using curl or any HTTP client.
curl -X GET http://localhost:3000/hello/Joe?jobTitle=node%20js%20backend%20developerExpected Response:
Hello, JOE!
Job Title: NodeJsBackendDeveloperExplanation:
- The 
nameparameter (Joe) is transformed to uppercase (JOE) due to the@Uppercase()decorator. - The 
jobTitlequery parameter (node js backend developer) is transformed to PascalCase (NodeJsBackendDeveloper) due to the@Pascalcase()decorator. 
Detailed Breakdown 
1. Defining Custom Decorators 
Custom decorators (Uppercase, Lowercase, Camelcase, Pascalcase) are created using Moost’s metadata system. These decorators attach specific transformation options to the parameters or properties they decorate.
export const Uppercase = () => mate.decorate("casePipeOption", "upper");
export const Lowercase = () => mate.decorate("casePipeOption", "lower");
export const Camelcase = () => mate.decorate("casePipeOption", "camel");
export const Pascalcase = () => mate.decorate("casePipeOption", "pascal");2. Creating the Pipe Function 
The casePipe function processes the input value based on the attached metadata. It reads the casePipeOption from metadata and applies the corresponding transformation.
export const casePipe = definePipeFn<TCustomMeta>((value, metas, level) => {
  const caseOption =
    metas.paramMeta?.casePipeOption ||
    metas.methodMeta?.casePipeOption ||
    metas.classMeta?.casePipeOption;
  switch (caseOption) {
    case "upper":
      return typeof value === "string" ? value.toUpperCase() : value;
    case "lower":
      return typeof value === "string" ? value.toLowerCase() : value;
    case "camel":
      return typeof value === "string"
        ? value
            .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) =>
              index === 0 ? word.toLowerCase() : word.toUpperCase()
            )
            .replace(/\s+/g, "")
        : value;
    case "pascal":
      return typeof value === "string"
        ? value
            .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => word.toUpperCase())
            .replace(/\s+/g, "")
        : value;
    default:
      return value;
  }
}, TPipePriority.TRANSFORM);3. Attaching Pipes via Decorators 
Decorators are used to attach the custom pipe metadata to specific parameters or properties. When the pipeline runs, it reads this metadata to apply the transformations.
@Pipe(casePipe) // Apply the custom pipe to the controller
@Controller()
export class AppController {
  
  @Get("hello/:name")
  greet(
    @Uppercase() // Apply uppercase transformation
    @Param("name") 
    name: string,
    @Pascalcase() // Apply PascalCase transformation
    @Query("jobTitle") 
    jobTitle: string
  ) {
    return `Hello, ${name}!\nJob Title: ${jobTitle || "unknown"}`;
  }
}