openapi-ff 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -3
- package/dist/openapi-ff.cjs +1 -1
- package/dist/openapi-ff.d.cts +12 -1
- package/dist/openapi-ff.d.ts +12 -1
- package/dist/openapi-ff.js +47 -38
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -58,6 +58,7 @@ Advanced Usage:
|
|
|
58
58
|
```ts
|
|
59
59
|
import { chainRoute } from "atomic-router";
|
|
60
60
|
import { startChain } from "@farfetched/atomic-router";
|
|
61
|
+
import { isApiError } from "openapi-ff";
|
|
61
62
|
|
|
62
63
|
const getBlogpostFx = createApiEffect("get", "/blogposts/{post_id}", {
|
|
63
64
|
mapParams: (args: { postId: string }) => ({ params: { path: { post_id: args.postId } } }),
|
|
@@ -85,14 +86,52 @@ const apiError = sample({
|
|
|
85
86
|
|
|
86
87
|
> openapi-typescript by its design generates runtime-free static types, and only static types.
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
However, `openapi-ff` allows adding a contract factory when creating a client and provides a corresponding method, `createApiEffectWithContract`:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const { createApiEffectWithContract } = createClient(fetchClient, {
|
|
93
|
+
createContract(method, path) {
|
|
94
|
+
// ... create your own contract
|
|
95
|
+
return contract; // Contract<unknown, unknown>
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const query = createQuery({
|
|
100
|
+
...createApiEffectWithContract("get", "/blogposts"),
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### [typed-openapi](https://github.com/astahmer/typed-openapi) example
|
|
89
105
|
|
|
90
106
|
```bash
|
|
107
|
+
npx typed-openapi path/to/api.yaml -o src/zod.ts -r zod # Generate zod schemas
|
|
91
108
|
pnpm install zod @farfetched/zod
|
|
92
|
-
npx orval --input path/to/api.yaml --output src/zod.ts --client zod --mode single
|
|
93
109
|
```
|
|
94
110
|
|
|
95
|
-
|
|
111
|
+
```ts
|
|
112
|
+
import { EndpointByMethod } from "./zod";
|
|
113
|
+
import { zodContract } from "@farfetched/zod";
|
|
114
|
+
|
|
115
|
+
const { createApiEffectWithContract } = createClient(fetchClient, {
|
|
116
|
+
createContract(method, path) {
|
|
117
|
+
const { response } = (EndpointByMethod as any)[method][path];
|
|
118
|
+
return zodContract(response);
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const query = createQuery({
|
|
123
|
+
...createApiEffectWithContract("get", "/blogposts"),
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### [orval](https://orval.dev/) example
|
|
128
|
+
|
|
129
|
+
Alternatively, you can simply add any contract to a query:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pnpm install zod @farfetched/zod
|
|
133
|
+
npx orval --input path/to/api.yaml --output src/zod.ts --client zod --mode single
|
|
134
|
+
```
|
|
96
135
|
|
|
97
136
|
```ts
|
|
98
137
|
import { zodContract } from "@farfetched/zod";
|
package/dist/openapi-ff.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("effector"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("effector"),l=require("@farfetched/core"),h="API";function C(t){return{...t,errorType:h,explanation:"Request was finished with unsuccessful HTTP code"}}function A(t){var e;return((e=t.error)==null?void 0:e.errorType)===h}function g(t,e={}){const u=(s,a,r)=>{const w=s.toUpperCase(),E=t[w];return p.createEffect(async i=>{var f;const{data:T,error:o,response:n}=await E(a,((f=r==null?void 0:r.mapParams)==null?void 0:f.call(r,i))??i).catch(c=>{throw l.networkError({reason:(c==null?void 0:c.message)??null,cause:c})});if(o!=null&&o!=="")throw C({status:n.status,statusText:n.statusText,response:o});if(!n.ok)throw l.httpError({status:n.status,statusText:n.statusText,response:null});return T})};return{createApiEffect:u,createApiEffectWithContract:(s,a,r)=>{if(e.createContract==null)throw new Error("'createContract' is missing in config");return{effect:u(s,a,r),contract:e.createContract(s,a.toString())}}}}exports.createClient=g;exports.isApiError=A;
|
package/dist/openapi-ff.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Client } from 'openapi-fetch';
|
|
2
|
+
import { Contract } from '@farfetched/core';
|
|
2
3
|
import { Effect } from 'effector';
|
|
3
4
|
import { FarfetchedError } from '@farfetched/core';
|
|
4
5
|
import { FetchResponse } from 'openapi-fetch';
|
|
@@ -23,7 +24,16 @@ declare type CreateApiEffectOptions<Init> = {
|
|
|
23
24
|
mapParams?: (init: any) => Init;
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
declare type CreateApiEffectWithContract<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<Paths[Path][Method], Init, Media>>, Options extends CreateApiEffectOptions<Init> = {}>(method: Method, path: Path, options?: Options) => {
|
|
28
|
+
effect: Effect<Init extends undefined ? void : InitOrPrependInit<Init, Parameters<NonNullable<Options["mapParams"]>>[0], Options>, Response["data"], ApiError<number, Response["error"]> | HttpError | NetworkError>;
|
|
29
|
+
contract: Contract<unknown, Response["data"]>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export declare function createClient<Paths extends {}, Media extends MediaType = MediaType>(client: Client<Paths, Media>, config?: EffectorClientOptions): OpenapiEffectorClient<Paths, Media>;
|
|
33
|
+
|
|
34
|
+
declare type EffectorClientOptions = {
|
|
35
|
+
createContract?: (method: HttpMethod, path: string) => Contract<unknown, unknown>;
|
|
36
|
+
};
|
|
27
37
|
|
|
28
38
|
declare type InitOrPrependInit<Init, PrependInit, Options extends CreateApiEffectOptions<Init>> = Options extends {
|
|
29
39
|
mapParams: (init: any) => any;
|
|
@@ -33,6 +43,7 @@ export declare function isApiError(args: WithError): args is WithError<ApiError>
|
|
|
33
43
|
|
|
34
44
|
declare interface OpenapiEffectorClient<Paths extends {}, Media extends MediaType = MediaType> {
|
|
35
45
|
createApiEffect: CreateApiEffect<Paths, Media>;
|
|
46
|
+
createApiEffectWithContract: CreateApiEffectWithContract<Paths, Media>;
|
|
36
47
|
}
|
|
37
48
|
|
|
38
49
|
declare type WithError<T = any, P = Record<string, unknown>> = P & {
|
package/dist/openapi-ff.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Client } from 'openapi-fetch';
|
|
2
|
+
import { Contract } from '@farfetched/core';
|
|
2
3
|
import { Effect } from 'effector';
|
|
3
4
|
import { FarfetchedError } from '@farfetched/core';
|
|
4
5
|
import { FetchResponse } from 'openapi-fetch';
|
|
@@ -23,7 +24,16 @@ declare type CreateApiEffectOptions<Init> = {
|
|
|
23
24
|
mapParams?: (init: any) => Init;
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
declare type CreateApiEffectWithContract<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<Paths[Path][Method], Init, Media>>, Options extends CreateApiEffectOptions<Init> = {}>(method: Method, path: Path, options?: Options) => {
|
|
28
|
+
effect: Effect<Init extends undefined ? void : InitOrPrependInit<Init, Parameters<NonNullable<Options["mapParams"]>>[0], Options>, Response["data"], ApiError<number, Response["error"]> | HttpError | NetworkError>;
|
|
29
|
+
contract: Contract<unknown, Response["data"]>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export declare function createClient<Paths extends {}, Media extends MediaType = MediaType>(client: Client<Paths, Media>, config?: EffectorClientOptions): OpenapiEffectorClient<Paths, Media>;
|
|
33
|
+
|
|
34
|
+
declare type EffectorClientOptions = {
|
|
35
|
+
createContract?: (method: HttpMethod, path: string) => Contract<unknown, unknown>;
|
|
36
|
+
};
|
|
27
37
|
|
|
28
38
|
declare type InitOrPrependInit<Init, PrependInit, Options extends CreateApiEffectOptions<Init>> = Options extends {
|
|
29
39
|
mapParams: (init: any) => any;
|
|
@@ -33,6 +43,7 @@ export declare function isApiError(args: WithError): args is WithError<ApiError>
|
|
|
33
43
|
|
|
34
44
|
declare interface OpenapiEffectorClient<Paths extends {}, Media extends MediaType = MediaType> {
|
|
35
45
|
createApiEffect: CreateApiEffect<Paths, Media>;
|
|
46
|
+
createApiEffectWithContract: CreateApiEffectWithContract<Paths, Media>;
|
|
36
47
|
}
|
|
37
48
|
|
|
38
49
|
declare type WithError<T = any, P = Record<string, unknown>> = P & {
|
package/dist/openapi-ff.js
CHANGED
|
@@ -1,50 +1,59 @@
|
|
|
1
|
-
import { createEffect as
|
|
2
|
-
import { networkError as
|
|
3
|
-
const
|
|
4
|
-
function
|
|
1
|
+
import { createEffect as m } from "effector";
|
|
2
|
+
import { networkError as E, httpError as T } from "@farfetched/core";
|
|
3
|
+
const l = "API";
|
|
4
|
+
function x(t) {
|
|
5
5
|
return {
|
|
6
|
-
...
|
|
7
|
-
errorType:
|
|
6
|
+
...t,
|
|
7
|
+
errorType: l,
|
|
8
8
|
explanation: "Request was finished with unsuccessful HTTP code"
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
var
|
|
13
|
-
return ((
|
|
11
|
+
function P(t) {
|
|
12
|
+
var e;
|
|
13
|
+
return ((e = t.error) == null ? void 0 : e.errorType) === l;
|
|
14
14
|
}
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
cause: a
|
|
28
|
-
});
|
|
15
|
+
function g(t, e = {}) {
|
|
16
|
+
const f = (a, s, r) => {
|
|
17
|
+
const h = a.toUpperCase(), p = t[h];
|
|
18
|
+
return m(async (u) => {
|
|
19
|
+
var i;
|
|
20
|
+
const { data: w, error: o, response: n } = await p(
|
|
21
|
+
s,
|
|
22
|
+
((i = r == null ? void 0 : r.mapParams) == null ? void 0 : i.call(r, u)) ?? u
|
|
23
|
+
).catch((c) => {
|
|
24
|
+
throw E({
|
|
25
|
+
reason: (c == null ? void 0 : c.message) ?? null,
|
|
26
|
+
cause: c
|
|
29
27
|
});
|
|
30
|
-
if (n != null && n !== "")
|
|
31
|
-
throw w({
|
|
32
|
-
status: e.status,
|
|
33
|
-
statusText: e.statusText,
|
|
34
|
-
response: n
|
|
35
|
-
});
|
|
36
|
-
if (!e.ok)
|
|
37
|
-
throw i({
|
|
38
|
-
status: e.status,
|
|
39
|
-
statusText: e.statusText,
|
|
40
|
-
response: null
|
|
41
|
-
});
|
|
42
|
-
return m;
|
|
43
28
|
});
|
|
29
|
+
if (o != null && o !== "")
|
|
30
|
+
throw x({
|
|
31
|
+
status: n.status,
|
|
32
|
+
statusText: n.statusText,
|
|
33
|
+
response: o
|
|
34
|
+
});
|
|
35
|
+
if (!n.ok)
|
|
36
|
+
throw T({
|
|
37
|
+
status: n.status,
|
|
38
|
+
statusText: n.statusText,
|
|
39
|
+
response: null
|
|
40
|
+
});
|
|
41
|
+
return w;
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
createApiEffect: f,
|
|
46
|
+
createApiEffectWithContract: (a, s, r) => {
|
|
47
|
+
if (e.createContract == null)
|
|
48
|
+
throw new Error("'createContract' is missing in config");
|
|
49
|
+
return {
|
|
50
|
+
effect: f(a, s, r),
|
|
51
|
+
contract: e.createContract(a, s.toString())
|
|
52
|
+
};
|
|
44
53
|
}
|
|
45
54
|
};
|
|
46
55
|
}
|
|
47
56
|
export {
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
g as createClient,
|
|
58
|
+
P as isApiError
|
|
50
59
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openapi-ff",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "vitest run --typecheck",
|
|
@@ -29,13 +29,15 @@
|
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@biomejs/biome": "^1.9.4",
|
|
32
|
+
"@farfetched/zod": "^0.12.8",
|
|
32
33
|
"@types/node": "^20.12.7",
|
|
33
34
|
"typescript": "5.1.6",
|
|
34
35
|
"undici": "^6.21.0",
|
|
35
36
|
"vite": "5",
|
|
36
37
|
"vite-plugin-dts": "^3.8.3",
|
|
37
38
|
"vite-tsconfig-paths": "4.2.1",
|
|
38
|
-
"vitest": "2.0.4"
|
|
39
|
+
"vitest": "2.0.4",
|
|
40
|
+
"zod": "^3.23.8"
|
|
39
41
|
},
|
|
40
42
|
"peerDependencies": {
|
|
41
43
|
"@farfetched/core": "^0.12.8",
|