CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-inversify-express-utils

Express utilities and decorators for building web applications with Inversify dependency injection container

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

base-controller.mddocs/

Base Controller

Base controller class providing helper methods for common HTTP responses and access to HTTP context. The BaseHttpController class includes methods for standard status codes and content negotiation, making it easy to return structured responses.

Capabilities

BaseHttpController Class

Abstract base class that controllers can extend to gain access to HTTP context and response helper methods.

/**
 * Base class for HTTP controllers with helper methods for common responses
 */
class BaseHttpController {
  /** Protected access to HTTP context for the current request */
  protected readonly httpContext: HttpContext;
}

Success Response Methods

Methods for returning successful HTTP responses with various status codes.

/**
 * Returns a 200 OK response with content
 * @param content - Response content to return
 */
protected ok<T>(content: T): OkNegotiatedContentResult<T>;

/**
 * Returns a 200 OK response without content
 */
protected ok(): OkResult;

/**
 * Returns a 201 Created response with location and content
 * @param location - Location of the created resource
 * @param content - Created resource content
 */
protected created<T>(location: string | URL, content: T): CreatedNegotiatedContentResult<T>;

Error Response Methods

Methods for returning error HTTP responses with appropriate status codes.

/**
 * Returns a 400 Bad Request response without message
 */
protected badRequest(): BadRequestResult;

/**
 * Returns a 400 Bad Request response with error message
 * @param message - Error message to include in response
 */
protected badRequest(message: string): BadRequestErrorMessageResult;

/**
 * Returns a 404 Not Found response
 */
protected notFound(): NotFoundResult;

/**
 * Returns a 409 Conflict response
 */
protected conflict(): ConflictResult;

/**
 * Returns a 500 Internal Server Error response without details
 */
protected internalServerError(): InternalServerErrorResult;

/**
 * Returns a 500 Internal Server Error response with exception details
 * @param error - Error object to include in response
 */
protected internalServerError(error: Error): ExceptionResult;

Specialized Response Methods

Methods for specialized HTTP responses and content types.

/**
 * Returns a redirect response
 * @param uri - URI to redirect to
 */
protected redirect(uri: string | URL): RedirectResult;

/**
 * Returns a response with custom status code
 * @param statusCode - HTTP status code to return
 */
protected statusCode(statusCode: number): StatusCodeResult;

/**
 * Returns a JSON response with custom status code
 * @param content - Content to serialize as JSON
 * @param statusCode - HTTP status code (defaults to 200)
 */
protected json(content: unknown, statusCode?: number): JsonResult;

/**
 * Returns a streaming response
 * @param readableStream - Readable stream to pipe to response
 * @param contentType - MIME type of the stream content
 * @param statusCode - HTTP status code (defaults to 200)
 */
protected stream(
  readableStream: Readable,
  contentType: string,
  statusCode?: number
): StreamResult;

/**
 * Returns a custom HTTP response message
 * @param message - HttpResponseMessage to return
 */
protected responseMessage(message: HttpResponseMessage): ResponseMessageResult;

Usage Examples:

import { controller, httpGet, httpPost, BaseHttpController, requestParam, requestBody } from "inversify-express-utils";

@controller("/users")
class UserController extends BaseHttpController {
  @httpGet("/:id")
  async getUser(@requestParam("id") id: string) {
    const user = await this.userService.findById(id);
    
    if (!user) {
      return this.notFound();
    }
    
    return this.ok(user);
  }

  @httpPost("/")
  async createUser(@requestBody() userData: CreateUserDto) {
    try {
      const existingUser = await this.userService.findByEmail(userData.email);
      if (existingUser) {
        return this.conflict();
      }

      const newUser = await this.userService.create(userData);
      return this.created(`/users/${newUser.id}`, newUser);
    } catch (error) {
      return this.internalServerError(error);
    }
  }

  @httpGet("/")
  async getUsers(@queryParam("format") format: string) {
    const users = await this.userService.findAll();
    
    if (format === "csv") {
      const csvStream = this.userService.getUsersCsv();
      return this.stream(csvStream, "text/csv");
    }
    
    return this.json(users, 200);
  }

  @httpPost("/:id/validate")
  async validateUser(@requestParam("id") id: string, @requestBody() data: any) {
    if (!data.token) {
      return this.badRequest("Validation token is required");
    }

    const isValid = await this.userService.validateToken(id, data.token);
    if (!isValid) {
      return this.badRequest("Invalid validation token");
    }

    return this.ok({ message: "User validated successfully" });
  }

  @httpGet("/:id/profile-image")
  async getProfileImage(@requestParam("id") id: string) {
    const user = await this.userService.findById(id);
    if (!user || !user.profileImagePath) {
      return this.notFound();
    }

    return this.redirect(`/static/images/${user.profileImagePath}`);
  }

  @httpPost("/:id/custom-response")
  async customResponse(@requestParam("id") id: string) {
    const response = new HttpResponseMessage(202);
    response.headers["X-Custom-Header"] = "custom-value";
    response.content = new JsonContent({ 
      message: "Processing started",
      userId: id 
    });

    return this.responseMessage(response);
  }
}

HTTP Context Access

The base controller provides protected access to the HTTP context for advanced scenarios.

/**
 * HTTP context providing access to container, request, response, and user
 */
interface HttpContext<T = unknown> {
  /** Child container for request-scoped dependencies */
  container: interfaces.Container;
  /** Express request object */
  request: Request;
  /** Express response object */  
  response: Response;
  /** Authenticated user principal */
  user: Principal<T>;
}

Usage Examples:

@controller("/advanced")
class AdvancedController extends BaseHttpController {
  @httpGet("/context-info")
  getContextInfo() {
    // Access HTTP context directly
    const { request, user, container } = this.httpContext;
    
    return this.ok({
      method: request.method,
      path: request.path,
      userAgent: request.headers["user-agent"],
      isAuthenticated: await user.isAuthenticated(),
      containerHasDependency: container.isBound("SomeService")
    });
  }

  @httpPost("/resolve-service")
  async resolveService() {
    // Use container from HTTP context
    const customService = this.httpContext.container.get<CustomService>("CustomService");
    const result = await customService.performOperation();
    
    return this.ok(result);
  }
}

docs

auth.md

base-controller.md

decorators.md

index.md

middleware.md

results.md

server.md

tile.json