Skip to content

Commit fbcb065

Browse files
feat: init repo
1 parent 7328c2e commit fbcb065

File tree

9 files changed

+200
-9
lines changed

9 files changed

+200
-9
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ test/bundle/*.js
1919
test/bundle/*.js.gz
2020
promise-*
2121
_release
22+
23+
*.mjs

README.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,33 @@
1-
# rescript-bindings-template
1+
# rescript-ky
2+
3+
ReScript bindings for ky HTTP client
4+
5+
## Setup
6+
7+
1. Install the module
8+
9+
```bash
10+
bun install @dck/rescript-ky
11+
```
12+
13+
or
14+
15+
```bash
16+
yarn install @dck/rescript-ky
17+
```
18+
19+
or
20+
21+
```bash
22+
npm install @dck/rescript-ky
23+
```
24+
25+
2. Add it to your `rescript.json` config
26+
27+
```json
28+
{
29+
"bsc-flags": ["@dck/rescript-ky"]
30+
}
31+
```
32+
33+
## API

bun.lockb

22.3 KB
Binary file not shown.

package.json

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
{
2-
"name": "@dck/rescript-bindings-template",
2+
"name": "@dck/rescript-ky",
33
"version": "0.0.0",
4-
"description": "",
4+
"description": "ReScript bindings for ky HTTP client",
5+
"type": "module",
56
"keywords": [
67
"rescript",
7-
"bindings"
8+
"bindings",
9+
"ky"
810
],
911
"license": "MIT",
1012
"author": {
@@ -13,15 +15,19 @@
1315
"url": "https://github.com/DCKT"
1416
},
1517
"peerDependencies": {
16-
"rescript": ">=11.0.0"
18+
"rescript": ">=11.0.0",
19+
"ky": "~1.2.0"
1720
},
1821
"devDependencies": {
22+
"ky": "1.2.0",
23+
"nock": "13.5.1",
1924
"rescript": ">=11.0.0"
2025
},
2126
"scripts": {
2227
"build": "rescript build",
23-
"watch": "rescript build -w",
24-
"clean": "rescript clean"
28+
"dev": "rescript build -w",
29+
"clean": "rescript clean",
30+
"test": "rescript build && retest tests/**/*.mjs"
2531
},
2632
"files": [
2733
"src/*",

rescript.json

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,22 @@
22
"name": "@dck/rescript-bindings-template",
33
"uncurried": true,
44
"namespace": false,
5-
"sources": ["src/js"]
5+
"sources": [
6+
{
7+
"dir": "src",
8+
"subdirs": true
9+
},
10+
{
11+
"dir": "tests",
12+
"type": "dev",
13+
"subdirs": true
14+
}
15+
],
16+
"suffix": ".mjs",
17+
"package-specs": [
18+
{
19+
"module": "es6",
20+
"in-source": true
21+
}
22+
]
623
}

src/Bindings.res

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/Ky.res

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
type request
2+
type response<'data> = {json: unit => promise<'data>, status: int, url: string, ok: bool}
3+
type error<'data> = {response: option<response<'data>>, request: option<request>, name: string}
4+
5+
type httpMethod =
6+
| GET
7+
| POST
8+
| PUT
9+
| HEAD
10+
| DELETE
11+
| PATCH
12+
13+
type retryMethod =
14+
| GET
15+
| PUT
16+
| HEAD
17+
| DELETE
18+
| OPTIONS
19+
| TRACE
20+
21+
type retryOptions = {
22+
limit?: int,
23+
methods?: array<retryMethod>,
24+
statusCodes?: array<int>,
25+
backoffLimit?: int,
26+
delay?: int => float,
27+
}
28+
29+
type retryCallbackParams = {
30+
request: request,
31+
retryCount: int,
32+
}
33+
34+
type beforeRequestCallback = request => unit
35+
type beforeRetryCallback = retryCallbackParams => unit
36+
type beforeErrorCallback<'data> = error<'data> => unit
37+
38+
type hooks<'errorData> = {
39+
beforeRequest?: array<beforeRequestCallback>,
40+
beforeRetry?: array<beforeRetryCallback>,
41+
beforeError?: array<beforeErrorCallback<'errorData>>,
42+
}
43+
44+
@unboxed
45+
type retry =
46+
| Int(int)
47+
| Options(retryOptions)
48+
49+
type requestOptions<'json, 'searchParams, 'errorData> = {
50+
prefixUrl?: string,
51+
method?: httpMethod,
52+
json?: 'json,
53+
searchParams?: 'searchParams,
54+
retry?: retry,
55+
timeout?: int,
56+
hooks?: hooks<'errorData>,
57+
}
58+
59+
@module("ky")
60+
external fetch: (string, requestOptions<'json, 'searchParams, 'errorData>) => response<'data> =
61+
"default"

tests/Simple_test.res

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
type expect<'a> = {toBe: 'a}
2+
@module("bun:test")
3+
external expect: 'a => expect<'b> = "expect"
4+
@module("bun:test")
5+
external test: (string, unit => unit) => unit = "test"
6+
@module("bun:test")
7+
external testAsync: (string, unit => promise<unit>) => unit = "test"
8+
9+
type mock = {
10+
mockInstance: unit => unit,
11+
path: string,
12+
}
13+
14+
@module("./mock.ts")
15+
external mockBasePath: string = "mockBasePath"
16+
17+
@module("./mock.ts")
18+
external initMockServer: unit => unit = "initMockServer"
19+
20+
initMockServer()
21+
22+
testAsync("Simple fetch", async () => {
23+
let response = await Ky.fetch("", {prefixUrl: mockBasePath, method: GET}).json()
24+
25+
expect(response["test"]).toBe(1)
26+
})
27+
28+
testAsync("Custom retry", async () => {
29+
let response = await Ky.fetch(
30+
`retry`,
31+
{prefixUrl: mockBasePath, method: GET, retry: Int(1)},
32+
).json()
33+
34+
expect(response["retryCount"]).toBe(1)
35+
})
36+
37+
testAsync("Custom timeout", async () => {
38+
try {
39+
await Ky.fetch(`timeout`, {prefixUrl: mockBasePath, method: GET, timeout: 100}).json()
40+
} catch {
41+
| JsError(err) => {
42+
let err: Ky.error<unit> = err->Obj.magic
43+
expect(err.name).toBe("TimeoutError")
44+
}
45+
}
46+
})

tests/mock.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export const mockBasePath = "http://localhost:3000";
2+
3+
let retry = 0;
4+
5+
function wait(ms) {
6+
return new Promise((resolve) => setTimeout(resolve, ms));
7+
}
8+
9+
export const initMockServer = () =>
10+
Bun.serve({
11+
async fetch(req) {
12+
const url = new URL(req.url);
13+
if (url.pathname === "/") return Response.json({ test: 1 });
14+
if (url.pathname === "/timeout") {
15+
await wait(2000);
16+
return Response.json({ test: 1 });
17+
}
18+
if (url.pathname === "/retry") {
19+
if (retry === 0) {
20+
retry = retry + 1;
21+
return new Response("busy !", { status: 429 });
22+
} else {
23+
return Response.json({ retryCount: retry });
24+
}
25+
}
26+
return new Response("404!", { status: 404 });
27+
},
28+
});

0 commit comments

Comments
 (0)