cloudflare-dtty v0.3.5
dtty
Dependency Injection + Itty Router = dtty.
Web framework for Cloudflare workers inspired by NestJS.
Initialization
To use Dtty, simply create a new instance and let it handle all incoming requests.
// index.ts
const app = new Dtty();
export default {
  async fetch(
    request: Request,
    env?: Record<string, any>,
    ctx?: ExecutionContext,
  ): Promise<Response> {
    return app.handle(request, env, ctx);
  },
};Routing
Controllers are registered through the Dtty.registerControllers method. This handles the mapping of routes and application of controller level and method level middleware.
@Controller("/route")
class RouteController {
  @Get("/")
  handleGet() {}
  @Post("/")
  handlePost() {}
  @Put("/")
  handlePut() {}
  @Delete("/")
  handleDelete() {}
}
/* ----- */
app.registerControllers(
  // Array of controller classes
  RouteController,
);Route params
Route parameters can be injected into controller methods with the @Param() decorator which takes an optional string to inject an individual parameter as opposed to all the parameters.
Optionally, the @Param() decorator takes a second parameter that to parse and validate the parameter. For example, if an endpoint expects an id parameter of type number (e.g /request/1234), the included IntegerTransformer will automatically validate that the parameter is an integer and will transform the string into an integer before supplying it to the controller handler.
Included Transformers
- IntegerTransformer
- UuidTransformer
@Get('/route/:id')
getRouteById(@Param("id") id: string) {}
@Get('/route/:id')
getRouteByNumberId(@Param("id", IntegerTransformer) id: number) {}Query Params
Much like route parameters, query parameters can be injected into the controller with the @Query() decorator. The decorator takes a configuration object to inject either an individual parameter or all the parameters with optional transformation and validation.
When working with esbuild, some of the metadata that typescript emits and class-transformer relies upon is missing. Therefore, all class properties should be decorated with the @Type decorator to manually specify the type of the field.
  @Get('/named')
  handleNamedParam(@Query({paramName: "test"}) value: string) {
    // maps the parameter named `test` out without transformation
  }
  @Get('/unnamed')
  handleUnnamed(@Query() values: Record<string, unknown>) {
    // maps all the query parameters out without transformation or validation
  }
  @Get('/named/transformed')
  handleNamedAndTransformed(@Query({paramName: "test", transformer: IntegerTransformer}) value: number) {
    // maps the parameter named `test` out and transforms into an integer
  }
  @Get('/unnamed/validated')
  handleUnnamedAndValidated(@Query({paramsType: QueryDto}) values: QueryDto) {
    // maps all the query parameters out and transforms and validates against a class definition
  }Body
The request body can be both validated and injected into controller methods via the @Body() decorator. This decorator optionally takes a class constructor to perform transformation and validation via class-transformer and class-validator respectively.
@Put('/route/:id')
updateRouteById(@Param('id') id: string, @Body(UpdateRouteDto) body: UpdateRouteDto) {}Exception Handling
Exceptions thrown by an endpoint are caught at three levels:
- Method
- Controller
- Global
Dtty provides an interface called ExceptionHandler to define how classes can be used to catch and handle exceptions. The HandleException decorator optionally takes a parameter to filter exceptions by type to enable finer grained control over exception handling logic. For a given exception:
- Evaluate any method level exception handlers for the specific exception type
- Evaluate any un-filtered method level exception handlers
- Evaluate any controller level exception handlers for the specific exception type
- Evaluate any un-filtered controller level exception handlers
- Evaluate any global level exception handlers for the specific exception type
- Evaluate any un-filtered global level exception handlers
If no exception handlers are found, the application will return with code 500.
@Controller()
@ApplyHandlers(ControllerExceptionHandler)
export class IndexController {
  @Get("")
  @ApplyHandlers(MethodExceptionHandler, GenericHandler)
  getIndex() {}
}Roadmap
- Global middleware
- Controller middleware
- Route middleware
- Global body transformer
- Global body validator
- Route param transformer / validator
- Global exception handler
- Controller exception handler
- Route exception handler
- URL query param mapper
- URL query param transformer / validator
- Optimizations for tree shaking
- Custom DI library
- UUID transformer
- Async constructors
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago