Skip to content

Commit e844497

Browse files
committed
move script
1 parent b499c10 commit e844497

2 files changed

Lines changed: 71 additions & 22 deletions

File tree

packages/app/examples/strict-error-handling.ts

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
// REF: PR#3 blocking review from skulidropek
55
// SOURCE: n/a
66
// PURITY: SHELL
7-
// EFFECT: Effect<void, never, never> - all errors handled
7+
// EFFECT: Effect<ReadonlyArray<Pet>, never, never> - all errors handled with an empty-list fallback
88

99
import { Console, Effect, Match } from "effect"
1010

1111
import { type ClientOptions, createClientEffect } from "../src/index.js"
12-
import type { Paths } from "../tests/fixtures/petstore.openapi.js"
12+
import type { Components, Paths } from "../tests/fixtures/petstore.openapi.js"
13+
14+
type Pet = Components["schemas"]["Pet"]
15+
type Pets = ReadonlyArray<Pet>
1316

1417
const clientOptions: ClientOptions = {
1518
baseUrl: "https://petstore.example.com",
@@ -28,28 +31,52 @@ const clientOptions: ClientOptions = {
2831
// COMPLEXITY: O(1)
2932
const apiClient = createClientEffect<Paths>(clientOptions)
3033

31-
const listPetsProgram = apiClient.GET("/pets", {
34+
const emptyPets: Pets = []
35+
36+
/**
37+
* Converts a handled listPets failure into the list monoid identity.
38+
*
39+
* @param logEffect - Diagnostic shell effect that records the handled failure
40+
* @returns Effect with an empty pets list and no error channel
41+
*
42+
* @pure false - preserves Console logging effect
43+
* @effect never
44+
* @invariant forall handledFailure: recoverWithEmptyPets(handledFailure) = []
45+
* @complexity O(1)
46+
* @throws Never - all failures are represented in the Effect error channel
47+
*/
48+
const recoverWithEmptyPets = (logEffect: Effect.Effect<void>): Effect.Effect<Pets> =>
49+
logEffect.pipe(Effect.as(emptyPets))
50+
51+
const listPetsProgram: Effect.Effect<Pets> = apiClient.GET("/pets", {
3252
params: { query: { limit: 10 } }
3353
}).pipe(
3454
Effect.flatMap((success) =>
3555
Match.value(success).pipe(
36-
Match.when({ status: 200 }, ({ body }) => Console.log(`Got ${body.length} pets`)),
56+
Match.when({ status: 200 }, ({ body }) =>
57+
Console.log(`Got ${body.length} pets`).pipe(Effect.as(body))
58+
),
3759
Match.exhaustive
3860
)
3961
),
4062
Effect.catchTags({
4163
HttpError: (error) =>
4264
Match.value(error.status).pipe(
43-
Match.when(500, () => Console.log(`Server error: ${error.body.message}`)),
65+
Match.when(500, () =>
66+
recoverWithEmptyPets(Console.log(`Server error: ${error.body.message}`))
67+
),
4468
Match.exhaustive
4569
),
46-
TransportError: ({ error }) => Console.log(`Transport error: ${error.message}`),
47-
UnexpectedStatus: ({ body, status }) => Console.log(`Unexpected status ${status}: ${body}`),
70+
TransportError: ({ error }) => recoverWithEmptyPets(Console.log(`Transport error: ${error.message}`)),
71+
UnexpectedStatus: ({ body, status }) =>
72+
recoverWithEmptyPets(Console.log(`Unexpected status ${status}: ${body}`)),
4873
UnexpectedContentType: ({ actual, expected }) =>
49-
Console.log(`Unexpected content type ${actual ?? "unknown"}; expected ${expected.join(", ")}`),
50-
ParseError: ({ error }) => Console.log(`Parse error: ${error.message}`),
51-
DecodeError: ({ error }) => Console.log(`Decode error: ${error.message}`)
74+
recoverWithEmptyPets(
75+
Console.log(`Unexpected content type ${actual ?? "unknown"}; expected ${expected.join(", ")}`)
76+
),
77+
ParseError: ({ error }) => recoverWithEmptyPets(Console.log(`Parse error: ${error.message}`)),
78+
DecodeError: ({ error }) => recoverWithEmptyPets(Console.log(`Decode error: ${error.message}`))
5279
})
5380
)
5481

55-
export const strictErrorHandlingProgram: Effect.Effect<void> = listPetsProgram
82+
export const strictErrorHandlingProgram: Effect.Effect<Pets> = listPetsProgram

packages/app/src/examples/strict-error-handling.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
// REF: PR#3 blocking review from skulidropek
55
// SOURCE: n/a
66
// PURITY: SHELL
7-
// EFFECT: Effect<void, never, never> - all errors handled
7+
// EFFECT: Effect<ReadonlyArray<Pet>, never, never> - all errors handled with an empty-list fallback
88

99
import { Console, Effect, Match } from "effect"
1010

11-
import type { Paths } from "../../tests/fixtures/petstore.openapi.js"
11+
import type { Components, Paths } from "../../tests/fixtures/petstore.openapi.js"
1212
import { type ClientOptions, createClientEffect } from "../index.js"
1313

14+
type Pet = Components["schemas"]["Pet"]
15+
type Pets = ReadonlyArray<Pet>
16+
1417
const clientOptions: ClientOptions = {
1518
baseUrl: "https://petstore.example.com",
1619
credentials: "include"
@@ -28,28 +31,47 @@ const clientOptions: ClientOptions = {
2831
// COMPLEXITY: O(1)
2932
const apiClient = createClientEffect<Paths>(clientOptions)
3033

31-
const listPetsProgram = apiClient.GET("/pets", {
34+
const emptyPets: Pets = []
35+
36+
/**
37+
* Converts a handled listPets failure into the list monoid identity.
38+
*
39+
* @param logEffect - Diagnostic shell effect that records the handled failure
40+
* @returns Effect with an empty pets list and no error channel
41+
*
42+
* @pure false - preserves Console logging effect
43+
* @effect never
44+
* @invariant forall handledFailure: recoverWithEmptyPets(handledFailure) = []
45+
* @complexity O(1)
46+
* @throws Never - all failures are represented in the Effect error channel
47+
*/
48+
const recoverWithEmptyPets = (logEffect: Effect.Effect<void>): Effect.Effect<Pets> =>
49+
logEffect.pipe(Effect.as(emptyPets))
50+
51+
const listPetsProgram: Effect.Effect<Pets> = apiClient.GET("/pets", {
3252
params: { query: { limit: 10 } }
3353
}).pipe(
3454
Effect.flatMap((success) =>
3555
Match.value(success).pipe(
36-
Match.when({ status: 200 }, ({ body }) => Console.log(`Got ${body.length} pets`)),
56+
Match.when({ status: 200 }, ({ body }) => Console.log(`Got ${body.length} pets`).pipe(Effect.as(body))),
3757
Match.exhaustive
3858
)
3959
),
4060
Effect.catchTags({
4161
HttpError: (error) =>
4262
Match.value(error.status).pipe(
43-
Match.when(500, () => Console.log(`Server error: ${error.body.message}`)),
63+
Match.when(500, () => recoverWithEmptyPets(Console.log(`Server error: ${error.body.message}`))),
4464
Match.exhaustive
4565
),
46-
TransportError: ({ error }) => Console.log(`Transport error: ${error.message}`),
47-
UnexpectedStatus: ({ body, status }) => Console.log(`Unexpected status ${status}: ${body}`),
66+
TransportError: ({ error }) => recoverWithEmptyPets(Console.log(`Transport error: ${error.message}`)),
67+
UnexpectedStatus: ({ body, status }) => recoverWithEmptyPets(Console.log(`Unexpected status ${status}: ${body}`)),
4868
UnexpectedContentType: ({ actual, expected }) =>
49-
Console.log(`Unexpected content type ${actual ?? "unknown"}; expected ${expected.join(", ")}`),
50-
ParseError: ({ error }) => Console.log(`Parse error: ${error.message}`),
51-
DecodeError: ({ error }) => Console.log(`Decode error: ${error.message}`)
69+
recoverWithEmptyPets(
70+
Console.log(`Unexpected content type ${actual ?? "unknown"}; expected ${expected.join(", ")}`)
71+
),
72+
ParseError: ({ error }) => recoverWithEmptyPets(Console.log(`Parse error: ${error.message}`)),
73+
DecodeError: ({ error }) => recoverWithEmptyPets(Console.log(`Decode error: ${error.message}`))
5274
})
5375
)
5476

55-
export const strictErrorHandlingProgram: Effect.Effect<void> = listPetsProgram
77+
export const strictErrorHandlingProgram: Effect.Effect<Pets> = listPetsProgram

0 commit comments

Comments
 (0)