### Example Server for Prototyping in Effect-HTTP Source: https://context7.com/sukovanej/effect-http/llms.txt Generates a functional server implementation with example responses for rapid prototyping. This example uses `ExampleServer.make` to create a server based on the API definition and `NodeServer.listen` to start it. ```typescript import { NodeRuntime } from "@effect/platform-node"; import { Schema } from "effect"; import { Api, ExampleServer, RouterBuilder } from "effect-http"; import { NodeServer } from "effect-http-node"; const Response = Schema.Struct({ name: Schema.String, value: Schema.Number, }); const api = Api.make({ servers: ["http://localhost:3000"], }).pipe( Api.addEndpoint(Api.get("test", "/test").pipe(Api.setResponseBody(Response))) ); ExampleServer.make(api).pipe( RouterBuilder.build, NodeServer.listen({ port: 3000 }), NodeRuntime.runMain ); ``` -------------------------------- ### Generate Example Server from API Specification Source: https://github.com/sukovanej/effect-http/blob/master/README.md Create an example server implementation automatically derived from an Api specification using ExampleServer.make. This generates a working HTTP server that returns valid example responses conforming to the API schema, useful for API design, frontend-first development, and integration testing without a real backend. ```typescript import { NodeRuntime } from "@effect/platform-node"; import { Effect, Schema } from "effect"; import { Api, ExampleServer, RouterBuilder } from "effect-http"; import { NodeServer } from "effect-http-node"; const Response = Schema.Struct({ name: Schema.String, value: Schema.Number, }); const api = Api.make({ servers: ["http://localhost:3000", { description: "hello", url: "/api/" }], }).pipe( Api.addEndpoint(Api.get("test", "/test").pipe(Api.setResponseBody(Response))) ); ExampleServer.make(api).pipe( RouterBuilder.build, NodeServer.listen({ port: 3000 }), NodeRuntime.runMain ); ``` -------------------------------- ### Creating an API with Endpoints Source: https://context7.com/sukovanej/effect-http/llms.txt Define API specifications using the Api builder with typed endpoints, query parameters, and response schemas. This example shows how to create a simple API with a GET endpoint to retrieve a user. ```APIDOC ## GET /user ### Description Retrieves a user based on the provided ID. ### Method GET ### Endpoint /user ### Parameters #### Query Parameters - **id** (number) - Required - The ID of the user to retrieve. ### Request Example ```json { "id": 12 } ``` ### Response #### Success Response (200) - **name** (string) - The name of the user. - **id** (number) - The positive integer ID of the user. #### Response Example ```json { "name": "milan", "id": 12 } ``` ``` -------------------------------- ### Server Implementation - Building a Server with RouterBuilder Source: https://context7.com/sukovanej/effect-http/llms.txt Implement API handlers and build a running HTTP server using Effect-TS and effect-http. This example demonstrates how to handle the 'getUser' endpoint. ```APIDOC ## Server Handler for GET /user ### Description Provides the server-side implementation for the 'getUser' endpoint, returning user data based on query parameters. ### Method GET ### Endpoint /user ### Parameters #### Query Parameters - **id** (number) - Required - The ID of the user to retrieve. ### Request Example *Example handled by the client/router, not directly by the handler code snippet.* ### Response #### Success Response (200) - **name** (string) - The name of the user. - **id** (number) - The positive integer ID of the user. #### Response Example ```json { "name": "milan", "id": 12 } ``` ``` -------------------------------- ### Install effect-http with Dependencies Source: https://github.com/sukovanej/effect-http/blob/master/README.md Install effect-http and effect-http-node packages along with required peer dependencies. effect-http-node is required only for Node.js server runtime; effect-http alone suffices for browser-only usage. ```bash pnpm add effect-http effect-http-node ``` ```bash pnpm add effect @effect/platform @effect/platform-node ``` -------------------------------- ### Server Startup and Client Request (Bash) Source: https://github.com/sukovanej/effect-http/blob/master/README.md Demonstrates the command to start the server and the client command to make a POST request to the /users endpoint. The output shows the server logs and the client's 409 Conflict response. ```bash # Server $ pnpm tsx examples/conflict-error-example.ts # Client $ http localhost:3000/users name="patrik" ``` -------------------------------- ### Mock Client for Testing in Effect-HTTP Source: https://context7.com/sukovanej/effect-http/llms.txt Illustrates how to create mock clients for testing API integrations. It shows two methods: one that returns auto-generated example values and another that allows specifying exact responses using fixtures. ```typescript import { Schema } from "effect"; import { Api, MockClient } from "effect-http"; const api = Api.make().pipe( Api.addEndpoint( Api.get("getValue", "/value").pipe(Api.setResponseBody(Schema.Number)) ) ); // Returns auto-generated example values const client = MockClient.make(api); // Returns specified values const clientWithFixtures = MockClient.make(api, { responses: { getValue: 12 } }); ``` -------------------------------- ### Start Node.js HTTP Server with effect-http-node Source: https://github.com/sukovanej/effect-http/blob/master/README.md Launch an HTTP server on a specified port using NodeServer from effect-http-node. Integrates with Effect runtime for proper async handling and resource management. ```typescript import { NodeRuntime } from "@effect/platform-node"; import { NodeServer } from "effect-http-node"; app.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain); ``` -------------------------------- ### GET /hello with Request Header Source: https://github.com/sukovanej/effect-http/blob/master/README.md This endpoint requires a specific request header 'X-Client-Id' to be present for successful execution. ```APIDOC ## GET /hello ### Description This endpoint expects a GET request with a mandatory `X-Client-Id` header. ### Method GET ### Endpoint /hello ### Parameters #### Path Parameters (None) #### Query Parameters (None) #### Request Body (None) #### Headers - **X-Client-Id** (string) - Required - The client identifier. ### Request Example ```json { "headers": { "X-Client-Id": "some-client-id" } } ``` ### Response #### Success Response (200) - (string) - A string response. #### Response Example ```json "Hello, World!" ``` #### Error Response (400) - **error** (string) - Description of the error. - **location** (string) - The location of the validation error (e.g., 'headers'). - **message** (string) - A detailed error message. #### Error Response Example ```json { "error": "Request validation error", "location": "headers", "message": "x-client-id is missing" } ``` ``` -------------------------------- ### Custom Security with Effect Services and Context Source: https://context7.com/sukovanej/effect-http/llms.txt Demonstrates building complex authentication flows using Effect services and context propagation. This example integrates custom user information retrieval via a UserStorage service. Dependencies include 'effect' and 'effect-http'. ```typescript import { Effect, Layer, Context } from "effect"; import { Security } from "effect-http"; interface UserInfo { email: string; } class UserStorage extends Effect.Tag("UserStorage") Effect.Effect } >() { static dummy = Layer.succeed( UserStorage, UserStorage.of({ getInfo: (_: string) => Effect.succeed({ email: "email@gmail.com" }), }) ); } const mySecurity = Security.basic({ description: "My basic auth" }).pipe( Security.map((creds) => creds.user), Security.mapEffect((user) => UserStorage.getInfo(user)) ); const app = RouterBuilder.make(api).pipe( RouterBuilder.handle("endpoint", (_, security) => Effect.succeed(`Logged as ${security.email}`) ), RouterBuilder.build ); app.pipe( NodeServer.listen({ port: 3000 }), Effect.provide(UserStorage.dummy), NodeRuntime.runMain ); ``` -------------------------------- ### GET /stuff/:param/:another? with Optional Path Parameter Source: https://github.com/sukovanej/effect-http/blob/master/README.md This endpoint shows how to define an optional path parameter. The ':another' parameter can be omitted. ```APIDOC ## GET /stuff/:param/:another? ### Description This endpoint accepts a GET request with a required path parameter ':param' and an optional path parameter ':another'. ### Method GET ### Endpoint /stuff/:param/:another? ### Parameters #### Path Parameters - **param** (string) - Required - The primary path parameter. - **another** (string) - Optional - An optional secondary path parameter. ### Request Example ```json { } ``` ### Response #### Success Response (200) - **value** (number) - The response body contains a number. #### Response Example ```json { "value": 123 } ``` ``` -------------------------------- ### Define API and Router with GET Endpoint Source: https://github.com/sukovanej/effect-http/blob/master/README.md Creates an API definition with a GET endpoint and implements request handling using RouterBuilder. The handler receives query parameters and returns a string response. This setup serves as the foundation for testing and error handling in effect-http applications. ```typescript const api = Api.api().pipe( Api.get("hello", "/hello", { response: Schema.String, }) ); const app = RouterBuilder.make(api).pipe( RouterBuilder.handle("hello", ({ query }) => Effect.succeed(`${query.input + 1}`) ), RouterBuilder.build ); ``` -------------------------------- ### Define optional path parameters in effect-http Source: https://github.com/sukovanej/effect-http/blob/master/README.md Create API endpoints with optional path parameters by using a question mark in the path pattern and wrapping the schema with Schema.optional(). This allows clients to omit certain path parameters when making requests. The example defines a GET endpoint where the second path parameter is optional. ```typescript import { Schema } from "effect"; import { Api } from "effect-http"; const Stuff = Schema.Struct({ value: Schema.Number }); const StuffParams = Schema.Struct({ param: Schema.String, another: Schema.optional(Schema.String) }); export const api = Api.make({ title: "My api" }).pipe( Api.addEndpoint( Api.get("stuff", "/stuff/:param/:another?").pipe( Api.setResponseBody(Stuff), Api.setRequestPath(StuffParams) ) ) ); ``` -------------------------------- ### Set up request validation with body, query, and path schemas Source: https://github.com/sukovanej/effect-http/blob/master/README.md Configure an API endpoint with multiple input schemas to validate request body, query parameters, path parameters, and response body. The input schemas are specified as the third argument to API methods like Api.get() and Api.post(). This example creates a POST endpoint that expects a request body, query parameters, path parameters, and returns a structured response. ```typescript import { Schema } from "effect"; import { Api } from "effect-http"; const Stuff = Schema.Struct({ value: Schema.Number }); const StuffRequest = Schema.Struct({ field: Schema.Array(Schema.String) }); const StuffQuery = Schema.Struct({ value: Schema.String }); const StuffPath = Schema.Struct({ param: Schema.String }); export const api = Api.make({ title: "My api" }).pipe( Api.addEndpoint( Api.post("stuff", "/stuff/:param").pipe( Api.setRequestBody(StuffRequest), Api.setRequestQuery(StuffQuery), Api.setRequestPath(StuffPath), Api.setResponseBody(Stuff) ) ) ); ``` -------------------------------- ### Create Mock Client for API Testing Source: https://github.com/sukovanej/effect-http/blob/master/README.md Generates a mock client from an API definition that returns example or specified responses without calling the actual API. The mock client performs the same client-side validation as a real client but returns predetermined values, useful for unit testing. Supports type-safe response specification through the options argument. ```typescript import { Schema } from "effect"; import { Api } from "effect-http"; const api = Api.make().pipe( Api.addEndpoint( Api.get("getValue", "/value").pipe(Api.setResponseBody(Schema.Number)) ) ); const client = MockClient.make(api); ``` ```typescript const client = MockClient.make(api, { responses: { getValue: 12 } }); ``` -------------------------------- ### GET /user Source: https://context7.com/sukovanej/effect-http/llms.txt Retrieves a User by their ID. This endpoint uses query parameters to specify the user ID. ```APIDOC ## GET /user ### Description Returns a User by id. This endpoint uses query parameters to specify the user ID. ### Method GET ### Endpoint /user #### Query Parameters - **id** (number) - Required - User id #### Request Body None ### Request Example None ### Response #### Success Response (200) - **name** (string) - The name of the user. - **id** (integer) - A positive integer representing the user's ID. #### Response Example ```json { "name": "mike", "id": 123 } ``` ``` -------------------------------- ### API Grouping and Endpoint Definitions Source: https://github.com/sukovanej/effect-http/blob/master/README.md Demonstrates how to group endpoints using `ApiGroup` and add them to a main `Api`. This includes GET, POST, PUT, and DELETE operations for different resource groups like 'test', 'Users', and 'Categories'. ```APIDOC ## API Grouping and Endpoint Definitions This section details how to organize API endpoints into logical groups using `ApiGroup` and how these groups are integrated into a main `Api` object. This approach enhances code maintainability and aids in generating structured OpenAPI specifications. ### Test API Group - **Purpose**: Defines a simple test endpoint. - **Endpoints**: - `GET /test`: Retrieves a test response. ### User API Group - **Purpose**: Manages user-related operations. - **Endpoints**: - `GET /user`: Retrieves a user. - `POST /user`: Stores a new user. - `PUT /user`: Updates an existing user. - `DELETE /user`: Deletes a user. ### Category API Group - **Purpose**: Manages category-related operations. - **Endpoints**: - `GET /category`: Retrieves a category. - `POST /category`: Stores a new category. - `PUT /category`: Updates an existing category. - `DELETE /category`: Deletes a category. ## Example Usage (TypeScript) ```ts import { NodeRuntime } from "@effect/platform-node"; import { Effect, Schema } from "effect"; import { Api, ApiGroup, ExampleServer, RouterBuilder } from "effect-http"; import { NodeServer } from "effect-http-node"; const Response = Schema.Struct({ name: Schema.String }); const testApi = ApiGroup.make("test", { description: "Test description", externalDocs: { description: "Test external doc", url: "https://www.google.com/search?q=effect-http", }, }).pipe( ApiGroup.addEndpoint( ApiGroup.get("test", "/test").pipe(Api.setResponseBody(Response)) ) ); const userApi = ApiGroup.make("Users", { description: "All about users", externalDocs: { url: "https://www.google.com/search?q=effect-http", }, }).pipe( ApiGroup.addEndpoint( ApiGroup.get("getUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.post("storeUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.put("updateUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.delete("deleteUser", "/user").pipe(Api.setResponseBody(Response)) ) ); const categoriesApi = ApiGroup.make("Categories").pipe( ApiGroup.addEndpoint( ApiGroup.get("getCategory", "/category").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.post("storeCategory", "/category").pipe( Api.setResponseBody(Response) ) ), ApiGroup.addEndpoint( ApiGroup.put("updateCategory", "/category").pipe( Api.setResponseBody(Response) ) ), ApiGroup.addEndpoint( ApiGroup.delete("deleteCategory", "/category").pipe( Api.setResponseBody(Response) ) ) ); const api = Api.make().pipe( Api.addGroup(testApi), Api.addGroup(userApi), Api.addGroup(categoriesApi) ); ExampleServer.make(api).pipe( RouterBuilder.build, NodeServer.listen({ port: 3000 }), NodeRuntime.runMain ); ``` This setup allows the OpenAPI UI to group endpoints by their respective `ApiGroup` names, providing a structured view of the API. ``` -------------------------------- ### Grouping Endpoints in Effect-HTTP Source: https://context7.com/sukovanej/effect-http/llms.txt Organizes API endpoints into logical groups using ApiGroup for better API structure and OpenAPI tags. It demonstrates adding multiple GET, POST, PUT, and DELETE endpoints to different groups. ```typescript import { Schema } from "effect"; import { Api, ApiGroup } from "effect-http"; const Response = Schema.Struct({ name: Schema.String }); const userApi = ApiGroup.make("Users", { description: "All about users", externalDocs: { url: "https://www.google.com/search?q=effect-http", }, }).pipe( ApiGroup.addEndpoint( ApiGroup.get("getUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.post("storeUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.put("updateUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.delete("deleteUser", "/user").pipe(Api.setResponseBody(Response)) ) ); const categoriesApi = ApiGroup.make("Categories").pipe( ApiGroup.addEndpoint( ApiGroup.get("getCategory", "/category").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.post("storeCategory", "/category").pipe( Api.setResponseBody(Response) ) ) ); const api = Api.make().pipe( Api.addGroup(userApi), Api.addGroup(categoriesApi) ); ``` -------------------------------- ### Create and Combine API Groups with Endpoints in TypeScript Source: https://github.com/sukovanej/effect-http/blob/master/README.md Demonstrates creating multiple API groups (test, Users, Categories) using ApiGroup.make() and combining them into a single Api using Api.addGroup(). Each group contains endpoints with different HTTP methods (GET, POST, PUT, DELETE) that are organized for better API structure and OpenAPI tag generation. ```typescript import { NodeRuntime } from "@effect/platform-node"; import { Effect, Schema } from "effect"; import { Api, ApiGroup, ExampleServer, RouterBuilder } from "effect-http"; import { NodeServer } from "effect-http-node"; const Response = Schema.Struct({ name: Schema.String }); const testApi = ApiGroup.make("test", { description: "Test description", externalDocs: { description: "Test external doc", url: "https://www.google.com/search?q=effect-http" } }).pipe( ApiGroup.addEndpoint( ApiGroup.get("test", "/test").pipe(Api.setResponseBody(Response)) ) ); const userApi = ApiGroup.make("Users", { description: "All about users", externalDocs: { url: "https://www.google.com/search?q=effect-http" } }).pipe( ApiGroup.addEndpoint( ApiGroup.get("getUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.post("storeUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.put("updateUser", "/user").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.delete("deleteUser", "/user").pipe(Api.setResponseBody(Response)) ) ); const categoriesApi = ApiGroup.make("Categories").pipe( ApiGroup.addEndpoint( ApiGroup.get("getCategory", "/category").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.post("storeCategory", "/category").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.put("updateCategory", "/category").pipe(Api.setResponseBody(Response)) ), ApiGroup.addEndpoint( ApiGroup.delete("deleteCategory", "/category").pipe(Api.setResponseBody(Response)) ) ); const api = Api.make().pipe( Api.addGroup(testApi), Api.addGroup(userApi), Api.addGroup(categoriesApi) ); ExampleServer.make(api).pipe( RouterBuilder.build, NodeServer.listen({ port: 3000 }), NodeRuntime.runMain ); ``` -------------------------------- ### Define Modular API Endpoints with ApiGroup Source: https://github.com/sukovanej/effect-http/blob/master/README.md Demonstrates how to declare endpoints independently and organize them into logical ApiGroups for better code organization in larger applications. This example shows CRUD endpoints for an article management system that can be exported and combined with other API groups. ```typescript import { Api, ApiGroup } from "effect-http"; export const getArticleEndpoint = Api.get("getArticle", "/article").pipe( Api.setResponseBody(Response) ); export const storeArticleEndpoint = Api.post("storeArticle", "/article").pipe( Api.setResponseBody(Response) ); export const updateArticleEndpoint = Api.put("updateArticle", "/article").pipe( Api.setResponseBody(Response) ); export const deleteArticleEndpoint = Api.delete( "deleteArticle", "/article" ).pipe(Api.setResponseBody(Response)); export const articleApi = ApiGroup.make("Articles").pipe( ApiGroup.addEndpoint(getArticleEndpoint), ApiGroup.addEndpoint(storeArticleEndpoint), ApiGroup.addEndpoint(updateArticleEndpoint), ApiGroup.addEndpoint(deleteArticleEndpoint) ); ``` -------------------------------- ### Validate request headers in effect-http API Source: https://github.com/sukovanej/effect-http/blob/master/README.md Define and validate required request headers using Schema.Struct() with header names as keys. Headers are specified using Api.setRequestHeaders() similar to query and path parameters. The example creates a GET endpoint requiring an 'X-Client-Id' header, with validation errors returned in JSON format when headers are missing or invalid. Header names must be in lowercase form. ```typescript import { NodeRuntime } from "@effect/platform-node"; import { Schema } from "effect"; import { Api, ExampleServer, RouterBuilder } from "effect-http"; import { NodeServer } from "effect-http-node"; const api = Api.make().pipe( Api.addEndpoint( Api.get("hello", "/hello").pipe( Api.setResponseBody(Schema.String), Api.setRequestHeaders(Schema.Struct({ "x-client-id": Schema.String })) ) ) ); ExampleServer.make(api).pipe( RouterBuilder.build, NodeServer.listen({ port: 3000 }), NodeRuntime.runMain ); ``` -------------------------------- ### POST /stuff/:param with Request Body, Query, and Path Parameters Source: https://github.com/sukovanej/effect-http/blob/master/README.md This endpoint demonstrates how to define expectations for the request body, query parameters, and path parameters using Effect's Schema. ```APIDOC ## POST /stuff/:param ### Description This endpoint accepts a POST request with a specified request body, query parameters, and path parameters. It validates these inputs against defined schemas. ### Method POST ### Endpoint /stuff/:param ### Parameters #### Path Parameters - **param** (string) - Required - The identifier for the path. #### Query Parameters - **value** (string) - Required - A query parameter named 'value'. #### Request Body - **field** (array of strings) - Required - A request body containing a field 'field' which is an array of strings. ### Request Example ```json { "field": ["string1", "string2"] } ``` ### Response #### Success Response (200) - **value** (number) - The response body contains a number. #### Response Example ```json { "value": 123 } ``` ``` -------------------------------- ### Client-Side Authentication Helpers Source: https://context7.com/sukovanej/effect-http/llms.txt Configure authentication headers on the client side using convenience methods for basic and bearer token authentication. ```APIDOC ## Client Authentication Examples ### Description Examples of how to configure authentication headers when making requests using the Effect-HTTP client. ### Basic Authentication Configure basic authentication with username and password. ```typescript client.someEndpoint({}, Client.setBasic("user", "pass")); ``` ### Bearer Token Authentication Configure bearer token authentication. ```typescript client.someEndpoint({}, Client.setBearer("my-token")); ``` ``` -------------------------------- ### Client-Side Authentication Configuration Source: https://context7.com/sukovanej/effect-http/llms.txt Shows how to configure authentication headers on the client side using Effect-HTTP's convenience helpers. Supports basic authentication and bearer tokens for API requests. Dependencies include 'effect-http'. ```typescript import { Client } from "effect-http"; const client = Client.make(api, { baseUrl: "http://localhost:3000" }); // Basic auth client.endpoint({}, Client.setBasic("user", "pass")); // Bearer token client.endpoint({}, Client.setBearer("my-token")); ``` -------------------------------- ### Test Content Negotiation with curl Accept Headers Source: https://github.com/sukovanej/effect-http/blob/master/README.md Bash commands demonstrating how to test content negotiation by sending different Accept headers to an effect-http server. Shows separate requests for JSON (application/json) and plain text (text/plain) content types. ```bash # JSON curl localhost:3000/ -H 'accept: application/json' -v # Plain text curl localhost:3000/ -H 'accept: text/plain' -v ``` -------------------------------- ### Define and Implement OpenAPI Documentation with Effect-HTTP (TypeScript) Source: https://context7.com/sukovanej/effect-http/llms.txt This snippet demonstrates how to define an OpenAPI specification for a 'Users API' using effect-http. It includes defining request query parameters and response body schemas, and then handling the 'getUser' endpoint. The code utilizes Effect-TS for handling asynchronous operations and dependency injection. ```typescript import { Effect, Schema, pipe } from "effect"; import { Api, QuerySchema, RouterBuilder } from "effect-http"; const Response = Schema.Struct({ name: Schema.String, id: pipe(Schema.Number, Schema.int(), Schema.positive()), }).pipe(Schema.annotations({ description: "User" })); const Query = Schema.Struct({ id: QuerySchema.Number.pipe(Schema.annotations({ description: "User id" })) }); const api = Api.make({ title: "Users API" }).pipe( Api.addEndpoint( Api.get("getUser", "/user", { description: "Returns a User by id" }).pipe( Api.setResponseBody(Response), Api.setRequestQuery(Query) ) ) ); const app = RouterBuilder.make(api).pipe( RouterBuilder.handle("getUser", ({ query }) => Effect.succeed({ name: "mike", id: query.id }) ), RouterBuilder.build ); ``` -------------------------------- ### Server Implementation - Handler with Multiple Responses Source: https://context7.com/sukovanej/effect-http/llms.txt Demonstrates how a handler can return different response types based on business logic, including type-safe status codes and headers. ```APIDOC ## Server Handler for POST /hello ### Description Implements the 'hello' endpoint, demonstrating the ability to return different response types and statuses based on logic. ### Method POST ### Endpoint /hello ### Parameters *No specific parameters defined for this endpoint in the example.* ### Request Example *Example handled by the client/router, not directly by the handler code snippet.* ### Response #### Success Response (201) - **body** (number) - The numeric response body. - **my-header** (number) - A custom header with a numeric value. #### Success Response (204) *This response indicates success with no content, potentially with custom headers.* #### Response Example (201) ```json { "body": 12, "headers": { "my-header": 69 } } ``` #### Response Example (204) *Example for 204 response would depend on defined headers.* ```json { "headers": { "x-another": "42" } } ``` ``` -------------------------------- ### API Key Security with Headers and OpenAPI Source: https://context7.com/sukovanej/effect-http/llms.txt Configures API key security by validating keys from request headers. It includes OpenAPI documentation generation for the API key parameter. Dependencies include '@effect/platform', 'effect', and 'effect-http'. ```typescript import { HttpServer } from "@effect/platform"; import { Effect, pipe, Schema } from "effect"; import { Security, HttpError } from "effect-http"; const customSecurity = Security.make( pipe( HttpServer.request.schemaHeaders( Schema.Struct({ "x-api-key": Schema.String }) ), Effect.mapError(() => HttpError.unauthorizedError("Expected valid X-API-KEY header") ), Effect.map((headers) => headers["x-api-key"]) ), { myApiKey: { name: "x-api-key", type: "apiKey", in: "header", description: "My API key", }, } ); ``` -------------------------------- ### Optional Security Pattern Source: https://github.com/sukovanej/effect-http/blob/master/README.md Shows how to implement optional authentication using Security.or combinator to allow requests with or without valid credentials, returning either the authenticated user or None. ```APIDOC ## Optional Security Implementation ### Description Implements an optional security mechanism that accepts requests either with valid basic authentication credentials or without authentication. ### Security Pattern Combining multiple security mechanisms using Security.or combinator, similar to combining Effects. ### Implementation ```typescript const mySecurity = Security.or( Security.asSome(Security.basic()), Security.as(Security.unit, Option.none()) ); ``` ### Behavior - **With valid credentials** - Returns Option.some(BasicCredentials) - **Without credentials** - Returns Option.none() ### Handler Signature ```typescript RouterBuilder.handle("endpoint", (_, security) => { // security is of type Option }) ``` ### Notes - Security.asSome, Security.as, and Security.unit follow the same patterns as Effect counterparts - The security parameter in the handler is wrapped in an Option type - Both authenticated and unauthenticated requests are accepted ``` -------------------------------- ### POST /my-secured-endpoint - Basic Authentication Source: https://github.com/sukovanej/effect-http/blob/master/README.md Demonstrates how to secure an endpoint using basic authentication. The endpoint handler receives the security context containing the authenticated user credentials from the incoming request. ```APIDOC ## POST /my-secured-endpoint ### Description A secured endpoint that uses basic authentication to control access and identify the requesting user. ### Method POST ### Endpoint /my-secured-endpoint ### Security - **Basic Auth** - Required - HTTP Basic Authentication with username and password ### Request Headers - **Authorization** (string) - Required - Basic auth credentials in format: Basic base64(username:password) ### Response #### Success Response (200) - **body** (string) - Success message containing the authenticated user #### Response Example ``` "Accessed as {username}" ``` #### Error Response (401) - **error** (string) - Unauthorized - Invalid or missing authorization credentials ### Response Example ```json { "error": "Unauthorized" } ``` ### Implementation Notes The Security.basic() constructor produces a Security type. The handler function receives BasicCredentials in the second argument if valid authorization is present. Invalid authorization results in a 401 Unauthorized response with a JSON error message. ``` -------------------------------- ### Request Validation with Body, Query, Path, and Headers Source: https://context7.com/sukovanej/effect-http/llms.txt Configure comprehensive request validation for all HTTP request components including request body, query parameters, path parameters, and headers. ```APIDOC ## POST /stuff/:param ### Description Processes 'stuff' with validation for body, query, path, and expected response. ### Method POST ### Endpoint /stuff/:param ### Parameters #### Path Parameters - **param** (string) - Required - A string parameter for the path. #### Query Parameters - **value** (string) - Required - A string value for the query. #### Request Body - **field** (array of strings) - Required - An array of strings. ### Request Example ```json { "field": [ "string1", "string2" ] } ``` ### Response #### Success Response (200) - **value** (number) - A numeric value. #### Response Example ```json { "value": 123 } ``` ``` -------------------------------- ### Complex Security with User Storage Source: https://github.com/sukovanej/effect-http/blob/master/README.md Demonstrates advanced security implementation that validates basic auth credentials and fetches additional user information from a UserStorage service using Effect context and dependency injection. ```APIDOC ## Complex Security with Service Dependency ### Description Implements a security mechanism that combines basic authentication with user information retrieval from a service layer using Effect dependencies. ### Security Implementation ```typescript const mySecurity = Security.basic({ description: "My basic auth" }).pipe( Security.map((creds) => creds.user), Security.mapEffect((user) => UserStorage.getInfo(user)) ); ``` ### Process Flow 1. Validate basic authentication credentials 2. Extract username from credentials 3. Fetch user information from UserStorage service 4. Pass UserInfo to endpoint handler ### Handler Implementation ```typescript RouterBuilder.handle("endpoint", (_, security) => Effect.succeed(`Logged as ${security.email}`) ) ``` ### Response #### Success Response (200) - **message** (string) - Success message with user email #### Response Example ``` "Logged as email@gmail.com" ``` ### Dependency Injection - **Requires** - UserStorage service must be provided via Effect.provide() - **Usage** - Pass UserStorage.dummy or custom implementation when running server ### Data Models ```typescript interface UserInfo { email: string; } ``` ``` -------------------------------- ### Descriptions in OpenAPI Source: https://github.com/sukovanej/effect-http/blob/master/README.md Explains how to add descriptions to API schemas and endpoints using Effect-HTTP and Effect Schema, which are then propagated to the OpenAPI specification. ```APIDOC ## Descriptions in OpenAPI Effect-HTTP leverages Effect Schema's description capabilities to enrich the OpenAPI specification. Descriptions can be applied to schemas, individual fields, and operation-level details. ### Schema Descriptions - **Purpose**: Adds descriptions to the schema itself and its fields, which appear in the OpenAPI `schema` object. - **Method**: Use `Schema.annotations({ description: "Your description" })`. ### Operation Descriptions - **Purpose**: Provides a description for a specific API endpoint operation. - **Method**: Pass a `description` field as the fourth argument to API endpoint methods like `Api.get`, `Api.post`, etc. ## Example Usage (TypeScript) ```ts import { NodeRuntime } from "@effect/platform-node"; import { Effect, Schema } from "effect"; import { Api, QuerySchema, RouterBuilder } from "effect-http"; import { NodeServer } from "effect-http-node"; const Response = Schema.Struct({ name: Schema.String, id: pipe(Schema.Number, Schema.int(), Schema.positive()), }).pipe(Schema.annotations({ description: "User" })); const Query = Schema.Struct({ id: QuerySchema.Number.pipe(Schema.annotations({ description: "User id" })) }); const api = Api.make({ title: "Users API" }).pipe( Api.addEndpoint( Api.get("getUser", "/user", { description: "Returns a User by id" }).pipe( Api.setResponseBody(Response), Api.setRequestQuery(Query) ) ) ); const app = RouterBuilder.make(api).pipe( RouterBuilder.handle("getUser", ({ query }) => Effect.succeed({ name: "mike", id: query.id }) ), RouterBuilder.build ); app.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain); ``` In this example: - The `Response` schema has a top-level description "User". - The `id` field within the `Query` schema has a description "User id". - The `getUser` endpoint operation has a description "Returns a User by id". These descriptions will be correctly reflected in the generated OpenAPI documentation. ``` -------------------------------- ### Basic Authentication with Effect-HTTP Source: https://context7.com/sukovanej/effect-http/llms.txt Implements basic HTTP authentication using Effect-HTTP. It automatically validates credentials and provides type-safe access to user information within the Effect ecosystem. Dependencies include 'effect' and 'effect-http'. ```typescript import { Effect, Schema } from "effect"; import { Api, RouterBuilder, Security } from "effect-http"; const api = Api.make().pipe( Api.addEndpoint( Api.post("mySecuredEndpoint", "/my-secured-endpoint").pipe( Api.setResponseBody(Schema.String), Api.setSecurity(Security.basic()) ) ) ); const app = RouterBuilder.make(api).pipe( RouterBuilder.handle("mySecuredEndpoint", (_, security) => Effect.succeed(`Accessed as ${security.user}`) ), RouterBuilder.build ); ``` -------------------------------- ### Client-Side Security Configuration Source: https://github.com/sukovanej/effect-http/blob/master/README.md Shows how to configure authentication on the client side when making API requests using the Client module with basic auth and bearer token helper combinators. ```APIDOC ## Client-Side Authentication ### Description Configures authentication headers on the client side when making requests to secured endpoints. ### Method Client request configuration with security headers ### Basic Auth Example ```typescript const client = Client.make(api); client.endpoint({}, Client.setBasic("user", "pass")); ``` ### Parameters #### Basic Authentication - **username** (string) - Required - The username for basic auth - **password** (string) - Required - The password for basic auth #### Request Mapper Function - **mapper** ((request: ClientRequest) => ClientRequest) - Optional - Function to modify ClientRequest ### Available Combinators - **Client.setBasic(username, password)** - Sets HTTP Basic Authentication header - **Client.setBearer(token)** - Sets HTTP Bearer Token in Authorization header ### Request Header Configuration The combinators internally configure the Authorization header: - Basic Auth: `Authorization: Basic base64(username:password)` - Bearer Token: `Authorization: Bearer {token}` ### Usage Pattern ```typescript const client = Client.make(api); // Basic authentication await client.mySecuredEndpoint({}, Client.setBasic("user", "pass")); // Bearer token authentication await client.mySecuredEndpoint({}, Client.setBearer("token123")); ``` ### Notes - The security mapper function is the optional second argument to endpoint methods - Custom header mapping is supported for additional security mechanisms - The ClientRequest is modified before being sent to the server ``` -------------------------------- ### Modular API with Separate Handlers in Effect-HTTP Source: https://context7.com/sukovanej/effect-http/llms.txt Demonstrates building a modular API by separating endpoint definitions and their corresponding handlers into different files. This promotes better organization for large applications. It shows how to define endpoints, create handlers, and merge them into a main application router. ```typescript import { Api, ApiGroup, Handler, RouterBuilder } from "effect-http"; import { Effect, Schema } from "effect"; // articles-api.ts const Response = Schema.Struct({ id: Schema.Number, title: Schema.String }); export const getArticleEndpoint = Api.get("getArticle", "/article").pipe( Api.setResponseBody(Response) ); export const storeArticleEndpoint = Api.post("storeArticle", "/article").pipe( Api.setResponseBody(Response) ); export const articleApi = ApiGroup.make("Articles").pipe( ApiGroup.addEndpoint(getArticleEndpoint), ApiGroup.addEndpoint(storeArticleEndpoint) ); // articles-handlers.ts const getArticleHandler = Handler.make(getArticleEndpoint, () => Effect.succeed({ id: 1, title: "Article" }) ); const storeArticleHandler = Handler.make(storeArticleEndpoint, () => Effect.succeed({ id: 2, title: "New Article" }) ); export const articleRouterBuilder = RouterBuilder.make(api).pipe( RouterBuilder.handle(getArticleHandler), RouterBuilder.handle(storeArticleHandler) ); // main.ts const app = RouterBuilder.make(api).pipe( RouterBuilder.merge(articleRouterBuilder), RouterBuilder.build ); ``` -------------------------------- ### Integration Test with NodeTesting.make Source: https://github.com/sukovanej/effect-http/blob/master/README.md Creates a scoped test using Effect.gen and NodeTesting.make to generate a testing client from the server and API definition. The test invokes the hello endpoint with query parameters and validates the response. Dependencies are type-safe and must be provided when the server uses DI services. ```typescript import { it } from "@effect/vitest"; import { NodeTesting } from "effect-http-node"; it.scoped("test /hello endpoint", () => Effect.gen(function* () { const response = yield* NodeTesting.make(app, api).pipe( Effect.flatMap((client) => client.hello({ query: { input: 12 } })) ); expect(response).toEqual("13"); }) ); ``` -------------------------------- ### Build Server with RouterBuilder in TypeScript Source: https://context7.com/sukovanej/effect-http/llms.txt Implements API handlers and builds a running HTTP server using Effect-TS and effect-http. It integrates with Node.js platform for server execution. ```typescript import { Effect } from "effect"; import { RouterBuilder } from "effect-http"; import { NodeServer } from "effect-http-node"; import { NodeRuntime } from "@effect/platform-node"; const app = RouterBuilder.make(api).pipe( RouterBuilder.handle("getUser", ({ query }) => Effect.succeed({ name: "milan", id: query.id }) ), RouterBuilder.build ); app.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain); ``` -------------------------------- ### Run Node Server with Mock Repository (TypeScript) Source: https://github.com/sukovanej/effect-http/blob/master/README.md Configures and runs the Node.js HTTP server using effect-http-node. It provides the mock UserRepository service to the application, enabling the conflict error scenario. ```typescript import { Effect, NodeRuntime } from "effect"; app.pipe( NodeServer.listen({ port: 3000 }), Effect.provideService(UserRepository, mockUserRepository), NodeRuntime.runMain ); ``` -------------------------------- ### Configure Client-Side Basic Authentication Header Source: https://github.com/sukovanej/effect-http/blob/master/README.md Demonstrates how to set authentication headers for HTTP client requests using effect-http. The `Client.setBasic` combinator is used to configure the `Authorization` header with basic credentials. ```typescript import { Client } from "effect-http"; // Assuming 'api' is previously defined // const client = Client.make(api); // client.endpoint({}, Client.setBasic("user", "pass")); ``` -------------------------------- ### Implement Mock UserRepository (TypeScript) Source: https://github.com/sukovanej/effect-http/blob/master/README.md Provides a mock implementation for a UserRepository interface. The mock simulates a scenario where a user always exists, ensuring the conflict error handling logic is triggered. ```typescript interface UserRepository { userExistsByName: (name: string) => Effect.Effect; storeUser: (user: string) => Effect.Effect; } const UserRepository = Context.GenericTag("UserRepository"); const mockUserRepository = UserRepository.of({ userExistsByName: () => Effect.succeed(true), storeUser: () => Effect.unit, }); const { userExistsByName, storeUser } = Effect.serviceFunctions(UserRepository); ``` -------------------------------- ### Construct Complex Security with User Storage Service Source: https://github.com/sukovanej/effect-http/blob/master/README.md Illustrates building a more complex security mechanism that first validates basic auth credentials and then fetches user information from a custom `UserStorage` service. This requires providing the `UserStorage` layer when running the application. ```typescript import { Effect, Layer } from "effect"; import { Security } from "effect-http"; interface UserInfo { email: string; } class UserStorage extends Effect.Tag("UserStorage") Effect.Effect; }>() { static dummy = Layer.succeed( UserStorage, UserStorage.of({ getInfo: (_: string) => Effect.succeed({ email: "email@gmail.com" }), }) ); } const mySecurity = Security.basic({ description: "My basic auth" }).pipe( Security.map((creds) => creds.user), Security.mapEffect((user) => UserStorage.getInfo(user)) ); // Handler implementation: // const app = RouterBuilder.make(api).pipe( // RouterBuilder.handle("endpoint", (_, security) => // Effect.succeed(`Logged as ${security.email}`) // ), // RouterBuilder.build, // Middlewares.errorLog // ); // Running the server: // app.pipe( // NodeServer.listen({ port: 3000 }), // Effect.provide(UserStorage.dummy), // NodeRuntime.runMain // ); ``` -------------------------------- ### Custom Security with Services Source: https://context7.com/sukovanej/effect-http/llms.txt Build complex authentication flows using Effect services and context propagation. This allows for custom user information retrieval based on credentials. ```APIDOC ## POST /endpoint ### Description This endpoint utilizes custom security logic, integrating with Effect services to fetch user information after authentication. ### Method POST ### Endpoint /endpoint ### Parameters #### Request Body * **credentials** (object) - Required - Contains authentication credentials. * **username** (string) - Required - The username for authentication. * **password** (string) - Required - The password for authentication. ### Request Example ```json { "credentials": { "username": "user", "password": "pass" } } ``` ### Response #### Success Response (200) - **message** (string) - A message including the user's email, confirming successful authentication and data retrieval. #### Response Example ```json { "message": "Logged as email@gmail.com" } ``` ``` -------------------------------- ### Implement HttpApp with Conflict Handling (TypeScript) Source: https://github.com/sukovanej/effect-http/blob/master/README.md Implements the HTTP application logic for the 'storeUser' endpoint. It checks if the user exists using the UserRepository and returns a 409 Conflict error if they do, otherwise proceeds to store the user. ```typescript const app = RouterBuilder.make(api).pipe( RouterBuilder.handle("storeUser", ({ body }) => pipe( userExistsByName(body.name), Effect.filterOrFail( (alreadyExists) => !alreadyExists, () => HttpError.conflict(`User "${body.name}" already exists.`).withMessage(`User "${body.name}" already exists.`) ), Effect.andThen(storeUser(body.name)), Effect.map(() => `User "${body.name}" stored.`) ) ), RouterBuilder.build ); ``` -------------------------------- ### Add Descriptions to API Endpoints and Schemas in TypeScript Source: https://github.com/sukovanej/effect-http/blob/master/README.md Shows how to add descriptions to OpenAPI specifications using Schema.annotations() for type-level descriptions and operation-level descriptions via the 4th argument of API endpoint methods. Demonstrates using Schema.positive() for built-in descriptions and custom descriptions for query parameters and responses. ```typescript import { NodeRuntime } from "@effect/platform-node"; import { Effect, Schema } from "effect"; import { Api, QuerySchema, RouterBuilder } from "effect-http"; import { NodeServer } from "effect-http-node"; const Response = Schema.Struct({ name: Schema.String, id: Schema.pipe(Schema.Number, Schema.int(), Schema.positive()) }).pipe(Schema.annotations({ description: "User" })); const Query = Schema.Struct({ id: QuerySchema.Number.pipe(Schema.annotations({ description: "User id" })) }); const api = Api.make({ title: "Users API" }).pipe( Api.addEndpoint( Api.get("getUser", "/user", { description: "Returns a User by id" }).pipe( Api.setResponseBody(Response), Api.setRequestQuery(Query) ) ) ); const app = RouterBuilder.make(api).pipe( RouterBuilder.handle("getUser", ({ query }) => Effect.succeed({ name: "mike", id: query.id }) ), RouterBuilder.build ); app.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain); ```