Skip to content

Commit b280293

Browse files
committed
refactor(openapi): use openapi-effect client
1 parent 126710b commit b280293

21 files changed

Lines changed: 735 additions & 276 deletions

bun.lock

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

packages/api/src/api/openapi.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -782,8 +782,8 @@ export const DockerGitApi = HttpApi.make("docker-git")
782782
// CHANGE: derive Swagger/OpenAPI from the Effect HttpApi contract.
783783
// WHY: frontend clients must be generated from one typed REST contract.
784784
// QUOTE(ТЗ): "Надо сделать REST API нормальный на базе Effect и использовать Swagger."
785-
// REF: user-message-2026-06-18-openapi-fetch
786-
// SOURCE: https://openapi-ts.dev/openapi-fetch/
785+
// REF: user-message-2026-06-19-openapi-effect
786+
// SOURCE: https://github.com/ProverCoderAI/openapi-effect
787787
// FORMAT THEOREM: forall endpoint e in DockerGitApi, e is represented in buildDockerGitOpenApi().paths.
788788
// PURITY: CORE
789789
// EFFECT: none

packages/api/src/http.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ const textResponse = (data: string, contentType: string, status = 200) =>
317317
// CHANGE: expose browser-readable Swagger UI for the Effect REST contract.
318318
// WHY: generated clients and humans must inspect the same OpenAPI document.
319319
// QUOTE(ТЗ): "использовать Swagger"
320-
// REF: user-message-2026-06-18-openapi-fetch
320+
// REF: user-message-2026-06-19-openapi-effect
321321
// SOURCE: n/a
322322
// FORMAT THEOREM: docsPath(d) = p -> openApiPath(d) = sibling(p, "openapi.json")
323323
// PURITY: CORE

packages/app/src/web/api-create-project.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Effect } from "effect"
22

3+
import { dockerGitOpenApi } from "./api-http.js"
34
import {
45
type BaseCreateProjectBody,
56
baseCreateProjectBody,
@@ -9,7 +10,6 @@ import {
910
} from "./api-project-create-body.js"
1011
import { CreateProjectAcceptedResponseSchema } from "./api-schema.js"
1112
import type { CreateProjectAcceptedResponse } from "./api-schema.js"
12-
import { openApiJsonSchema } from "./openapi-client.js"
1313

1414
type CreateProjectAcceptedBody = Readonly<
1515
& BaseCreateProjectBody
@@ -42,7 +42,7 @@ export const createProjectAcceptedBody = (draft: CreateProjectRequestDraft): Cre
4242
export const startCreateProject = (
4343
draft: CreateProjectRequestDraft
4444
): Effect.Effect<CreateProjectAcceptedResponse, string> =>
45-
openApiJsonSchema(CreateProjectAcceptedResponseSchema, (client) =>
45+
dockerGitOpenApi.openApiJsonSchema(CreateProjectAcceptedResponseSchema, (client) =>
4646
client.POST("/projects", {
4747
body: createProjectAcceptedBody(draft)
4848
}))

packages/app/src/web/api-database.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Effect } from "effect"
22

3+
import { dockerGitOpenApi } from "./api-http.js"
34
import {
45
ProjectDatabaseForwardResponseSchema,
56
ProjectDatabaseForwardsResponseSchema,
@@ -8,15 +9,14 @@ import {
89
ProjectDatabaseSessionResponseSchema
910
} from "./api-schema.js"
1011
import type { ProjectDatabaseForward, ProjectDatabaseSession } from "./api-schema.js"
11-
import { openApiJsonSchema, openApiVoid } from "./openapi-client.js"
1212

1313
export const projectDatabaseEditorUrl = (session: ProjectDatabaseSession): string => session.editorPath
1414

1515
export const projectDatabaseExternalUrl = (forward: ProjectDatabaseForward): string =>
1616
`${forward.publicHost}:${forward.hostPort}`
1717

1818
export const loadProjectDatabaseProfiles = (projectId: string) =>
19-
openApiJsonSchema(
19+
dockerGitOpenApi.openApiJsonSchema(
2020
ProjectDatabaseProfilesResponseSchema,
2121
(client) =>
2222
client.GET("/projects/{projectId}/databases/profiles", {
@@ -27,7 +27,7 @@ export const loadProjectDatabaseProfiles = (projectId: string) =>
2727
)
2828

2929
export const loadProjectDatabaseForwards = (projectId: string) =>
30-
openApiJsonSchema(
30+
dockerGitOpenApi.openApiJsonSchema(
3131
ProjectDatabaseForwardsResponseSchema,
3232
(client) =>
3333
client.GET("/projects/{projectId}/databases/forwards", {
@@ -42,7 +42,7 @@ export const saveProjectDatabaseProfile = (
4242
connectionString: string,
4343
label: string | null
4444
) =>
45-
openApiJsonSchema(
45+
dockerGitOpenApi.openApiJsonSchema(
4646
ProjectDatabaseProfileResponseSchema,
4747
(client) =>
4848
client.POST("/projects/{projectId}/databases/profiles", {
@@ -57,7 +57,7 @@ export const deleteProjectDatabaseProfile = (
5757
projectId: string,
5858
profileId: string
5959
) =>
60-
openApiVoid((client) =>
60+
dockerGitOpenApi.openApiVoid((client) =>
6161
client.DELETE("/projects/{projectId}/databases/profiles/{profileId}", {
6262
params: { path: { profileId, projectId } }
6363
})
@@ -67,7 +67,7 @@ export const exposeProjectDatabaseProfile = (
6767
projectId: string,
6868
profileId: string
6969
) =>
70-
openApiJsonSchema(
70+
dockerGitOpenApi.openApiJsonSchema(
7171
ProjectDatabaseForwardResponseSchema,
7272
(client) =>
7373
client.POST("/projects/{projectId}/databases/profiles/{profileId}/expose", {
@@ -81,14 +81,14 @@ export const deleteProjectDatabaseForward = (
8181
projectId: string,
8282
profileId: string
8383
) =>
84-
openApiVoid((client) =>
84+
dockerGitOpenApi.openApiVoid((client) =>
8585
client.DELETE("/projects/{projectId}/databases/profiles/{profileId}/expose", {
8686
params: { path: { profileId, projectId } }
8787
})
8888
)
8989

9090
export const loadProjectDatabaseSession = (projectId: string) =>
91-
openApiJsonSchema(
91+
dockerGitOpenApi.openApiJsonSchema(
9292
ProjectDatabaseSessionResponseSchema,
9393
(client) =>
9494
client.GET("/projects/{projectId}/databases/session", {
@@ -99,7 +99,7 @@ export const loadProjectDatabaseSession = (projectId: string) =>
9999
)
100100

101101
export const openProjectDatabaseEditor = (projectId: string) =>
102-
openApiJsonSchema(
102+
dockerGitOpenApi.openApiJsonSchema(
103103
ProjectDatabaseSessionResponseSchema,
104104
(client) =>
105105
client.POST("/projects/{projectId}/databases/open", {
@@ -110,7 +110,7 @@ export const openProjectDatabaseEditor = (projectId: string) =>
110110
)
111111

112112
export const restartProjectDatabaseEditor = (projectId: string) =>
113-
openApiJsonSchema(
113+
dockerGitOpenApi.openApiJsonSchema(
114114
ProjectDatabaseSessionResponseSchema,
115115
(client) =>
116116
client.POST("/projects/{projectId}/databases/restart", {

packages/app/src/web/api-http.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { FetchHttpClient, HttpBody, HttpClient } from "@effect/platform"
22
import * as ParseResult from "@effect/schema/ParseResult"
33
import * as Schema from "@effect/schema/Schema"
44
import * as TreeFormatter from "@effect/schema/TreeFormatter"
5+
import { createClient } from "@prover-coder-ai/docker-git-openapi"
56
import { Effect, Either } from "effect"
67

78
import { type JsonRequest, parseResponseBody, renderJsonPayload } from "../docker-git/api-json.js"
@@ -84,6 +85,21 @@ export const resolveApiBaseUrl = (): string => {
8485
: trimTrailingSlash(configured.trim())
8586
}
8687

88+
/**
89+
* Configured docker-git OpenAPI client for the web HTTP boundary.
90+
*
91+
* @pure false - binds the shared OpenAPI client to the app-specific base URL resolver.
92+
* @effect none during construction; returned client methods perform HTTP IO when their Effects run.
93+
* @invariant transport, error rendering, and schema decoding stay owned by the openapi package.
94+
* @precondition resolveApiBaseUrl returns a valid docker-git API base URL for the current runtime.
95+
* @postcondition app modules depend on one configured OpenAPI client instance.
96+
* @complexity O(1)/O(1) for construction, excluding request execution.
97+
* @throws Never.
98+
*/
99+
export const dockerGitOpenApi = createClient({
100+
resolveBaseUrl: resolveApiBaseUrl
101+
})
102+
87103
export const requestText = (
88104
method: ApiHttpMethod,
89105
path: string,

0 commit comments

Comments
 (0)