effect-patterns-building-apis | Skill Performance & Reviews | TopRankSkills

TopRank Skills

Home / Skills / tools / effect-patterns-building-apis

effect-patterns-building-apis

maintained by PaulJPhilp

star 623 account_tree 20 verified_user MIT License
bolt View GitHub

name: effect-patterns-building-apis description: Effect-TS patterns for Building Apis. Use when working with building apis in Effect-TS applications.

Effect-TS Patterns: Building Apis

This skill provides 13 curated Effect-TS patterns for building apis. Use this skill when working on tasks related to:

  • building apis
  • Best practices in Effect-TS applications
  • Real-world patterns and solutions

🟢 Beginner Patterns

Handle a GET Request

Rule: Use Http.router.get to associate a URL path with a specific response Effect.

Good Example:

This example defines two separate GET routes, one for the root path (/) and one for /hello. We create an empty router and add each route to it. The resulting app is then served. The router automatically handles sending a 404 Not Found response for any path that doesn't match.

import { Data, Effect } from "effect";

// Define response types
interface RouteResponse {
  readonly status: number;
  readonly body: string;
}

// Define error types
class RouteNotFoundError extends Data.TaggedError("RouteNotFoundError")<{
  readonly path: string;
}> {}

class RouteHandlerError extends Data.TaggedError("RouteHandlerError")<{
  readonly path: string;
  readonly error: string;
}> {}

// Define route service
class RouteService extends Effect.Service<RouteService>()("RouteService", {
  sync: () => {
    // Create instance methods
    const handleRoute = (
      path: string
    ): Effect.Effect<RouteResponse, RouteNotFoundError | RouteHandlerError> =>
      Effect.gen(function* () {
        yield* Effect.logInfo(`Processing request for path: ${path}`);

        try {
          switch (path) {
            case "/":
              const home = "Welcome to the home page!";
              yield* Effect.logInfo(`Serving home page`);
              return { status: 200, body: home };

            case "/hello":
              const hello = "Hello, Effect!";
              yield* Effect.logInfo(`Serving hello page`);
              return { status: 200, body: hello };

            default:
              yield* Effect.logWarning(`Route not found: ${path}`);
              return yield* Effect.fail(new RouteNotFoundError({ path }));
          }
        } catch (e) {
          const error = e instanceof Error ? e.message : String(e);
          yield* Effect.logError(`Error handling route ${path}: ${error}`);
          return yield* Effect.fail(new RouteHandlerError({ path, error }));
        }
      });

    // Return service implementation
    return {
      handleRoute,
      // Simulate GET request
      simulateGet: (
        path: string
      ): Effect.Effect<RouteResponse, RouteNotFoundError | RouteHandlerError> =>
        Effect.gen(function* () {
          yield* Effect.logInfo(`GET ${path}`);
          const response = yield* handleRoute(path);
          yield* Effect.logInfo(`Response: ${JSON.stringify(response)}`);
          return response;
        }),
    };
  },
}) {}

// Create program with proper error handling
const program = Effect.gen(function* () {
  const router = yield* RouteService;

  yield* Effect.logInfo("=== Starting Route Tests ===");

  // Test different routes
  for (const path of ["/", "/hello", "/other", "/error"]) {
    yield* Effect.logInfo(`\n--- Testing ${path} ---`);

    const result = yield* router.simulateGet(path).pipe(
      Effect.catchTags({
        RouteNotFoundError: (error) =>
          Effect.gen(function* () {
            const response = { status: 404, body: `Not Found: ${error.path}` };
            yield* Effect.logWarning(`${response.status} ${response.body}`);
            return response;
          }),
        RouteHandlerError: (error) =>
          Effect.gen(function* () {
            const response = {
              status: 500,
              body: `Internal Error: ${error.error}`,
            };
            yield* Effect.logError(`${response.status} ${response.body}`);
            return response;
          }),
      })
    );

    yield* Effect.logInfo(`Final Response: ${JSON.stringify(result)}`);
  }

  yield* Effect.logInfo("\n=== Route Tests Complete ===");
});

// Run the program
Effect.runPromise(Effect.provide(program, RouteService.Default));

Anti-Pattern:

The anti-pattern is to create a single, monolithic handler that uses conditional logic to inspect the request URL. This imperative approach is difficult to maintain and scale.

import { Effect } from "effect";
import { Http, NodeHttpServer, NodeRuntime } from "@effect/platform-node";

// A single app that manually checks the URL
const app = Http.request.ServerRequest.pipe(
  Effect.flatMap((req) => {
    if (req.url === "/") {
      return Effect.succeed(Http.response.text("Welcome to the home page!"));
    } else if (req.url === "/hello") {
      return Effect.succeed(Http.response.text("Hello, Effect!"));
    } else {
      return Effect.succeed(Http.response.empty({ status: 404 }));
    }
  })
);

const program = 

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!

Skill Details

GitHub Stars 623
GitHub Forks 20
Created Jan 2026
Last Updated 5个月前
tools tools architecture patterns

Related Skills

dagger-design-proposals
chevron_right
nestjs-expert
chevron_right
docker-expert
chevron_right
kafka-streams-topology
chevron_right
kafka-architecture
chevron_right

Build your own?

Join 12,000+ developers contributing to the Claude ecosystem.