Skip to content

Commit

Permalink
feat: move response to module type t style
Browse files Browse the repository at this point in the history
BREAKING CHANGE: use @send for response parsing
  • Loading branch information
DCKT committed May 13, 2024
1 parent bb8cbf6 commit cf71d8b
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 50 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ type errorPayload = {
let fetchSomething = async () => {
try {
let response: data = await Ky.fetch("test", {prefixUrl: "https://fake.com", method: GET}).json()
let response: data = await Ky.fetch("test", {prefixUrl: "https://fake.com", method: GET})->Ky.Response.json()
// handle response data
} catch {
| JsError(err) => {
let errorResponse = (err->Ky.unkownToError).response->Option.getExn
let errorData: errorPayload = await errorResponse.json()
let errorData: errorPayload = await errorResponse->Ky.Response.json()
switch (errorData.code) {
| "CODE_1" => () // do something
Expand All @@ -57,7 +57,7 @@ type data = {anything: string}
let fetchSomething = async () => {
try {
let response: data = await Ky.get("test", {prefixUrl: "https://fake.com"}).json()
let response: data = await Ky.get("test", {prefixUrl: "https://fake.com"})->Ky.Response.json()
// handle response data
} catch {
| JsError(err) => {
Expand All @@ -77,7 +77,7 @@ type data = {anything: string}
let fetchSomething = async () => {
try {
let response: data = await (instance->Ky.Instance.get("test")).json()
let response: data = await (instance->Ky.Instance.get("test"))->Ky.Response.json()
// handle response data
} catch {
| JsError(err) => {
Expand All @@ -103,7 +103,7 @@ type data = {anything: string}
let fetchSomething = async () => {
try {
let response: data = await (extendedInstance->Ky.Instance.get("test")).json()
let response: data = await (extendedInstance->Ky.Instance.get("test"))->Ky.Response.json()
// handle response data
} catch {
| JsError(err) => {
Expand Down
52 changes: 32 additions & 20 deletions src/Ky.res
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
module Request = {
type t
}
module Response = {
type t = {
status: int,
url: string,
ok: bool,
}

@send
external json: (t, unit) => promise<'data> = "json"
external text: (t, unit) => promise<'data> = "text"
}
type request
type response<'data> = {json: unit => promise<'data>, status: int, url: string, ok: bool}
type error<'data> = {response: option<response<'data>>, request: option<request>, name: string}
type error<'data> = {response: option<Response.t>, request: option<Request.t>, name: string}

module HttpMethod = {
type t =
Expand Down Expand Up @@ -42,13 +55,13 @@ type responseOptions

@unboxed
type afterResponseCallbackResponse<'data> =
| Sync(response<'data>)
| Async(promise<response<'data>>)
| Sync(Response.t)
| Async(promise<Response.t>)

type afterResponseCallback<'responseData> = (
request,
responseOptions,
response<'responseData>,
Response.t,
) => afterResponseCallbackResponse<'responseData>

type hooks<'errorData, 'responseData> = {
Expand Down Expand Up @@ -95,38 +108,38 @@ type requestOptions<'json, 'searchParams, 'errorData, 'responseData> = {
external fetch: (
string,
requestOptions<'json, 'searchParams, 'errorData, 'responseData>,
) => response<'data> = "default"
) => Response.t = "default"

@module("ky") @scope("default")
external get: (
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "get"
) => Response.t = "get"
@module("ky") @scope("default")
external post: (
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "post"
) => Response.t = "post"
@module("ky") @scope("default")
external put: (
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "put"
) => Response.t = "put"
@module("ky") @scope("default")
external patch: (
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "patch"
) => Response.t = "patch"
@module("ky") @scope("default")
external head: (
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "head"
) => Response.t = "head"
@module("ky") @scope("default")
external delete: (
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "delete"
) => Response.t = "delete"

module Instance = {
type t
Expand All @@ -137,8 +150,7 @@ module Instance = {
type callable<'json, 'searchParams, 'errorData, 'responseData> = (
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => t
@send external json: t => 'a = "json"
) => Response.t

external asCallable: t => callable<'json, 'searchParams, 'errorData, 'responseData> = "%identity"

Expand All @@ -147,37 +159,37 @@ module Instance = {
t,
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "get"
) => Response.t = "get"
@send
external post: (
t,
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "post"
) => Response.t = "post"
@send
external put: (
t,
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "put"
) => Response.t = "put"
@send
external patch: (
t,
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "patch"
) => Response.t = "patch"
@send
external head: (
t,
string,
~options: requestOptions<'json, 'searchParams, 'errorData, 'responseData>=?,
) => response<'data> = "head"
) => Response.t = "head"
@send
external delete: (
t,
string,
requestOptions<'json, 'searchParams, 'errorData, 'responseData>,
) => response<'data> = "delete"
) => Response.t = "delete"

@send
external extend: (t, requestOptions<'json, 'searchParams, 'errorData, 'responseData>) => t =
Expand Down
57 changes: 32 additions & 25 deletions tests/Ky_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,32 @@ let mockBasePath = `http://localhost:${port}`
type jsonMethod = {method: Ky.HttpMethod.t}
describe("HTTP methods imports", () => {
testAsync("GET", async () => {
let response: jsonMethod = await Ky.get("method", ~options={prefixUrl: mockBasePath}).json()
let response: jsonMethod =
await Ky.get("method", ~options={prefixUrl: mockBasePath})->Ky.Response.json()

expect(response.method)->Expect.toBe(GET)
})
testAsync("POST", async () => {
let response: jsonMethod = await Ky.post("method", ~options={prefixUrl: mockBasePath}).json()
let response: jsonMethod =
await Ky.post("method", ~options={prefixUrl: mockBasePath})->Ky.Response.json()

expect(response.method)->Expect.toBe(POST)
})
testAsync("PUT", async () => {
let response: jsonMethod = await Ky.put("method", ~options={prefixUrl: mockBasePath}).json()
let response: jsonMethod =
await Ky.put("method", ~options={prefixUrl: mockBasePath})->Ky.Response.json()

expect(response.method)->Expect.toBe(PUT)
})
testAsync("PATCH", async () => {
let response: jsonMethod = await Ky.patch("method", ~options={prefixUrl: mockBasePath}).json()
let response: jsonMethod =
await Ky.patch("method", ~options={prefixUrl: mockBasePath})->Ky.Response.json()

expect(response.method)->Expect.toBe(PATCH)
})
testAsync("DELETE", async () => {
let response: jsonMethod = await Ky.delete("method", ~options={prefixUrl: mockBasePath}).json()
let response: jsonMethod =
await Ky.delete("method", ~options={prefixUrl: mockBasePath})->Ky.Response.json()

expect(response.method)->Expect.toBe(DELETE)
})
Expand All @@ -97,7 +102,7 @@ describe("HTTP methods imports", () => {
type jsonData = {test: int, randomStr: string}
describe("Configuration", () => {
testAsync("Simple fetch", async () => {
let response = await Ky.fetch("", {prefixUrl: mockBasePath, method: GET}).json()
let response = await Ky.fetch("", {prefixUrl: mockBasePath, method: GET})->Ky.Response.json()

expect(response["test"])->Expect.toBe(1)
})
Expand All @@ -107,26 +112,28 @@ describe("Configuration", () => {
test: 1,
randomStr: "test",
}
let response: jsonData = await Ky.post(
"json",
~options={prefixUrl: mockBasePath, json: data},
).json()
let response: jsonData =
await Ky.post("json", ~options={prefixUrl: mockBasePath, json: data})->Ky.Response.json()

expect(response.test)->Expect.toBe(1)
})

testAsync("Custom retry", async () => {
let response = await Ky.fetch(
`retry`,
{prefixUrl: mockBasePath, method: GET, retry: Int(1)},
).json()
let response =
await Ky.fetch(
`retry`,
{prefixUrl: mockBasePath, method: GET, retry: Int(1)},
)->Ky.Response.json()

expect(response["retryCount"])->Expect.toBe(1)
})

testAsync("Custom timeout", async () => {
try {
await Ky.fetch(`timeout`, {prefixUrl: mockBasePath, method: GET, timeout: 100}).json()
await Ky.fetch(
`timeout`,
{prefixUrl: mockBasePath, method: GET, timeout: 100},
)->Ky.Response.json()
} catch {
| JsError(err) => {
let err: Ky.error<unit> = err->Obj.magic
Expand All @@ -141,29 +148,29 @@ describe("Instance", () => {

testAsync("fetch", async () => {
let response =
await Ky.Instance.asCallable(instance)("get", ~options={method: GET})->Ky.Instance.json
await (instance->Ky.Instance.asCallable)("get", ~options={method: GET})->Ky.Response.json()

expect(response["test"])->Expect.toBe(1)
})

testAsync("GET", async () => {
let response = await (instance->Ky.Instance.get("get")).json()
let response = await instance->Ky.Instance.get("get")->Ky.Response.json()

expect(response["test"])->Expect.toBe(1)
})

testAsync("POST", async () => {
let response = await (instance->Ky.Instance.post("post")).json()
let response = await instance->Ky.Instance.post("post")->Ky.Response.json()

expect(response["test"])->Expect.toBe(1)
})
testAsync("PUT", async () => {
let response = await (instance->Ky.Instance.put("put")).json()
let response = await instance->Ky.Instance.put("put")->Ky.Response.json()

expect(response["test"])->Expect.toBe(1)
})
testAsync("DELETE", async () => {
let response = await (instance->Ky.Instance.delete("delete", {})).json()
let response = await instance->Ky.Instance.delete("delete", {})->Ky.Response.json()

expect(response["test"])->Expect.toBe(1)
})
Expand All @@ -176,7 +183,7 @@ describe("Instance", () => {
}),
})

let response = await (extendedInstance->Ky.Instance.get("test")).json()
let response = await extendedInstance->Ky.Instance.get("test")->Ky.Response.json()

expect(response["test"])->Expect.toBe(1)
})
Expand All @@ -188,14 +195,14 @@ describe("Hooks", () => {
hooks: {
afterResponse: [
(_request, _responseOptions, _response) => {
Ky.Async(Ky.get("afterResponse", ~options={prefixUrl: mockBasePath}).json())
Ky.Async(Ky.get("afterResponse", ~options={prefixUrl: mockBasePath})->Ky.Response.json())
},
],
},
})

testAsync("Async", async () => {
let response = await (instance->Ky.Instance.get("")).json()
let response = await instance->Ky.Instance.get("")->Ky.Response.json()

expect(response["test"])->Expect.toBe(1)
expect((afterResponseMock->Obj.magic: string))->Expect.toHaveBeenCalled
Expand All @@ -206,11 +213,11 @@ type errorPayload = {code: string}
describe("Error handling", () => {
testAsync("Get code error from the payload", async () => {
try {
let _ = await Ky.get("error-code", ~options={prefixUrl: mockBasePath}).json()
let _ = await Ky.get("error-code", ~options={prefixUrl: mockBasePath})->Ky.Response.json()
} catch {
| JsError(err) => {
let errorResponse = (err->Ky.unkownToError).response->Option.getExn
let errorData: errorPayload = await errorResponse.json()
let errorData: errorPayload = await errorResponse->Ky.Response.json()

expect(errorData.code)->Expect.toBe("ERROR_CODE")
}
Expand Down

0 comments on commit cf71d8b

Please sign in to comment.