Skip to content

rowtype-yoga/purescript-yoga-fetch-om

Repository files navigation

purescript-yoga-fetch-om

Derive type-safe fetch clients from purescript-yoga-http-api route definitions.

Installation

spago install yoga-fetch-om

Quick Start

Example 1: Simple GET and POST Requests

import Yoga.Fetch.Om.Simple (get, post)

type User = { id :: Int, name :: String, email :: String }

main = do
  -- Simple GET request
  user <- get @User "https://api.example.com/users/42" {}
  log user.name
  
  -- Simple POST request with JSON body
  newUser <- post @User "https://api.example.com/users" {} { name: "Alice", email: "alice@example.com" }
  log $ "Created user with ID: " <> show newUser.id

Example 2: Type-Safe API Client with Full CRUD

type UserAPI =
  { getUser ::
      Route GET ("users" / "id" : Int) {}
        ( ok :: { body :: User }
        , notFound :: { body :: ErrorMessage }
        )
  , listUsers ::
      Route GET ("users" :? { limit :: Int, offset :: Int }) {}
        ( ok :: { body :: Array User } )
  , createUser ::
      Route POST "users" { body :: JSON CreateUserRequest }
        ( created :: { body :: User }
        , badRequest :: { body :: ErrorMessage }
        )
  , updateUser ::
      Route PUT ("users" / "id" : Int) { body :: JSON UpdateUserRequest }
        ( ok :: { body :: User }
        , notFound :: { body :: ErrorMessage }
        , badRequest :: { body :: ErrorMessage }
        )
  , deleteUser ::
      Route DELETE ("users" / "id" : Int) {}
        ( noContent :: { body :: {} }
        , notFound :: { body :: ErrorMessage }
        )
  }

api = client @UserAPI "https://api.example.com"

-- Create a user
user <- api.createUser { name: "Alice", email: "alice@example.com" }
  # handleErrors
      { badRequest: \err -> do
          log $ "Validation error: " <> err.error
          throw err
      }

-- Update with path param + body
updated <- api.updateUser { id: user.id } { name: "Alice Updated", email: user.email }
  # handleErrors
      { notFound: \_ -> throw userNotFound
      , badRequest: \err -> throw validationError
      }

-- Query with pagination
users <- api.listUsers { limit: 10, offset: 0 }

More Examples

See the test files for complete, runnable examples with all imports:

Features

✅ Type-Safe Everything

  • Path parameters: /users/:id requires { id: Int }
  • Query parameters: Type-safe query strings with ?
  • Request bodies: Automatic JSON serialization
  • Response bodies: Automatic JSON parsing
  • Error handling: Exhaustive pattern matching on variants

✅ Single Source of Truth

Define your API once, use it everywhere:

-- Server (yoga-fastify-om)
server = buildServer apiRoutes handlers

-- Client (yoga-fetch-om)
apiClient = client @apiRoutes baseUrl

Changes to routes automatically update both client and server!

✅ Automatic Derivation

No manual client code:

  • ✅ URL building with path parameter substitution
  • ✅ Query string construction
  • ✅ JSON request serialization
  • ✅ JSON response parsing
  • ✅ Status code → variant mapping
  • ✅ CORS and credentials handling

✅ Integration with yoga-om

Works seamlessly with the Om monad:

getUserProfile :: Om AppContext AppErrors User
getUserProfile = do
  { api, userId } <- ask
  api.getUser { id: userId }
    # handleErrors { notFound: \_ -> throw { userNotFound: userId } }

How It Works

The library uses PureScript's type system to:

  1. Extract parameters from route definitions at compile time

    • Path params: "users" / "id" : Int{ id :: Int }
    • Query params: :? { limit :: Int }{ limit :: Int }
    • Body params: { body :: JSON User } → request body
  2. Build URLs automatically

    • Pattern: /users/:id + params: { id: 42 }/users/42
    • Query: ?limit=10&offset=20
  3. Make requests with js-fetch and js-promise-aff

  4. Parse responses by mapping status codes to variant labels

    • 200"ok", 404"notFound", etc.

All automatically based on your route types!

API Reference

client

client :: forall @routes. String -> Record clients

Derives a record of client functions from a record of routes using Visible Type Application.

Parameters:

  • @routes - Your API route type (provided via VTA syntax)
  • baseUrl - Base URL (e.g., "https://api.example.com")

Returns: Record where each route becomes a function returning Om context errors result

Example:

api = client @UserAPI "https://api.example.com"

Features

  • ✅ Core client derivation with VTA syntax
  • ✅ All HTTP methods (GET, POST, PUT, PATCH, DELETE)
  • ✅ Path, query, and body parameters
  • ✅ Request/response headers
  • ✅ JSON encoding/decoding
  • ✅ FormData support
  • ✅ Variant response handling
  • ✅ Om monad integration

License

MIT

Related Projects

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published