Back to Skills

create-middleware

majiayu000
Updated Today
1 views
58
9
58
View on GitHub
Metageneral

About

This Claude skill generates Hono middleware for cross-cutting concerns like authentication, validation, and error handling. It creates properly structured middleware files in the correct project location when triggered by phrases like "create middleware" or "auth middleware." The output follows naming conventions and includes examples for common middleware types.

Quick Install

Claude Code

Recommended
Plugin CommandRecommended
/plugin add https://github.com/majiayu000/claude-skill-registry
Git CloneAlternative
git clone https://github.com/majiayu000/claude-skill-registry.git ~/.claude/skills/create-middleware

Copy and paste this command in Claude Code to install this skill

Documentation

Create Middleware

Creates Hono middleware for cross-cutting concerns like authentication, validation, and error handling.

Quick Reference

Location: src/middlewares/{middleware-name}.middleware.ts Naming: Descriptive, kebab-case (e.g., auth.middleware.ts, validation.middleware.ts)

Middleware Types

Examples of middleware types:

TypePurposeExample
AuthenticationVerify user identity, set c.var.userauth.middleware.ts
ValidationValidate request data, set validated varsvalidation.middleware.ts
Error HandlingGlobal error handler for consistent errorsIn src/errors.ts

Creating Authentication Middleware

Step 1: Create the File

Create src/middlewares/auth.middleware.ts

Step 2: Define Dependencies Interface

import { createMiddleware } from "hono/factory";
import type { AppEnv } from "@/schemas/app-env.schema";
import { AuthenticationService } from "@/services/authentication.service";
import { UnauthenticatedError } from "@/errors";

export interface AuthMiddlewareDeps {
  authenticationService: AuthenticationService;
}

Step 3: Create Factory Function

export const createAuthMiddleware = (deps: AuthMiddlewareDeps) => {
  const { authenticationService } = deps;

  return createMiddleware<AppEnv>(async (c, next) => {
    const authHeader = c.req.header("Authorization");
    if (!authHeader)
      throw new UnauthenticatedError("Authorization header is missing.");

    const parts = authHeader.split(" ");
    let token: string | undefined;

    if (parts.length === 2 && parts[0].toLowerCase() === "bearer") {
      token = parts[1];
    }
    if (!token) throw new UnauthenticatedError("Invalid authorization format.");

    // Will throw errors if it cannot authenticate
    const user = await authenticationService.authenticateUserByToken(token);

    c.set("user", user);
    await next();
  });
};

Step 4: Export Default Instance

const defaultAuthenticationService = new AuthenticationService();
export const authMiddleware = createAuthMiddleware({
  authenticationService: defaultAuthenticationService,
});

Creating Validation Middleware

The validation middleware is generic and validates body, query, or params using Zod schemas.

Factory Function

import type { MiddlewareHandler } from "hono";
import { createMiddleware } from "hono/factory";
import type { ZodTypeAny } from "zod";
import type { AppEnv } from "@/schemas/app-env.schema";
import { BadRequestError, InternalServerError } from "@/errors";

export type ValidationDataSource = "body" | "query" | "params";

interface ValidationOptions {
  schema: ZodTypeAny;
  source: ValidationDataSource;
  varKey: string;
}

export const validate = (
  options: ValidationOptions,
): MiddlewareHandler<AppEnv> => {
  const { schema, source, varKey } = options;

  return createMiddleware<AppEnv>(async (c, next) => {
    let dataToValidate: unknown;

    try {
      switch (source) {
        case "body":
          dataToValidate = await c.req.json();
          break;
        case "query":
          dataToValidate = c.req.query();
          break;
        case "params":
          dataToValidate = c.req.param();
          break;
        default:
          throw new InternalServerError();
      }
    } catch (error) {
      if (error instanceof InternalServerError) throw error;
      throw new BadRequestError(`Invalid request ${source}.`);
    }

    const result = schema.safeParse(dataToValidate);

    if (!result.success) {
      const fieldErrors = result.error.flatten().fieldErrors;
      const fieldErrorMessages = Object.entries(fieldErrors)
        .map(([field, errors]) => `${field}: ${errors?.join(", ")}`)
        .join("; ");
      throw new BadRequestError(
        `Validation failed for ${source}. ${fieldErrorMessages}`,
        { cause: result.error.flatten() },
      );
    }

    c.set(varKey as keyof AppEnv["Variables"], result.data);
    await next();
  });
};

Patterns & Rules

Use createMiddleware Factory

Always use Hono's createMiddleware with AppEnv type:

import { createMiddleware } from "hono/factory";
import type { AppEnv } from "@/schemas/app-env.schema";

return createMiddleware<AppEnv>(async (c, next) => {
  // Middleware logic
  await next();
});

Dependency Injection Pattern

Create a factory function that accepts dependencies:

export interface MyMiddlewareDeps {
  someService: SomeService;
}

export const createMyMiddleware = (deps: MyMiddlewareDeps) => {
  return createMiddleware<AppEnv>(async (c, next) => {
    // Use deps.someService
    await next();
  });
};

// Export default instance
export const myMiddleware = createMyMiddleware({
  someService: new SomeService(),
});

Setting Context Variables

Store data for downstream handlers using c.set():

// In middleware
c.set("user", authenticatedUser);
c.set("validatedBody", parsedData);

// In controller
const user = c.var.user as AuthenticatedUserContextType;

Error Throwing

Throw domain errors - global handler converts to HTTP responses:

import { UnauthenticatedError, BadRequestError } from "@/errors";

// Authentication errors
if (!token) throw new UnauthenticatedError("Missing token");

// Validation errors
if (!result.success) throw new BadRequestError("Invalid data");

Always Call next()

After successful processing, always call await next():

return createMiddleware<AppEnv>(async (c, next) => {
  // Process request...

  // Pass to next handler
  await next();
});

Global Error Handler

The global error handler converts domain errors to HTTP responses:

// In src/errors.ts
export const globalErrorHandler = (err: Error, c: Context<AppEnv>) => {
  console.error(err);

  if (err instanceof BaseError) {
    return createErrorResponse(c, err);
  } else if (err instanceof HTTPException) {
    return c.json({ error: err.message }, err.status);
  } else {
    const internalError = new InternalServerError(
      "An unexpected error occurred",
      { cause: err },
    );
    return createErrorResponse(c, internalError);
  }
};

// Register in app setup
app.onError(globalErrorHandler);

Complete Examples

See REFERENCE.md for complete examples:

  • auth.middleware.ts - Authentication with dependency injection
  • validation.middleware.ts - Generic validation middleware

Usage in Routes

import { authMiddleware } from "@/middlewares/auth.middleware";
import { validate } from "@/middlewares/validation.middleware";
import { createNoteSchema, noteQueryParamsSchema } from "@/schemas/note.schema";
import { entityIdParamSchema } from "@/schemas/shared.schema";

// Apply to routes
router.get(
  "/",
  authMiddleware,
  validate({
    schema: noteQueryParamsSchema,
    source: "query",
    varKey: "validatedQuery",
  }),
  controller.getAll,
);

router.post(
  "/",
  authMiddleware,
  validate({
    schema: createNoteSchema,
    source: "body",
    varKey: "validatedBody",
  }),
  controller.create,
);

router.get(
  "/:id",
  authMiddleware,
  validate({
    schema: entityIdParamSchema,
    source: "params",
    varKey: "validatedParams",
  }),
  controller.getById,
);

What NOT to Do

  • Do NOT use MiddlewareHandler type directly (use createMiddleware factory)
  • Do NOT forget to call await next()
  • Do NOT catch errors (let global handler catch them)
  • Do NOT access process.env directly (use @/env)
  • Do NOT put business logic in middleware (that's for services)

See Also

  • create-routes - Wire middleware to routes
  • add-error-type - Add custom error types
  • test-middleware - Test middleware handlers

GitHub Repository

majiayu000/claude-skill-registry
Path: skills/create-middleware

Related Skills

algorithmic-art

Meta

This Claude Skill creates original algorithmic art using p5.js with seeded randomness and interactive parameters. It generates .md files for algorithmic philosophies, plus .html and .js files for interactive generative art implementations. Use it when developers need to create flow fields, particle systems, or other computational art while avoiding copyright issues.

View skill

subagent-driven-development

Development

This skill executes implementation plans by dispatching a fresh subagent for each independent task, with code review between tasks. It enables fast iteration while maintaining quality gates through this review process. Use it when working on mostly independent tasks within the same session to ensure continuous progress with built-in quality checks.

View skill

executing-plans

Design

Use the executing-plans skill when you have a complete implementation plan to execute in controlled batches with review checkpoints. It loads and critically reviews the plan, then executes tasks in small batches (default 3 tasks) while reporting progress between each batch for architect review. This ensures systematic implementation with built-in quality control checkpoints.

View skill

cost-optimization

Other

This Claude Skill helps developers optimize cloud costs through resource rightsizing, tagging strategies, and spending analysis. It provides a framework for reducing cloud expenses and implementing cost governance across AWS, Azure, and GCP. Use it when you need to analyze infrastructure costs, right-size resources, or meet budget constraints.

View skill