Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: generic action type #1454

Closed

Conversation

periakteon
Copy link

Description

Checklist

  • the pull request title describes what this PR does (not a vague title like Update index.md)
  • the pull request targets the default branch of the repository (develop)
  • the code follows the established code style of the repository
    • npm run prettier:check passes
    • npm run lint:check passes
  • tests are added for the changes I made (if any source code was modified)
  • documentation added or updated
  • I have run the project locally and verified that there are no errors

Generic Action Interface in routing-controllers

Introduction

The routing-controllers library has introduced a generic Action interface to provide better type safety and flexibility when working with different web frameworks or custom request/response types.

Why We Need Generic Action Types

  1. Type Safety: Generic types allow for stronger type checking, reducing runtime errors and improving code quality.

  2. Framework Flexibility: Different web frameworks (e.g., Express, Koa) have different request and response object structures. Generic types allow us to adapt to these differences easily.

  3. Custom Types: Projects often extend or modify standard request/response objects. Generics enable the use of these custom types without losing type information.

  4. Better IntelliSense: IDE autocompletion and suggestions become more accurate when using properly typed actions.

  5. Code Readability: Explicit typing makes the code more self-documenting and easier to understand.

The New Action Interface

export interface Action<TRequest = any, TResponse = any, TContext = any, TNext extends Function = Function> {
  request: TRequest;
  response: TResponse;
  context?: TContext;
  next?: TNext;
}

Generic Parameters

  • TRequest: Type of the request object (default: any)
  • TResponse: Type of the response object (default: any)
  • TContext: Type of the context object (for Koa-specific usage, default: any)
  • TNext: Type of the next function (default: Function)

Usage Example

import { Action, JsonController, Get, Post, Body } from 'routing-controllers';
import { Request, Response } from 'express';

@JsonController()
export class UserController {
  @Get('/users')
  getUsers(@Req() req: Request, @Res() res: Response) {
    // Implementation
  }

  @Post('/users')
  createUser(@Body() user: User, action: Action<Request, Response>) {
    console.log(action.request.headers);
    action.response.status(201);
  }
}

Benefits

  1. Framework-Specific Typing: Easily use types specific to Express, Koa, or any other framework.
  2. Custom Request/Response Types: Integrate seamlessly with custom request or response types in your application.
  3. Improved Developer Experience: Better autocompletion and type checking in IDEs.
  4. Reduced Errors: Catch type-related issues at compile-time rather than runtime.

Conclusion

The introduction of generic types to the Action interface in routing-controllers significantly enhances the library's flexibility and type safety. It allows developers to write more robust and maintainable code while adapting to various frameworks and custom type definitions.

@periakteon periakteon changed the title feat: extended action type feat: generic action type Oct 26, 2024
@attilaorosz
Copy link
Member

Hi! I might be missing something here but this doesn’t seem functional. Could you include a unit test that is using this action parameter?

@periakteon
Copy link
Author

Hi! I might be missing something here but this doesn’t seem functional. Could you include a unit test that is using this action parameter?

We needed such a generic type feature due to a situation we encountered in our own service. There is an authorizationChecker function in our own service. When we tried to access the req object in the Action parameter in this function, we always encountered the any type. See:

Ekran Resmi 2024-10-28 08 48 08

However, when we gave the Action, interface the RequestandResponsetypes ofexpress, the req` object became type-safe:

Ekran Resmi 2024-10-28 08 50 03

We now have access to all the objects inside the req object. This is how I can express the context that led to such a need.

I would like to know if there is something I'm missing or if this is already possible with the current Action interface. If this kind of request is approved, I can also write a unit test later.

}

@Post('/users')
createUser(@Body() user: User, action: Action<Request, Response>) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The action parameter here is never resolved

@attilaorosz
Copy link
Member

I do understand why you think this would be useful, my concern is that the changes you made are not correct. The action parameter is not accessible for controllers, it was only exposed to the user validator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants