Module

Yoga.Fastify.Om.Route

Package
purescript-yoga-fastify-om
Repository
rowtype-yoga/purescript-yoga-fastify-om

Re-exports from Data.Variant

Re-exports from Yoga.Fastify.Om.Route.OmHandler

#Handler Source

newtype Handler :: Type -> Row Type -> Typenewtype Handler route (ctx :: Row Type)

A handler with deferred dependency injection. The ctx row tracks what extra dependencies are needed beyond the request. Use handle to create one, and registerAPILayer to provide the deps.

Constructors

#BuildErrorHandlers Source

class BuildErrorHandlers :: RowList Type -> Row Type -> Row Type -> Constraintclass BuildErrorHandlers (rl :: RowList Type) (respVariant :: Row Type) (handlers :: Row Type) | rl respVariant -> handlers where

Build a record of handlers for Variant.onMatch that convert each error variant label into the full response variant.

Members

Instances

#Is2xxStatus Source

class Is2xxStatus :: Symbol -> Boolean -> Constraintclass Is2xxStatus (label :: Symbol) (is2xx :: Boolean) | label -> is2xx

Determine whether a variant label corresponds to a 2xx HTTP status code.

Instances

#RouteResponseVariant Source

class RouteResponseVariant :: Type -> Row Type -> Constraintclass RouteResponseVariant (route :: Type) (respVariant :: Row Type) | route -> respVariant

Instances

#SplitResponse Source

class SplitResponse :: Row Type -> Row Type -> Row Type -> Constraintclass SplitResponse (respVariant :: Row Type) (successRow :: Row Type) (errorRow :: Row Type) | respVariant -> successRow errorRow

Split a response variant row into success (2xx) and error (non-2xx) sub-rows.

Instances

#SplitResponseEntry Source

class SplitResponseEntry :: Boolean -> Symbol -> Type -> RowList Type -> Row Type -> Row Type -> Constraintclass SplitResponseEntry (is2xx :: Boolean) (label :: Symbol) (ty :: Type) (tail :: RowList Type) (successRow :: Row Type) (errorRow :: Row Type) | is2xx label ty tail -> successRow errorRow

Dispatch based on Is2xxStatus result.

Instances

#SplitResponseRL Source

class SplitResponseRL :: RowList Type -> Row Type -> Row Type -> Constraintclass SplitResponseRL (rl :: RowList Type) (successRow :: Row Type) (errorRow :: Row Type) | rl -> successRow errorRow

Instances

#ToLabel Source

class ToLabel :: Type -> Symbol -> Constraintclass ToLabel labelOrCode label | labelOrCode -> label

Convert either a status code (Int) or label (Symbol) to a label (Symbol). This allows functions to accept both @404 and @"notFound" polymorphically.

Instances

#respondWith Source

respondWith :: forall @labelOrCode label headers body r1 r2 ctx err. ToLabel (Proxy labelOrCode) label => IsSymbol label => Cons label (Response headers body) r1 r2 => Record headers -> body -> Om ctx err (Variant r2)

Return a response with a specific reason label or status code and custom headers

Example:

respondWith @"created" { "Location": "/users/123" } user
respondWith @201 { "Location": "/users/123" } user

#respondNotModified Source

respondNotModified :: forall ctx err r. Om ctx err (Variant (notModified :: Response () Unit | r))

Return a 304 Not Modified response (no headers, no body).

Example:

respondNotModified

#respondNoContent Source

respondNoContent :: forall ctx err r. Om ctx err (Variant (noContent :: Response () Unit | r))

Return a 204 No Content response (no headers, no body).

Example:

respondNoContent

#respond Source

respond :: forall @labelOrCode label body r1 r2 ctx err. ToLabel (Proxy labelOrCode) label => IsSymbol label => Cons label (Response () body) r1 r2 => body -> Om ctx err (Variant r2)

Return a response with a specific reason label or status code

Example:

respond @"ok" { id: 1, name: "Alice" }
respond @200 { id: 1, name: "Alice" }
respond @"created" newUser
respond @201 newUser

#rejectWith Source

rejectWith :: forall @labelOrCode label headers body _r1 err _r2 ctx a. ToLabel (Proxy labelOrCode) label => IsSymbol label => Cons label (Response headers body) _r1 err => Cons label (Response headers body) _r2 (exception :: Error | err) => Record headers -> body -> Om ctx err a

Throw a non-2xx error response with custom headers (short-circuits)

Example:

rejectWith @"unauthorized" { "WWW-Authenticate": "Bearer" } { error: "Invalid token" }
rejectWith @401 { "WWW-Authenticate": "Bearer" } { error: "Invalid token" }

#reject Source

reject :: forall @labelOrCode label body _r1 err _r2 ctx a. ToLabel (Proxy labelOrCode) label => IsSymbol label => Cons label (Response () body) _r1 err => Cons label (Response () body) _r2 (exception :: Error | err) => body -> Om ctx err a

Throw a non-2xx error response (short-circuits the handler)

Example:

reject @"notFound" { error: "User not found" }
reject @404 { error: "User not found" }
reject @"badRequest" { error: "Invalid input" }
reject @400 { error: "Invalid input" }

#mapReject Source

mapReject :: forall @from @toLabelOrCode toLabel tyIn body ctx errIn errMid errOut a. IsSymbol from => ToLabel (Proxy toLabelOrCode) toLabel => IsSymbol toLabel => Cons from tyIn (exception :: Error | errMid) (exception :: Error | errIn) => Cons toLabel (Response () body) (exception :: Error | errMid) (exception :: Error | errOut) => (tyIn -> body) -> Om ctx errIn a -> Om ctx errOut a

#handle Source

handle :: forall @route pathParams queryParams reqHeaders body respVariant successRow errorRow extraCtx. RouteHandler route pathParams queryParams reqHeaders body respVariant => SplitResponse respVariant successRow errorRow => Lacks "_respondNow" errorRow => Lacks "path" extraCtx => Lacks "query" extraCtx => Lacks "headers" extraCtx => Lacks "body" extraCtx => Om { body :: body, headers :: Record reqHeaders, path :: Record pathParams, query :: Record queryParams | extraCtx } (_respondNow :: Variant successRow | errorRow) (Variant successRow) -> Handler route extraCtx

Create a Handler from an Om computation.

The Om computation receives the request context (path, query, headers, body) plus any extra dependencies via ask. Request field types are verified against the route at compile time.

Example:

putUserHandler :: Handler PutUser (userRepo :: UserRepo)
putUserHandler = handle do
  { path, body, userRepo } <- ask
  existing <- userRepo.findByName path.name # liftAff
  case existing of
    Just user -> respond @"ok" user
    Nothing -> do
      user <- userRepo.create path.name body.email # liftAff
      respond @"created" user

Re-exports from Yoga.Fastify.Route.HandleResponse

#HandleResponse Source

class HandleResponse :: Row Type -> Constraintclass HandleResponse (respVariant :: Row Type)  where

Members

Instances

Re-exports from Yoga.Fastify.Route.HandleRoute

#handleRoute Source

handleRoute :: forall method segments partialRequest o_ fullHeaders fullCookies fullEncoding userResp respVariant pathParams queryParams body. Union partialRequest o_ (body :: fullEncoding, cookies :: Record fullCookies, headers :: Record fullHeaders) => DefaultRequestFields partialRequest fullHeaders fullCookies fullEncoding => RenderMethod method => PathPattern segments => SegmentPathParams segments pathParams => SegmentQueryParams segments queryParams => EncodingBody fullEncoding body => ParsePathParams pathParams => ParseQueryParamsFromObject queryParams => ParseHeaders fullHeaders => ParseBody fullEncoding body => ConvertResponseVariant userResp respVariant => HandleResponse respVariant => RouteHandler (Route method segments (Request (Record partialRequest)) userResp) pathParams queryParams fullHeaders body respVariant => Handler (Route method segments (Request (Record partialRequest)) userResp) -> Fastify -> Effect Unit

Re-exports from Yoga.Fastify.Route.ParseBody

#ParseBody Source

class ParseBody (encoding :: Type) (body :: Type) | encoding -> body where

Members

Instances

Re-exports from Yoga.Fastify.Route.ParseHeaders

#ParseHeaders Source

class ParseHeaders :: Row Type -> Constraintclass ParseHeaders (headers :: Row Type)  where

Parse a record of headers from an Object, accumulating all errors

Returns Either (NonEmptyArray HeaderError) (Record headers) to collect all parsing errors

Examples: parseHeaders (Proxy :: Proxy (auth :: String)) obj -- Left (NEA.singleton (MissingHeader "auth")) if missing -- Right { auth: "Bearer token" } if present

Members

Instances

#ParseHeadersRL Source

class ParseHeadersRL :: RowList Type -> Row Type -> Constraintclass ParseHeadersRL (rl :: RowList Type) (headers :: Row Type) | rl -> headers where

Helper class using RowList to accumulate errors

Members

Instances

Re-exports from Yoga.Fastify.Route.ParsePathParams

#ParsePathParams Source

class ParsePathParams :: Row Type -> Constraintclass ParsePathParams (params :: Row Type)  where

Members

Instances

Re-exports from Yoga.Fastify.Route.ParseQueryParams

#ParseQueryParamsFromObject Source

Re-exports from Yoga.Fastify.Route.SetHeaders

#SetHeaders Source

class SetHeaders :: Row Type -> Constraintclass SetHeaders (headers :: Row Type)  where

Members

Instances

Re-exports from Yoga.HTTP.API.Route.BearerToken

#BearerToken Source

newtype BearerToken

Bearer token newtype that validates the "Bearer " prefix

Example: parseHeader "Bearer abc123" :: Either String BearerToken = Right (BearerToken "abc123") parseHeader "abc123" :: Either String BearerToken = Left "missing 'Bearer ' prefix"

Constructors

Instances

Re-exports from Yoga.HTTP.API.Route.Encoding

#NoBody Source

data NoBody

No request body (for GET, DELETE, etc.)

Example: Request {} -- NoBody is the default when body is omitted

#JSON Source

data JSON a

JSON-encoded request body (application/json)

Example: Request { body :: JSON User }

#FormData Source

data FormData a

Form data encoded request body (application/x-www-form-urlencoded)

Example: Request { body :: FormData { username :: String, password :: String } }

Re-exports from Yoga.HTTP.API.Route.Handler

#Request Source

data Request r

#HandlerFn Source

type HandlerFn :: Row Type -> Row Type -> Row Type -> Type -> Row Type -> Typetype HandlerFn pathParams queryParams reqHeaders body respVariant = { body :: body, headers :: Record reqHeaders, path :: Record pathParams, query :: Record queryParams } -> Aff (Variant respVariant)

Type-safe handler tied to a route's computed types.

Usage: myHandler :: Handler (id :: Int) (limit :: Maybe Int) (authorization :: BearerToken) User (ok :: ResponseData () (Array Post), notFound :: ResponseData () ErrorMessage) myHandler { path, query, headers, body } = do -- path :: { id :: Int } -- query :: { limit :: Maybe Int } -- headers :: { authorization :: BearerToken } -- body :: User pure $ respondNoHeaders (Proxy :: _ "ok") []

#CaptureParams Source

class CaptureParams :: forall k. k -> Row Type -> Constraintclass CaptureParams segs (params :: Row Type) | segs -> params

Walk the path segments and collect all Capture/Param entries into a row.

Instances

#EncodingBody Source

class EncodingBody (encoding :: Type) (body :: Type) | encoding -> body

Map encoding phantom types to the runtime body type the handler receives.

Instances

#RequestBody Source

class RequestBody (request :: Type) (encoding :: Type) | request -> encoding

Extract the body encoding type from a request record type.

The request is expected to have a body field.

Instances

#RequestHeaders Source

class RequestHeaders :: Type -> Row Type -> Constraintclass RequestHeaders (request :: Type) (headers :: Row Type) | request -> headers

Extract the headers row from a request record type.

The request is expected to have a headers field.

Instances

#SegmentPathParams Source

class SegmentPathParams :: forall k. k -> Row Type -> Constraintclass SegmentPathParams segments params | segments -> params

Extract the row of typed path parameters from a path segments type.

Instances

#SegmentQueryParams Source

class SegmentQueryParams :: forall k. k -> Row Type -> Constraintclass SegmentQueryParams segments query | segments -> query

Extract the row of typed query parameters from a path segments type.

Instances

#SegmentQueryParamsRL Source

class SegmentQueryParamsRL :: RowList Type -> Row Type -> Constraintclass SegmentQueryParamsRL (rl :: RowList Type) (query :: Row Type) | rl -> query

RowList-based processing of query param rows. Required ty → ty (plain), otherwise → Maybe ty

Instances

Re-exports from Yoga.HTTP.API.Route.HeaderError

#HeaderError Source

data HeaderError

Typed errors for header parsing

Constructors

Instances

Re-exports from Yoga.HTTP.API.Route.HeaderValue

#HeaderValue Source

class HeaderValue a  where

Typeclass for values that can be parsed from and printed to HTTP header strings

This mirrors the ParseParam pattern from path parsing and allows headers to be typed beyond just strings.

Returns Either String for detailed error messages (the string is the reason, not the header name).

Examples: parseHeader "42" :: Either String Int = Right 42 parseHeader "bad" :: Either String Int = Left "not a valid integer" printHeader 42 = "42" parseHeader "hello" :: Either String String = Right "hello"

Members

Instances

  • HeaderValue String

    String headers are pass-through (identity)

  • HeaderValue Int

    Integer headers are parsed from strings

  • (HeaderValue a) => HeaderValue (Maybe a)

    Optional headers (Maybe a) where a has HeaderValue This instance allows headers to be optional Note: parseHeader always succeeds for Maybe types (returns Just or Nothing)

#HeaderValueType Source

class HeaderValueType (ty :: Type)  where

Get OpenAPI type string for a HeaderValue type

Members

Instances

Re-exports from Yoga.HTTP.API.Route.Method

#PUT Source

data PUT

HTTP PUT method

#POST Source

data POST

HTTP POST method

#PATCH Source

data PATCH

HTTP PATCH method

#GET Source

data GET

HTTP GET method

#DELETE Source

data DELETE

HTTP DELETE method

Re-exports from Yoga.HTTP.API.Route.OpenAPI

#ServerObject Source

type ServerObject = { description :: Maybe String, url :: String }

Type for OpenAPI server object

#OpenAPISpec Source

data OpenAPISpec

Opaque type representing a complete OpenAPI specification document.

Instances

#CollectOperations Source

class CollectOperations (routes :: Type)  where

Collect OpenAPI operations from a type-level structure of routes. Use a Record to combine multiple named routes: CollectOperations { getUser :: RouteA, createUser :: RouteB }

Members

Instances

#RenderHeadersSchema Source

class RenderHeadersSchema :: Row Type -> Constraintclass RenderHeadersSchema (headers :: Row Type)  where

Render headers row as OpenAPI parameter array

Members

Instances

#RenderHeadersSchemaRL Source

class RenderHeadersSchemaRL :: RowList Type -> Row Type -> Constraintclass RenderHeadersSchemaRL (rl :: RowList Type) (headers :: Row Type) | rl -> headers where

Helper class using RowList

Members

Instances

#RenderJSONSchema Source

class RenderJSONSchema :: forall k. k -> Constraintclass RenderJSONSchema ty  where

Render a PureScript type as an OpenAPI JSON schema

Members

Instances

#RenderPathParamsSchema Source

class RenderPathParamsSchema :: Row Type -> Constraintclass RenderPathParamsSchema (params :: Row Type)  where

Render path parameters row as OpenAPI parameter array

Members

Instances

#RenderPathParamsSchemaRL Source

class RenderPathParamsSchemaRL :: RowList Type -> Row Type -> Constraintclass RenderPathParamsSchemaRL (rl :: RowList Type) (params :: Row Type) | rl -> params where

Helper class using RowList

Members

Instances

#RenderQueryParamsSchema Source

class RenderQueryParamsSchema :: Row Type -> Constraintclass RenderQueryParamsSchema (params :: Row Type)  where

Render query parameters row as OpenAPI parameter array

Members

Instances

#RenderQueryParamsSchemaRL Source

class RenderQueryParamsSchemaRL :: RowList Type -> Row Type -> Constraintclass RenderQueryParamsSchemaRL (rl :: RowList Type) (params :: Row Type) | rl -> params where

Helper class using RowList

Members

Instances

#RenderRequestBodySchema Source

class RenderRequestBodySchema (encoding :: Type)  where

Render request body schema for OpenAPI requestBody section Returns Nothing for NoBody, Just requestBody object for JSON/FormData

Members

Instances

#RenderResponseHeadersSchema Source

class RenderResponseHeadersSchema :: Row Type -> Constraintclass RenderResponseHeadersSchema (headers :: Row Type)  where

Render response headers row as OpenAPI header object (for responses section)

Members

Instances

#RenderResponseHeadersSchemaRL Source

class RenderResponseHeadersSchemaRL :: RowList Type -> Row Type -> Constraintclass RenderResponseHeadersSchemaRL (rl :: RowList Type) (headers :: Row Type) | rl -> headers where

Helper class using RowList

Members

Instances

#RenderResponseSchema Source

class RenderResponseSchema :: Row Type -> Type -> Constraintclass RenderResponseSchema (headers :: Row Type) (body :: Type)  where

Render complete response object for OpenAPI (status 200 with headers and body)

Members

Instances

#RenderVariantResponseSchemaRL Source

class RenderVariantResponseSchemaRL :: RowList Type -> Constraintclass RenderVariantResponseSchemaRL (rl :: RowList Type)  where

Helper class that processes RowList for variant responses

Members

Instances

#ToOpenAPI Source

class ToOpenAPI (route :: Type) 

Generate complete OpenAPI operation object for a route Note: The instance for this typeclass is defined in Route.purs since it depends on the Route type defined there

#toOpenAPI Source

toOpenAPI :: forall @a. ToOpenAPI a => String

#buildOpenAPISpec' Source

buildOpenAPISpec' :: forall @routes. CollectOperations routes => CollectRouteSchemas routes => ValidateSchemaNames routes => OpenAPIInfoUor -> { servers :: Opt (Array ServerObject) } -> OpenAPISpec

Build a complete OpenAPI 3.0 spec with optional servers configuration.

#buildOpenAPISpec Source

Re-exports from Yoga.HTTP.API.Route.OpenAPIMetadata

#Title Source

data Title :: Symbol -> Type -> Typedata Title t a

Attach a title to a type. Example: String # Title "UserName"

Instances

#Pattern Source

data Pattern :: Symbol -> Type -> Typedata Pattern pat a

Set a regex pattern constraint. Example: String # Pattern "^[a-z]+$"

Instances

#OperationMetadata Source

type OperationMetadata = { deprecated :: Boolean, description :: Maybe String, operationId :: Maybe String, summary :: Maybe String, tags :: Array String }

#Format Source

data Format :: Symbol -> Type -> Typedata Format formatStr a

Attach a format annotation to a type. Example: String # Format "email"

Instances

#Example Source

data Example :: Symbol -> Type -> Typedata Example exampleValue a

Attach an example value to a type. Example: Int # Example "123"

Instances

#Enum Source

data Enum a

Wrapper to use an enum type (sum type with no-argument constructors) in routes. The type parameter should be a Generic sum type, and enum values will be automatically extracted from its constructor names.

Example: data Status = Pending | Active | Completed derive instance Generic Status _

type StatusParam = Enum Status

Instances

#Description Source

data Description :: Symbol -> Type -> Typedata Description desc a

Attach a description to a type. Example: Int # Description "The unique identifier for a user"

Instances

#Default Source

data Default :: Symbol -> Type -> Typedata Default val a

Set a default value. Example: Int # Default "10"

Instances

#GenericEnumValues Source

class GenericEnumValues rep  where

Extract enum values from a Generic sum type representation. Walks through GR.Sum constructors and collects constructor names.

Members

Instances

#HasEnum Source

class HasEnum ty  where

Members

Instances

#HasFormat Source

class HasFormat ty  where

Members

Instances

#HasOperationMetadata Source

class HasOperationMetadata route  where

Members

Instances

#HasTitle Source

class HasTitle ty  where

Members

Instances

Re-exports from Yoga.HTTP.API.Route.RenderMethod

#RenderMethod Source

class RenderMethod (method :: Type)  where

Render HTTP method to lowercase string (OpenAPI format)

Members

Instances

Re-exports from Yoga.HTTP.API.Route.Response

#ResponseData Source

type ResponseData :: Row Type -> Type -> Typetype ResponseData headers body = Response headers body

Deprecated alias for backwards compatibility

#Response Source

data Response :: Row Type -> Type -> Typedata Response headers body

Response data combining headers and body This is a data type (not type alias) to work with type class instances

Constructors

Instances

#respondNoHeaders Source

respondNoHeaders :: forall @label body r1 r2. IsSymbol label => Cons label (Response () body) r1 r2 => body -> Variant r2

Construct a variant response with no custom headers (most common case)

Example: respondNoHeaders (Proxy :: _ "ok") user respondNoHeaders (Proxy :: _ "notFound") { error: "Not found" }

Re-exports from Yoga.HTTP.API.Route.Route

#Route Source

data Route :: forall k. Type -> k -> Type -> Row Type -> Typedata Route method segments request respVariant

Constructors

Instances

#ConvertResponseVariant Source

class ConvertResponseVariant :: Row Type -> Row Type -> Constraintclass ConvertResponseVariant (userRow :: Row Type) (internalRow :: Row Type) | userRow -> internalRow

Convert a variant row with record syntax to Response types. Input: ( ok :: { body :: User }, notFound :: { body :: ErrorMsg } ) Output: ( ok :: Response () User, notFound :: Response () ErrorMsg )

Instances

#ConvertResponseVariantRL Source

class ConvertResponseVariantRL :: RowList Type -> Row Type -> Row Type -> Constraintclass ConvertResponseVariantRL (rl :: RowList Type) (acc :: Row Type) (out :: Row Type) | rl acc -> out

Instances

Re-exports from Yoga.HTTP.API.Route.StatusCode

#StatusCodeMap Source

class StatusCodeMap :: Symbol -> Constraintclass StatusCodeMap (sym :: Symbol)  where

Map variant constructor names (Symbols) to HTTP status codes

Members

Instances

#statusCodeToString Source

statusCodeToString :: StatusCode -> String

Convert StatusCode to String for OpenAPI generation

Re-exports from Yoga.Om

#onError Source

onError :: forall @label ty ctx errIn errOut a. IsSymbol label => Cons label ty (exception :: Error | errOut) (exception :: Error | errIn) => (ty -> Om ctx errOut a) -> Om ctx errIn a -> Om ctx errOut a

#mapError Source

mapError :: forall @from @to tyIn tyOut ctx errIn errMid errOut a. IsSymbol from => IsSymbol to => Cons from tyIn (exception :: Error | errMid) (exception :: Error | errIn) => Cons to tyOut (exception :: Error | errMid) (exception :: Error | errOut) => (tyIn -> tyOut) -> Om ctx errIn a -> Om ctx errOut a