git.iko.soy/rowtype-yoga/purescript-yoga-fetch-om
on main help sign in
Add VTA support and fix API parameter ordering

- Add VTA syntax support to client, substitutePathParams, appendQueryParams - Add RecordRow typeclass for clean VTA without Proxy - Fix all Simple.purs functions to take URL first for better currying - Remove unnecessary Path wrapper from README examples - Fix vitest configuration (remove explicit js-promise-aff dependency) - Update README with VTA examples and simplified features section - Bump to 0.2.0 (breaking change: parameter order)

commit9ef3e99951a0decdd4d231d81d5a14fc5f4aea10 authorMark <mark.eibes@gmail.com> dateSun 8 Feb 2026, 21:32 (8 months ago) parent3ad87f0
9 files changed+140−124
README.md+31−37 package.json+2−2 spago.yaml+1−2 src/Yoga/Fetch/Om.purs+22−6 src/Yoga/Fetch/Om/BuildUrl.purs+14−6 src/Yoga/Fetch/Om/Simple.purs+42−42 test/BuildUrl.Spec.purs+10−10 test/Complete.Example.purs+2−3 test/Simple.Spec.purs+16−16
README.md+31−37
@@ -10,57 +10,54 @@ spago install yoga-fetch-om
1010
1111## Quick Start
1212
13−### Example 1: Simple GET Request
13+### Example 1: Simple GET and POST Requests
1414
1515```purescript
16−import Yoga.Fetch.Om (GET, Route, Path, type (/), type (:), deriveClient)
16+import Yoga.Fetch.Om.Simple (get, post)
1717
18−type SimpleAPI =
19− { getUser ::
20− Route GET
21− (Path ("users" / "id" : Int))
22− {}
23− ( ok :: { body :: User } )
24− }
25−
26−api = deriveClient "https://api.example.com" (Proxy :: _ SimpleAPI)
18+type User = { id :: Int, name :: String, email :: String }
2719
2820main = do
29− user <- api.getUser { id: 42 }
30− log user.name -- Type-safe! Compiler knows user is a User
21+ -- Simple GET request
22+ user <- get @User "https://api.example.com/users/42" {}
23+ log user.name
24+
25+ -- Simple POST request with JSON body
26+ newUser <- post @User "https://api.example.com/users" {} { name: "Alice", email: "alice@example.com" }
27+ log $ "Created user with ID: " <> show newUser.id
3128```
3229
33−### Example 2: Complete CRUD API with Error Handling
30+### Example 2: Type-Safe API Client with Full CRUD
3431
3532```purescript
3633type UserAPI =
3734 { getUser ::
38− Route GET (Path ("users" / "id" : Int)) {}
35+ Route GET ("users" / "id" : Int) {}
3936 ( ok :: { body :: User }
4037 , notFound :: { body :: ErrorMessage }
4138 )
4239 , listUsers ::
43− Route GET (Path "users" :? { limit :: Int, offset :: Int }) {}
40+ Route GET ("users" :? { limit :: Int, offset :: Int }) {}
4441 ( ok :: { body :: Array User } )
4542 , createUser ::
46− Route POST (Path "users") { body :: JSON CreateUserRequest }
43+ Route POST "users" { body :: JSON CreateUserRequest }
4744 ( created :: { body :: User }
4845 , badRequest :: { body :: ErrorMessage }
4946 )
5047 , updateUser ::
51− Route PUT (Path ("users" / "id" : Int)) { body :: JSON UpdateUserRequest }
48+ Route PUT ("users" / "id" : Int) { body :: JSON UpdateUserRequest }
5249 ( ok :: { body :: User }
5350 , notFound :: { body :: ErrorMessage }
5451 , badRequest :: { body :: ErrorMessage }
5552 )
5653 , deleteUser ::
57− Route DELETE (Path ("users" / "id" : Int)) {}
54+ Route DELETE ("users" / "id" : Int) {}
5855 ( noContent :: { body :: {} }
5956 , notFound :: { body :: ErrorMessage }
6057 )
6158 }
6259
63−api = deriveClient "https://api.example.com" (Proxy :: _ UserAPI)
60+api = client @UserAPI "https://api.example.com"
6461
6562-- Create a user
6663user <- api.createUser { name: "Alice", email: "alice@example.com" }
@@ -110,7 +107,7 @@ Define your API once, use it everywhere:
110107server = buildServer apiRoutes handlers
111108
112109-- Client (yoga-fetch-om)
113−client = deriveClient baseUrl (Proxy :: _ apiRoutes)
110+apiClient = client @apiRoutes baseUrl
114111```
115112
116113Changes to routes automatically update both client and server!
@@ -159,39 +156,36 @@ All automatically based on your route types!
159156
160157## API Reference
161158
162−### `deriveClient`
159+### `client`
163160
164161```purescript
165−deriveClient :: String -> Proxy (Record routes) -> Record clients
162+client :: forall @routes. String -> Record clients
166163```
167164
168−Derives a record of client functions from a record of routes.
165+Derives a record of client functions from a record of routes using Visible Type Application.
169166
170167**Parameters:**
168+- `@routes` - Your API route type (provided via VTA syntax)
171169- `baseUrl` - Base URL (e.g., `"https://api.example.com"`)
172−- `routes` - Proxy of your API route definitions
173170
174171**Returns:** Record where each route becomes a function returning `Om context errors result`
175172
176−## Roadmap
173+**Example:**
174+```purescript
175+api = client @UserAPI "https://api.example.com"
176+```
177+
178+## Features
177179
178−### Current (0.1.0)
179−- ✅ Core client derivation
180+- ✅ Core client derivation with VTA syntax
180181- ✅ All HTTP methods (GET, POST, PUT, PATCH, DELETE)
181182- ✅ Path, query, and body parameters
183+- ✅ Request/response headers
182184- ✅ JSON encoding/decoding
185+- ✅ FormData support
183186- ✅ Variant response handling
184187- ✅ Om monad integration
185188
186−### Future
187−- ⏳ Request/response headers
188−- ⏳ Authentication (Bearer tokens, API keys)
189−- ⏳ Interceptors
190−- ⏳ Retry logic
191−- ⏳ Timeout configuration
192−- ⏳ FormData/file uploads
193−- ⏳ Request cancellation
194−
195189## License
196190
197191MIT
package.json+2−2
@@ -1,11 +1,11 @@
11{
22 "name": "purescript-yoga-fetch-om",
3− "version": "0.1.0",
3+ "version": "0.2.0",
44 "description": "Derive type-safe fetch clients from yoga HTTP API definitions",
55 "type": "module",
66 "scripts": {
77 "build": "spago build",
8− "test": "spago test",
8+ "test": "spago build && bunx vitest run",
99 "clean": "rm -rf output .spago",
1010 "watch": "spago build --watch",
1111 "repl": "spago repl",
spago.yaml+1−2
@@ -3,7 +3,7 @@ workspace: {}
33package:
44 name: yoga-fetch-om
55 publish:
6− version: 0.1.0
6+ version: 0.2.0
77 license: MIT
88 location:
99 githubOwner: rowtype-yoga
@@ -21,7 +21,6 @@ package:
2121 - exceptions: ">=6.1.0 <7.0.0"
2222 - http-methods: ">=6.0.0 <7.0.0"
2323 - js-fetch: ">=0.2.1 <0.3.0"
24− - js-promise-aff: ">=1.0.0 <2.0.0"
2524 - maybe: ">=6.0.0 <7.0.0"
2625 - prelude: ">=6.0.2 <7.0.0"
2726 - record: ">=4.0.0 <5.0.0"
src/Yoga/Fetch/Om.purs+22−6
@@ -1,11 +1,13 @@
11module Yoga.Fetch.Om
2− ( deriveClient
2+ ( client
3+ , deriveClient
34 , class DeriveClient
45 , deriveClientImpl
56 , class DeriveClientRL
67 , deriveClientRL
78 , class DeriveClientFn
89 , deriveClientFn
10+ , class RecordRow
911 , module Yoga.HTTP.API.Route
1012 , module Yoga.HTTP.API.Path
1113 , module Yoga.Fetch.Om.Simple
@@ -34,6 +36,12 @@ import Yoga.HTTP.API.Route (Route(..), GET, POST, PUT, DELETE, PATCH, Response(.
3436import Yoga.HTTP.API.Route.Handler (class SegmentPathParams, class SegmentQueryParams)
3537import Yoga.Om (Om, fromAff)
3638
39+-- | Extract row type from Record type
40+class RecordRow :: Type -> Row Type -> Constraint
41+class RecordRow t r | t -> r
42+
43+instance RecordRow (Record r) r
44+
3745class DeriveClientFn :: forall k1. Type -> k1 -> Type -> Row Type -> Row Type -> Row Type -> Type -> Type -> Constraint
3846class
3947 DeriveClientFn method segments request response errorRow successRow result fn
@@ -78,14 +86,22 @@ class DeriveClient :: Row Type -> Row Type -> Constraint
7886class DeriveClient routesRow clientsRow | routesRow -> clientsRow where
7987 deriveClientImpl :: String -> Proxy (Record routesRow) -> Record clientsRow
8088
81−-- | Derive API client functions from route definitions
89+-- | Derive API client functions from route definitions using VTA
90+-- |
91+-- | ```purescript
92+-- | type UserAPI = { getUser :: Route ... }
93+-- | api = client @UserAPI "https://api.example.com"
94+-- | ```
95+client :: forall @routes routesRow clientsRow. RecordRow routes routesRow => DeriveClient routesRow clientsRow => String -> Record clientsRow
96+client baseUrl = deriveClientImpl baseUrl (Proxy :: _ { | routesRow })
97+
98+-- | Deprecated: Use `client` with VTA instead
8299-- |
83−-- | Use a Proxy with a wildcard to avoid repetition:
84100-- | ```purescript
85−-- | api = deriveClient "https://api.example.com" (Proxy :: _ UserAPI)
101+-- | api = deriveClient @UserAPI "https://api.example.com"
86102-- | ```
87−deriveClient :: forall routesRow clientsRow. DeriveClient routesRow clientsRow => String -> Proxy (Record routesRow) -> Record clientsRow
88−deriveClient = deriveClientImpl
103+deriveClient :: forall @routesRow clientsRow. DeriveClient routesRow clientsRow => String -> Record clientsRow
104+deriveClient baseUrl = deriveClientImpl baseUrl (Proxy :: _ { | routesRow })
89105
90106instance
91107 ( RowToList routesRow rl
src/Yoga/Fetch/Om/BuildUrl.purs+14−6
@@ -3,8 +3,10 @@ module Yoga.Fetch.Om.BuildUrl
33 , buildUrl
44 , class SubstitutePathParams
55 , substitutePathParams
6+ , substitutePathParamsImpl
67 , class AppendQueryParams
78 , appendQueryParams
9+ , appendQueryParamsImpl
810 , class AppendQueryParamsRL
911 , appendQueryParamsRL
1012 , class SubstitutePathParamsRL
@@ -43,19 +45,22 @@ instance
4345 withBase = case baseUrl of
4446 "" -> pattern
4547 base -> base <> pattern
46− withPathParams = substitutePathParams (Proxy :: _ pathParams) pathParamsRec withBase
47− withQueryParams = appendQueryParams (Proxy :: _ queryParams) queryParamsRec withPathParams
48+ withPathParams = substitutePathParamsImpl (Proxy :: _ pathParams) pathParamsRec withBase
49+ withQueryParams = appendQueryParamsImpl (Proxy :: _ queryParams) queryParamsRec withPathParams
4850
4951class SubstitutePathParams :: Row Type -> Constraint
5052class SubstitutePathParams params where
51− substitutePathParams :: Proxy params -> Record params -> String -> String
53+ substitutePathParamsImpl :: Proxy params -> Record params -> String -> String
54+
55+substitutePathParams :: forall @params. SubstitutePathParams params => Record params -> String -> String
56+substitutePathParams = substitutePathParamsImpl (Proxy :: _ params)
5257
5358instance
5459 ( RowToList params rl
5560 , SubstitutePathParamsRL rl params
5661 ) =>
5762 SubstitutePathParams params where
58− substitutePathParams _ = substitutePathParamsRL (Proxy :: _ rl)
63+ substitutePathParamsImpl _ = substitutePathParamsRL (Proxy :: _ rl)
5964
6065class SubstitutePathParamsRL :: RowList Type -> Row Type -> Constraint
6166class SubstitutePathParamsRL rl r where
@@ -79,14 +84,17 @@ instance
7984
8085class AppendQueryParams :: Row Type -> Constraint
8186class AppendQueryParams params where
82− appendQueryParams :: Proxy params -> Record params -> String -> String
87+ appendQueryParamsImpl :: Proxy params -> Record params -> String -> String
88+
89+appendQueryParams :: forall @params. AppendQueryParams params => Record params -> String -> String
90+appendQueryParams = appendQueryParamsImpl (Proxy :: _ params)
8391
8492instance
8593 ( RowToList params rl
8694 , AppendQueryParamsRL rl params
8795 ) =>
8896 AppendQueryParams params where
89− appendQueryParams _ rec url = url <> queryString
97+ appendQueryParamsImpl _ rec url = url <> queryString
9098 where
9199 pairs = appendQueryParamsRL (Proxy :: _ rl) rec []
92100 queryString = case pairs of
src/Yoga/Fetch/Om/Simple.purs+42−42
@@ -109,138 +109,138 @@ get
109109 :: forall @a result headers ctx err
110110 . DecodeResponse a result
111111 => Homogeneous headers String
112− => Record headers
113− -> String
112+ => String
113+ -> Record headers
114114 -> Om ctx (fetchError :: FetchError | err) result
115−get headers url = _.body <$> simpleFetch @a GET headers url Nothing
115+get url headers = _.body <$> simpleFetch @a GET headers url Nothing
116116
117117getWithHeaders
118118 :: forall @a result headers ctx err
119119 . DecodeResponse a result
120120 => Homogeneous headers String
121− => Record headers
122− -> String
121+ => String
122+ -> Record headers
123123 -> Om ctx (fetchError :: FetchError | err) (FetchResponse result)
124−getWithHeaders headers url = simpleFetch @a GET headers url Nothing
124+getWithHeaders url headers = simpleFetch @a GET headers url Nothing
125125
126126delete
127127 :: forall @a result headers ctx err
128128 . DecodeResponse a result
129129 => Homogeneous headers String
130− => Record headers
131− -> String
130+ => String
131+ -> Record headers
132132 -> Om ctx (fetchError :: FetchError | err) result
133−delete headers url = _.body <$> simpleFetch @a DELETE headers url Nothing
133+delete url headers = _.body <$> simpleFetch @a DELETE headers url Nothing
134134
135135deleteWithHeaders
136136 :: forall @a result headers ctx err
137137 . DecodeResponse a result
138138 => Homogeneous headers String
139− => Record headers
140− -> String
139+ => String
140+ -> Record headers
141141 -> Om ctx (fetchError :: FetchError | err) (FetchResponse result)
142−deleteWithHeaders headers url = simpleFetch @a DELETE headers url Nothing
142+deleteWithHeaders url headers = simpleFetch @a DELETE headers url Nothing
143143
144144delete_
145145 :: forall headers ctx err
146146 . Homogeneous headers String
147− => Record headers
148− -> String
147+ => String
148+ -> Record headers
149149 -> Om ctx (fetchError :: FetchError | err) Unit
150−delete_ headers url = void $ simpleFetch @PlainTextResponse DELETE headers url Nothing
150+delete_ url headers = void $ simpleFetch @PlainTextResponse DELETE headers url Nothing
151151
152152post
153153 :: forall @a result headers body ctx err
154154 . DecodeResponse a result
155155 => Homogeneous headers String
156156 => WriteForeign body
157− => Record headers
158− -> String
157+ => String
158+ -> Record headers
159159 -> body
160160 -> Om ctx (fetchError :: FetchError | err) result
161−post headers url body = _.body <$> simpleFetch @a POST headers url (Just (writeJSON body))
161+post url headers body = _.body <$> simpleFetch @a POST headers url (Just (writeJSON body))
162162
163163postWithHeaders
164164 :: forall @a result headers body ctx err
165165 . DecodeResponse a result
166166 => Homogeneous headers String
167167 => WriteForeign body
168− => Record headers
169− -> String
168+ => String
169+ -> Record headers
170170 -> body
171171 -> Om ctx (fetchError :: FetchError | err) (FetchResponse result)
172−postWithHeaders headers url body = simpleFetch @a POST headers url (Just (writeJSON body))
172+postWithHeaders url headers body = simpleFetch @a POST headers url (Just (writeJSON body))
173173
174174post_
175175 :: forall headers body ctx err
176176 . Homogeneous headers String
177177 => WriteForeign body
178− => Record headers
179− -> String
178+ => String
179+ -> Record headers
180180 -> body
181181 -> Om ctx (fetchError :: FetchError | err) Unit
182−post_ headers url body = void $ simpleFetch @PlainTextResponse POST headers url (Just (writeJSON body))
182+post_ url headers body = void $ simpleFetch @PlainTextResponse POST headers url (Just (writeJSON body))
183183
184184put
185185 :: forall @a result headers body ctx err
186186 . DecodeResponse a result
187187 => Homogeneous headers String
188188 => WriteForeign body
189− => Record headers
190− -> String
189+ => String
190+ -> Record headers
191191 -> body
192192 -> Om ctx (fetchError :: FetchError | err) result
193−put headers url body = _.body <$> simpleFetch @a PUT headers url (Just (writeJSON body))
193+put url headers body = _.body <$> simpleFetch @a PUT headers url (Just (writeJSON body))
194194
195195putWithHeaders
196196 :: forall @a result headers body ctx err
197197 . DecodeResponse a result
198198 => Homogeneous headers String
199199 => WriteForeign body
200− => Record headers
201− -> String
200+ => String
201+ -> Record headers
202202 -> body
203203 -> Om ctx (fetchError :: FetchError | err) (FetchResponse result)
204−putWithHeaders headers url body = simpleFetch @a PUT headers url (Just (writeJSON body))
204+putWithHeaders url headers body = simpleFetch @a PUT headers url (Just (writeJSON body))
205205
206206put_
207207 :: forall headers body ctx err
208208 . Homogeneous headers String
209209 => WriteForeign body
210− => Record headers
211− -> String
210+ => String
211+ -> Record headers
212212 -> body
213213 -> Om ctx (fetchError :: FetchError | err) Unit
214−put_ headers url body = void $ simpleFetch @PlainTextResponse PUT headers url (Just (writeJSON body))
214+put_ url headers body = void $ simpleFetch @PlainTextResponse PUT headers url (Just (writeJSON body))
215215
216216patch
217217 :: forall @a result headers body ctx err
218218 . DecodeResponse a result
219219 => Homogeneous headers String
220220 => WriteForeign body
221− => Record headers
222− -> String
221+ => String
222+ -> Record headers
223223 -> body
224224 -> Om ctx (fetchError :: FetchError | err) result
225−patch headers url body = _.body <$> simpleFetch @a PATCH headers url (Just (writeJSON body))
225+patch url headers body = _.body <$> simpleFetch @a PATCH headers url (Just (writeJSON body))
226226
227227patchWithHeaders
228228 :: forall @a result headers body ctx err
229229 . DecodeResponse a result
230230 => Homogeneous headers String
231231 => WriteForeign body
232− => Record headers
233− -> String
232+ => String
233+ -> Record headers
234234 -> body
235235 -> Om ctx (fetchError :: FetchError | err) (FetchResponse result)
236−patchWithHeaders headers url body = simpleFetch @a PATCH headers url (Just (writeJSON body))
236+patchWithHeaders url headers body = simpleFetch @a PATCH headers url (Just (writeJSON body))
237237
238238patch_
239239 :: forall headers body ctx err
240240 . Homogeneous headers String
241241 => WriteForeign body
242− => Record headers
243− -> String
242+ => String
243+ -> Record headers
244244 -> body
245245 -> Om ctx (fetchError :: FetchError | err) Unit
246−patch_ headers url body = void $ simpleFetch @PlainTextResponse PATCH headers url (Just (writeJSON body))
246+patch_ url headers body = void $ simpleFetch @PlainTextResponse PATCH headers url (Just (writeJSON body))
test/BuildUrl.Spec.purs+10−10
@@ -22,26 +22,26 @@ testSubstitutePathParams :: Effect ViTest
2222testSubstitutePathParams = describe "substitutePathParams" $ do
2323 _ <- test "substitutes single path param" do
2424 let
25− result = substitutePathParams (Proxy :: _ (id :: Int)) { id: 42 } "/users/:id"
25+ result = substitutePathParams @(id :: Int) { id: 42 } "/users/:id"
2626 expectToEqual "/users/42" result
2727
2828 _ <- test "substitutes multiple path params" do
2929 let
30− result = substitutePathParams (Proxy :: _ (userId :: Int, postId :: Int))
30+ result = substitutePathParams @(userId :: Int, postId :: Int)
3131 { userId: 1, postId: 99 }
3232 "/users/:userId/posts/:postId"
3333 expectToEqual "/users/1/posts/99" result
3434
3535 _ <- test "handles String params" do
3636 let
37− result = substitutePathParams (Proxy :: _ (slug :: String))
37+ result = substitutePathParams @(slug :: String)
3838 { slug: "hello-world" }
3939 "/posts/:slug"
4040 expectToEqual "/posts/hello-world" result
4141
4242 test "handles empty params" do
4343 let
44− result = substitutePathParams (Proxy :: _ ()) {} "/users"
44+ result = substitutePathParams @() {} "/users"
4545 expectToEqual "/users" result
4646
4747--------------------------------------------------------------------------------
@@ -52,40 +52,40 @@ testAppendQueryParams :: Effect ViTest
5252testAppendQueryParams = describe "appendQueryParams" $ do
5353 _ <- test "appends single query param" do
5454 let
55− result = appendQueryParams (Proxy :: _ (limit :: Int)) { limit: 10 } "/users"
55+ result = appendQueryParams @(limit :: Int) { limit: 10 } "/users"
5656 expectToEqual "/users?limit=10" result
5757
5858 _ <- test "appends multiple query params" do
5959 let
60− result = appendQueryParams (Proxy :: _ (limit :: Int, offset :: Int))
60+ result = appendQueryParams @(limit :: Int, offset :: Int)
6161 { limit: 10, offset: 20 }
6262 "/users"
6363 expectToEqual "/users?limit=10&offset=20" result
6464
6565 _ <- test "handles Maybe params - Just" do
6666 let
67− result = appendQueryParams (Proxy :: _ (limit :: Maybe Int))
67+ result = appendQueryParams @(limit :: Maybe Int)
6868 { limit: Just 10 }
6969 "/users"
7070 expectToEqual "/users?limit=10" result
7171
7272 _ <- test "handles Maybe params - Nothing" do
7373 let
74− result = appendQueryParams (Proxy :: _ (limit :: Maybe Int))
74+ result = appendQueryParams @(limit :: Maybe Int)
7575 { limit: Nothing }
7676 "/users"
7777 expectToEqual "/users" result
7878
7979 _ <- test "handles mixed Maybe and required params" do
8080 let
81− result = appendQueryParams (Proxy :: _ (limit :: Maybe Int, offset :: Int))
81+ result = appendQueryParams @(limit :: Maybe Int, offset :: Int)
8282 { limit: Nothing, offset: 20 }
8383 "/users"
8484 expectToEqual "/users?offset=20" result
8585
8686 test "handles empty query params" do
8787 let
88− result = appendQueryParams (Proxy :: _ ()) {} "/users"
88+ result = appendQueryParams @() {} "/users"
8989 expectToEqual "/users" result
9090
9191--------------------------------------------------------------------------------
test/Complete.Example.purs+2−3
@@ -5,8 +5,7 @@ import Prelude
55import Data.Array (length)
66import Data.Maybe (Maybe(..))
77import Effect.Class.Console (log)
8−import Type.Proxy (Proxy(..))
9−import Yoga.Fetch.Om (GET, POST, PUT, DELETE, Route, JSON, Path, type (/), type (:), type (:?), deriveClient)
8+import Yoga.Fetch.Om (GET, POST, PUT, DELETE, Route, JSON, Path, type (/), type (:), type (:?), client)
109import Yoga.Om (Om, handleErrors)
1110
1211type User =
@@ -74,7 +73,7 @@ api
7473 , listUsers :: { limit :: Maybe Int, offset :: Maybe Int } -> Om {} () (Array User)
7574 , updateUser :: { id :: Int } -> UpdateUserRequest -> Om {} (badRequest :: ErrorMessage, notFound :: ErrorMessage) User
7675 }
77−api = deriveClient "https://api.example.com" (Proxy :: Proxy UserAPI)
76+api = client @UserAPI "https://api.example.com"
7877
7978exampleGetUser :: Om {} (notFound :: ErrorMessage) Unit
8079exampleGetUser = do
test/Simple.Spec.purs+16−16
@@ -10,59 +10,59 @@ type User = { id :: Int, name :: String, email :: String }
1010type CreateUser = { name :: String, email :: String }
1111
1212exampleGet :: forall ctx err. Om ctx (fetchError :: FetchError | err) User
13−exampleGet = get @User {} "https://api.example.com/users/42"
13+exampleGet = get @User "https://api.example.com/users/42" {}
1414
1515exampleGetWithAuth :: forall ctx err. Om ctx (fetchError :: FetchError | err) User
16−exampleGetWithAuth = get @User { authorization: "Bearer abc123" } "https://api.example.com/users/42"
16+exampleGetWithAuth = get @User "https://api.example.com/users/42" { authorization: "Bearer abc123" }
1717
1818exampleGetPlainText :: forall ctx err. Om ctx (fetchError :: FetchError | err) String
19−exampleGetPlainText = get @String {} "https://api.example.com/health"
19+exampleGetPlainText = get @String "https://api.example.com/health" {}
2020
2121exampleGetWithHeaders :: forall ctx err. Om ctx (fetchError :: FetchError | err) (FetchResponse User)
2222exampleGetWithHeaders = do
23− { headers, body: user } <- getWithHeaders @User {} "https://api.example.com/users/42"
23+ { headers, body: user } <- getWithHeaders @User "https://api.example.com/users/42" {}
2424 log $ "Got user: " <> user.name
2525 pure { headers, body: user }
2626
2727examplePost :: forall ctx err. Om ctx (fetchError :: FetchError | err) User
28−examplePost = post @User {} "https://api.example.com/users" { name: "Alice", email: "alice@example.com" }
28+examplePost = post @User "https://api.example.com/users" {} { name: "Alice", email: "alice@example.com" }
2929
3030examplePostFireAndForget :: forall ctx err. Om ctx (fetchError :: FetchError | err) Unit
31−examplePostFireAndForget = post_ {} "https://api.example.com/users" { name: "Alice", email: "alice@example.com" }
31+examplePostFireAndForget = post_ "https://api.example.com/users" {} { name: "Alice", email: "alice@example.com" }
3232
3333examplePut :: forall ctx err. Om ctx (fetchError :: FetchError | err) User
34−examplePut = put @User {} "https://api.example.com/users/42" { name: "Bob", email: "bob@example.com" }
34+examplePut = put @User "https://api.example.com/users/42" {} { name: "Bob", email: "bob@example.com" }
3535
3636examplePut_ :: forall ctx err. Om ctx (fetchError :: FetchError | err) Unit
37−examplePut_ = put_ {} "https://api.example.com/users/42" { name: "Bob", email: "bob@example.com" }
37+examplePut_ = put_ "https://api.example.com/users/42" {} { name: "Bob", email: "bob@example.com" }
3838
3939examplePatch :: forall ctx err. Om ctx (fetchError :: FetchError | err) User
40−examplePatch = patch @User {} "https://api.example.com/users/42" { name: "Bob" }
40+examplePatch = patch @User "https://api.example.com/users/42" {} { name: "Bob" }
4141
4242examplePatch_ :: forall ctx err. Om ctx (fetchError :: FetchError | err) Unit
43−examplePatch_ = patch_ {} "https://api.example.com/users/42" { name: "Bob" }
43+examplePatch_ = patch_ "https://api.example.com/users/42" {} { name: "Bob" }
4444
4545exampleDelete :: forall ctx err. Om ctx (fetchError :: FetchError | err) User
46−exampleDelete = delete @User {} "https://api.example.com/users/42"
46+exampleDelete = delete @User "https://api.example.com/users/42" {}
4747
4848exampleDelete_ :: forall ctx err. Om ctx (fetchError :: FetchError | err) Unit
49−exampleDelete_ = delete_ {} "https://api.example.com/users/42"
49+exampleDelete_ = delete_ "https://api.example.com/users/42" {}
5050
5151exampleHandleError :: forall ctx. Om ctx () Unit
5252exampleHandleError = do
53− user <- get @User {} "https://api.example.com/users/42"
53+ user <- get @User "https://api.example.com/users/42" {}
5454 # handleErrors { fetchError: \_ -> pure { id: 0, name: "unknown", email: "" } }
5555 log $ "Got user: " <> user.name
5656
5757exampleComposition :: forall ctx. Om ctx () Unit
5858exampleComposition = do
59− user <- post @User {} "https://api.example.com/users" { name: "Alice", email: "alice@example.com" }
59+ user <- post @User "https://api.example.com/users" {} { name: "Alice", email: "alice@example.com" }
6060 # handleErrors
6161 { fetchError: \e -> do
6262 log $ "Failed with status " <> show e.status <> ": " <> e.body
6363 pure { id: 0, name: "", email: "" }
6464 }
65− _ <- put @User {} ("https://api.example.com/users/" <> show user.id) { name: "Alice Updated", email: user.email }
65+ _ <- put @User ("https://api.example.com/users/" <> show user.id) {} { name: "Alice Updated", email: user.email }
6666 # handleErrors { fetchError: \_ -> pure user }
67− delete_ {} ("https://api.example.com/users/" <> show user.id)
67+ delete_ ("https://api.example.com/users/" <> show user.id) {}
6868 # handleErrors { fetchError: \_ -> pure unit }