Skip to content

Commit 7d9deb6

Browse files
committed
refactor(openapi): use published openapi-effect types
1 parent b280293 commit 7d9deb6

6 files changed

Lines changed: 52 additions & 320 deletions

File tree

bun.lock

Lines changed: 4 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/app/tsconfig.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"lib": ["ES2023", "DOM", "DOM.Iterable"],
99
"jsx": "react-jsx",
1010
"paths": {
11-
"@prover-coder-ai/openapi-effect": ["../openapi/src/types/openapi-effect.d.ts"],
1211
"@/*": ["./src/*"]
1312
}
1413
},

packages/openapi/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,8 @@
2828
},
2929
"dependencies": {
3030
"@effect/schema": "^0.75.5",
31-
"@prover-coder-ai/openapi-effect": "^1.0.22",
32-
"effect": "^3.21.3",
33-
"openapi-typescript-helpers": "^0.1.0"
31+
"@prover-coder-ai/openapi-effect": "^1.0.27",
32+
"effect": "^3.21.3"
3433
},
3534
"devDependencies": {
3635
"openapi-typescript": "^7.13.0",

packages/openapi/src/client.ts

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import * as ParseResult from "@effect/schema/ParseResult"
22
import type * as Schema from "@effect/schema/Schema"
33
import * as TreeFormatter from "@effect/schema/TreeFormatter"
44
import { createClientEffect } from "@prover-coder-ai/openapi-effect"
5-
import type { ClientOptions, Middleware } from "@prover-coder-ai/openapi-effect"
6-
import { Effect, Either, Option } from "effect"
5+
import type { BoundaryError, ClientOptions, Middleware } from "@prover-coder-ai/openapi-effect"
6+
import { Effect, Either, Match } from "effect"
77

88
import type { paths } from "./openapi-paths.js"
99

@@ -20,13 +20,19 @@ export type ApiTransportValue =
2020
| ReadonlyArray<ApiTransportValue>
2121
| { readonly [key: string]: ApiTransportValue }
2222

23-
export type OpenApiResponse<A> = {
24-
readonly data?: A
25-
readonly error?: unknown
26-
readonly response: Response
23+
export type OpenApiSuccess = {
24+
readonly status: number | string
25+
readonly contentType: string
26+
readonly body: unknown
2727
}
2828

29-
export type OpenApiRequestResult = Effect.Effect<OpenApiResponse<unknown>, Error>
29+
export type OpenApiHttpError = OpenApiSuccess & {
30+
readonly _tag: "HttpError"
31+
}
32+
33+
export type OpenApiFailure = OpenApiHttpError | BoundaryError
34+
35+
export type OpenApiRequestResult = Effect.Effect<OpenApiSuccess, OpenApiFailure>
3036

3137
export type OpenApiRequest = (client: DockerGitOpenApiTransportClient) => OpenApiRequestResult
3238

@@ -44,7 +50,7 @@ export type DockerGitOpenApiClient = {
4450
readonly openApiVoid: (request: OpenApiRequest) => Effect.Effect<void, string>
4551
}
4652

47-
type RunOpenApi = (request: OpenApiRequest) => Effect.Effect<OpenApiResponse<unknown>, string>
53+
type RunOpenApi = (request: OpenApiRequest) => Effect.Effect<OpenApiSuccess, OpenApiFailure>
4854

4955
const noCacheHeaders: Readonly<Record<string, string>> = {
5056
accept: "application/json",
@@ -102,14 +108,13 @@ const decodeTransportValue = (value: unknown): Effect.Effect<ApiTransportValue,
102108
Effect.flatMap((rendered) => Effect.fail(`Invalid JSON response payload: ${rendered}`))
103109
)
104110

105-
const renderOpenApiError = (
106-
response: Response,
107-
error: unknown
111+
const renderOpenApiHttpError = (
112+
error: OpenApiHttpError
108113
): Effect.Effect<string> => {
109-
if (response.status === 429) {
114+
if (String(error.status) === "429") {
110115
return Effect.succeed("HTTP 429: tunnel or proxy rate limited the request. Retry or request a fresh tunnel URL.")
111116
}
112-
return error === undefined ? Effect.succeed(`HTTP ${response.status}`) : renderTransportValue(error)
117+
return error.body === undefined ? Effect.succeed(`HTTP ${error.status}`) : renderTransportValue(error.body)
113118
}
114119

115120
const noCacheGetMiddleware: DockerGitOpenApiMiddleware = {
@@ -175,16 +180,27 @@ export const createTransportClient = (
175180
export const runOpenApi = (
176181
client: DockerGitOpenApiTransportClient,
177182
request: OpenApiRequest
178-
): Effect.Effect<OpenApiResponse<unknown>, string> =>
179-
request(client).pipe(
180-
Effect.mapError(String)
183+
): Effect.Effect<OpenApiSuccess, OpenApiFailure> => request(client)
184+
185+
const renderOpenApiFailure = (failure: OpenApiFailure): Effect.Effect<string> =>
186+
Match.value(failure).pipe(
187+
Match.when({ _tag: "HttpError" }, renderOpenApiHttpError),
188+
Match.when({ _tag: "TransportError" }, (error) => Effect.succeed(error.error.message)),
189+
Match.when({ _tag: "UnexpectedStatus" }, (error) => Effect.succeed(`HTTP ${error.status}: ${error.body}`)),
190+
Match.when({ _tag: "UnexpectedContentType" }, (error) =>
191+
Effect.succeed(`HTTP ${error.status}: unexpected content type ${error.actual ?? "none"}: ${error.body}`)
192+
),
193+
Match.when({ _tag: "ParseError" }, (error) =>
194+
Effect.succeed(`HTTP ${error.status}: invalid ${error.contentType} response: ${error.error.message}`)
195+
),
196+
Match.when({ _tag: "DecodeError" }, (error) =>
197+
Effect.succeed(`HTTP ${error.status}: invalid decoded response: ${error.error.message}`)
198+
),
199+
Match.exhaustive
181200
)
182201

183-
const failRenderedOpenApiError = (
184-
response: Response,
185-
error: unknown
186-
): Effect.Effect<never, string> =>
187-
renderOpenApiError(response, error).pipe(
202+
const failRenderedOpenApiFailure = (failure: OpenApiFailure): Effect.Effect<never, string> =>
203+
renderOpenApiFailure(failure).pipe(
188204
Effect.flatMap((message) => Effect.fail(message))
189205
)
190206

@@ -193,16 +209,11 @@ const openApiJsonWithRunner = (
193209
request: OpenApiRequest
194210
): Effect.Effect<ApiTransportValue, string> =>
195211
runner(request).pipe(
196-
Effect.flatMap(({ data, error, response }) =>
197-
Option.match(Option.fromNullable(error), {
198-
onNone: () =>
199-
response.ok
200-
? data === undefined
201-
? Effect.fail(`HTTP ${response.status}: empty response`)
202-
: decodeTransportValue(data)
203-
: failRenderedOpenApiError(response, error),
204-
onSome: (apiError) => failRenderedOpenApiError(response, apiError)
205-
})
212+
Effect.catchAll(failRenderedOpenApiFailure),
213+
Effect.flatMap((success) =>
214+
success.body === undefined
215+
? Effect.fail(`HTTP ${success.status}: empty response`)
216+
: decodeTransportValue(success.body)
206217
)
207218
)
208219

@@ -226,14 +237,8 @@ const openApiVoidWithRunner = (
226237
request: OpenApiRequest
227238
): Effect.Effect<void, string> =>
228239
runner(request).pipe(
229-
Effect.flatMap(({ error, response }) =>
230-
response.ok
231-
? Option.match(Option.fromNullable(error), {
232-
onNone: () => Effect.void,
233-
onSome: (apiError) => failRenderedOpenApiError(response, apiError)
234-
})
235-
: failRenderedOpenApiError(response, error)
236-
)
240+
Effect.asVoid,
241+
Effect.catchAll(failRenderedOpenApiFailure)
237242
)
238243

239244
/**
@@ -335,10 +340,8 @@ export const createClient = (
335340
return clientCache.client
336341
}
337342

338-
const runRuntimeOpenApi = (request: OpenApiRequest): Effect.Effect<OpenApiResponse<unknown>, string> =>
339-
request(getOpenApiClient()).pipe(
340-
Effect.mapError(String)
341-
)
343+
const runRuntimeOpenApi = (request: OpenApiRequest): Effect.Effect<OpenApiSuccess, OpenApiFailure> =>
344+
request(getOpenApiClient())
342345

343346
return {
344347
openApiJson: (request) => openApiJsonWithRunner(runRuntimeOpenApi, request),

0 commit comments

Comments
 (0)