Skip to content

Commit

Permalink
R/use-platform-http-client (#53)
Browse files Browse the repository at this point in the history
* extend

* convert to use platform client

* Remove legacy exports

* add changeset
  • Loading branch information
patroza authored Oct 21, 2023
1 parent 016a099 commit 51b546c
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 38 deletions.
7 changes: 7 additions & 0 deletions .changeset/weak-knives-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@effect-app/prelude": minor
"@effect-app/core": minor
"@effect-app/vue": minor
---

feat: Convert clientFor to use @effect/platform HttpClient
5 changes: 0 additions & 5 deletions packages/core/_src/_global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,6 @@ import { Lens, lens, Optic } from "@fp-ts/optic"
*/
import type { lazyGetter } from "@effect-app/core/utils"

/**
* @tsplus global
*/
import { HttpClient, HttpClientFetch } from "@effect-app/core/http"

// TODO: these may be problematic global imports causing bundling issues?
// "import type {} from" doesn't work outside this package
import "./_global.ext.js"
Expand Down
4 changes: 0 additions & 4 deletions packages/core/_src/http.ts

This file was deleted.

10 changes: 0 additions & 10 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -294,16 +294,6 @@
"default": "./_cjs/global.cjs"
}
},
"./http": {
"import": {
"types": "./dist/http.d.ts",
"default": "./dist/http.js"
},
"require": {
"types": "./dist/http.d.ts",
"default": "./_cjs/http.cjs"
}
},
"./http/http-client": {
"import": {
"types": "./dist/http/http-client.d.ts",
Expand Down
21 changes: 21 additions & 0 deletions packages/core/vendor/effect-platform-tsplus.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@
}
]
},
{
"definitionName": "patch",
"definitionKind": "const",
"extensions": [
{
"kind": "static",
"typeName": "effect/platform/Http/ClientRequest.Ops",
"name": "patch"
}
]
},
{
"definitionName": "put",
"definitionKind": "const",
Expand Down Expand Up @@ -183,6 +194,11 @@
"definitionName": "jsonBody",
"definitionKind": "const",
"extensions": [
{
"kind": "pipeable",
"typeName": "effect/platform/Http/ClientRequest",
"name": "jsonBody"
},
{
"kind": "static",
"typeName": "effect/platform/Http/ClientRequest.Ops",
Expand All @@ -194,6 +210,11 @@
"definitionName": "unsafeJsonBody",
"definitionKind": "const",
"extensions": [
{
"kind": "pipeable",
"typeName": "effect/platform/Http/ClientRequest",
"name": "unsafeJsonBody"
},
{
"kind": "static",
"typeName": "effect/platform/Http/ClientRequest.Ops",
Expand Down
81 changes: 65 additions & 16 deletions packages/prelude/_src/client/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,85 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { HttpClient } from "@effect-app/core/http"
import type { HttpClient as HttpClientLegacy } from "@effect-app/core/http"
import { constant, flow } from "@effect-app/prelude/Function"
import type { ReqRes, RequestSchemed } from "@effect-app/prelude/schema"
import { StringId } from "@effect-app/prelude/schema"
import { Path } from "path-parser"
import qs from "query-string"
import { getConfig } from "./config.js"
import { ApiConfig } from "./config.js"

export type FetchError = HttpClient.HttpError<string>
export type FetchError = HttpClientLegacy.HttpError<string>

export class ResponseError {
public readonly _tag = "ResponseError"
constructor(public readonly error: unknown) {}
}

export function fetchApi(method: HttpClient.Method, path: string, body?: unknown) {
const request = HttpClient.request(method, "JSON", "JSON")
return getConfig(({ apiUrl, headers }) =>
HttpClient
.withHeaders({
"request-id": headers.flatMap((_) => _.get("request-id")).value ?? StringId.make(),
...headers.map((_) => Object.fromEntries(_)).value
})(request(`${apiUrl}${path}`, body))
.map((x) => ({ ...x, body: x.body.value ?? null }))
)
const getClient = HttpClient.flatMap((defaultClient) =>
ApiConfig
.Tag
.map(({ apiUrl, headers }) =>
defaultClient
.filterStatusOk
.mapRequest(ClientRequest.acceptJson)
.mapRequest(ClientRequest.prependUrl(apiUrl))
.mapRequest(ClientRequest.setHeaders({
"request-id": headers.flatMap((_) => _.get("request-id")).value ?? StringId.make(),
...headers.map((_) => Object.fromEntries(_)).value
}))
.tapRequest((r) =>
Effect
.logDebug(`[HTTP] ${r.method}`)
.annotateLogs("url", r.url)
.annotateLogs("body", r.body._tag === "Uint8Array" ? new TextDecoder().decode(r.body.body) : r.body._tag)
.annotateLogs("headers", r.headers)
)
.mapEffect((_) => _.json.map((body) => ({ status: _.status, body, headers: _.headers })))
.catchTags({
"ResponseError": (err) =>
err
.response
.text
// TODO
.orDie
.flatMap((_) =>
Effect.fail({
_tag: "HttpErrorResponse" as const,
response: { body: Option.fromNullable(_), status: err.response.status, headers: err.response.headers }
} as HttpClientLegacy.HttpResponseError<unknown>)
),
"RequestError": (err) =>
Effect.fail({ _tag: "HttpErrorRequest", error: err.error } as HttpClientLegacy.HttpRequestError)
})
)
)

export function fetchApi(
method: HttpClientLegacy.Method,
path: string,
body?: unknown
) {
return getClient
.flatMap((client) => {
const req = method === "DELETE"
? ClientRequest.del
: method === "GET"
? ClientRequest.get
: method === "POST"
? ClientRequest.post
: method === "PUT"
? ClientRequest.put
: ClientRequest.patch

return client(req(path).unsafeJsonBody(body))
.map((x) => ({ ...x, body: x.body ?? null }))
})
}

export function fetchApi2S<RequestA, RequestE, ResponseA>(
encodeRequest: (a: RequestA) => RequestE,
decodeResponse: (u: unknown) => Effect<never, unknown, ResponseA>
) {
const decodeRes = (u: unknown) => decodeResponse(u).mapError((err) => new ResponseError(err))
return (method: HttpClient.Method, path: Path) => (req: RequestA) =>
return (method: HttpClientLegacy.Method, path: Path) => (req: RequestA) =>
fetchApi(
method,
method === "DELETE"
Expand Down Expand Up @@ -132,7 +181,7 @@ export function mapResponseM<T, R, E, A>(map: (t: T) => Effect<R, E, A>) {
})
}
}
export type FetchResponse<T> = { body: T; headers: HttpClient.Headers; status: number }
export type FetchResponse<T> = { body: T; headers: HttpClientLegacy.Headers; status: number }

export const EmptyResponse = Object.freeze({ body: null, headers: {}, status: 404 })
export const EmptyResponseM = Effect(EmptyResponse)
Expand Down
5 changes: 3 additions & 2 deletions packages/vue/_src/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { Http } from "@effect-app/core/http/http-client"
import { ApiConfig } from "@effect-app/prelude/client"
import { fetch } from "cross-fetch"
import * as Scope from "effect/Scope"
import { initRuntime } from "./internal.js"

import * as HttpClientBrowser from "@effect/platform-browser/HttpClient"

export { initRuntime } from "./internal.js"

const DefaultApiConfig = Config.all({
Expand All @@ -15,7 +16,7 @@ const DefaultApiConfig = Config.all({
})

export function makeApiLayers(config: Config<ApiConfig> = DefaultApiConfig) {
return HttpClientFetch.Client(fetch) + ApiConfig.Live(config)
return HttpClientBrowser.client.layer + ApiConfig.Live(config)
}

export function makeAppRuntime<R, E, A>(layer: Layer<R, E, A>) {
Expand Down
3 changes: 2 additions & 1 deletion packages/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
"license": "MIT",
"type": "module",
"dependencies": {
"@effect/platform-browser": "^0.12.0",
"@effect-app/prelude": "workspace:*",
"@effect-app/vue": "workspace:*",
"@effect-app/core": "workspace:*",
"@effect-app/schema": "workspace:*",
"effect": "^2.0.0-next.50",
"@fp-ts/optic": "^0.13.0",
"@formatjs/intl": "^2.9.4",
"effect": "^2.0.0-next.50",
"query-string": "^8.1.0",
"swrv": "^1.0.4",
"vue": "^3.3.6"
Expand Down
14 changes: 14 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 51b546c

Please sign in to comment.