oazapfts 4.3.3 → 4.4.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.
Files changed (45) hide show
  1. package/README.md +93 -32
  2. package/lib/codegen/generate.d.ts +13 -11
  3. package/lib/codegen/generate.js +130 -70
  4. package/lib/codegen/generate.js.map +1 -1
  5. package/lib/codegen/generate.test.js +17 -126
  6. package/lib/codegen/generate.test.js.map +1 -1
  7. package/lib/codegen/generateServers.js +10 -28
  8. package/lib/codegen/generateServers.js.map +1 -1
  9. package/lib/codegen/index.d.ts +6 -2
  10. package/lib/codegen/index.js +29 -16
  11. package/lib/codegen/index.js.map +1 -1
  12. package/lib/codegen/index.test.d.ts +1 -0
  13. package/lib/codegen/index.test.js +115 -0
  14. package/lib/codegen/index.test.js.map +1 -0
  15. package/lib/codegen/tscodegen.d.ts +12 -3
  16. package/lib/codegen/tscodegen.js +25 -22
  17. package/lib/codegen/tscodegen.js.map +1 -1
  18. package/lib/index.d.ts +3 -2
  19. package/lib/index.js.map +1 -1
  20. package/lib/runtime/index.d.ts +9 -5
  21. package/lib/runtime/index.js +10 -13
  22. package/lib/runtime/index.js.map +1 -1
  23. package/lib/runtime/query.d.ts +1 -0
  24. package/lib/runtime/query.js +12 -1
  25. package/lib/runtime/query.js.map +1 -1
  26. package/package.json +2 -2
  27. package/src/codegen/__fixtures__/allOf.json +80 -0
  28. package/src/codegen/__fixtures__/binary.json +43 -0
  29. package/src/codegen/__fixtures__/const.json +64 -0
  30. package/src/codegen/__fixtures__/contentParams.json +56 -0
  31. package/src/codegen/__fixtures__/duplicateIdentifiers.yaml +27 -0
  32. package/src/codegen/__fixtures__/geojson.json +83 -0
  33. package/src/codegen/__fixtures__/integer.yaml +1 -0
  34. package/src/codegen/__fixtures__/invalidIdentifiers.yaml +24 -0
  35. package/src/codegen/__fixtures__/oneOfRef.yaml +24 -0
  36. package/src/codegen/__fixtures__/string.yaml +1 -0
  37. package/src/codegen/generate.test.ts +17 -141
  38. package/src/codegen/generate.ts +155 -89
  39. package/src/codegen/generateServers.ts +19 -42
  40. package/src/codegen/index.test.ts +118 -0
  41. package/src/codegen/index.ts +27 -15
  42. package/src/codegen/tscodegen.ts +29 -37
  43. package/src/index.ts +6 -2
  44. package/src/runtime/index.ts +14 -15
  45. package/src/runtime/query.ts +14 -0
package/README.md CHANGED
@@ -4,13 +4,16 @@
4
4
 
5
5
  Generate TypeScript clients to tap into OpenAPI servers.
6
6
 
7
+ ![](https://avatars.githubusercontent.com/u/119607625?s=200&v=4)
8
+
7
9
  ## Features
8
10
 
9
11
  - **AST-based**:
10
12
  Unlike other code generators `oazapfts` does not use templates to generate code but uses TypeScript's built-in API to generate and pretty-print an abstract syntax tree.
11
- - **Fast**: The cli does not use any of the common Java-based tooling, so the code generation is super fast.
13
+ - **Fast**: The CLI does not use any of the common Java-based tooling, so the code generation is super fast.
14
+ - **Single file**: All functions and types are co-located in one single self-contained file.
12
15
  - **Tree-shakeable**: Individually exported functions allow you to bundle only the ones you actually use.
13
- - **Human friendly signatures**: The generated api methods don't leak an HTTP-specific implementation details. For example, all optional parameters are grouped together in one object, no matter whether they end up in the headers, path or query-string.
16
+ - **Human friendly signatures**: The generated API methods don't leak any HTTP-specific implementation details. For example, all optional parameters are grouped together in one object, no matter whether they end up in the headers, path or query-string.
14
17
 
15
18
  ## Installation
16
19
 
@@ -18,7 +21,8 @@ Generate TypeScript clients to tap into OpenAPI servers.
18
21
  npm install oazapfts
19
22
  ```
20
23
 
21
- **NOTE:** With version 3.0.0 oazapfts has become a runtime dependency and the generated code does no longer include all the fetch logic.
24
+ > **Note**
25
+ > With version 3.0.0 oazapfts has become a runtime dependency and the generated code does no longer include all the fetch logic.
22
26
 
23
27
  ## Usage
24
28
 
@@ -36,36 +40,64 @@ Where `<spec>` is the URL or local path of an OpenAPI or Swagger spec (in either
36
40
 
37
41
  Use the `useEnumType` option to generate typescript enums instead of union of values.
38
42
 
39
- ## Overriding the defaults
43
+ ## Consuming the generated API
40
44
 
41
- The generated file exports a `defaults` constant that can be used to override the `basePath`, provide a custom `fetch` implementation or to send additional headers with each request:
45
+ For each operation defined in the spec the generated API will export a function with a name matching the `operationId`. If no ID is specified, a reasonable name is generated from the HTTP verb and the path.
42
46
 
43
47
  ```ts
44
- import * as api from "./api.ts";
45
- import nodeFetch from "node-fetch";
48
+ import * as api from "./my-generated-api.ts";
49
+ const res = api.getPetById(1);
50
+ ```
46
51
 
47
- api.default.basePath = "https://example.com/api";
52
+ > **Note**
53
+ > If your API is large, and you want to take advantage of tree-shaking to exclude unused code, use individual named imports instead:
48
54
 
49
- api.defaults.headers = {
50
- access_token: "secret",
51
- };
55
+ ```ts
56
+ import { getPetById } from "./my-generated-api.ts";
57
+ ```
52
58
 
53
- api.defaults.fetch = nodeFetch;
59
+ ## Fetch options
60
+
61
+ The **last argument** of each function is an optional [`RequestOpts`](https://github.com/oazapfts/oazapfts/blob/27b296c6fc28fec4869f1b7e1a4a5585ebbd5ee9/src/runtime/index.ts#L5) object that can be used to pass options to the `fetch` call, for example to pass additional `headers` or an `AbortSignal` to cancel the request later on.
62
+
63
+ ```ts
64
+ const res = getPetById(1, {
65
+ credentials: "include",
66
+ headers: {
67
+ Authorization: `Bearer ${token}`,
68
+ },
69
+ });
54
70
  ```
55
71
 
56
- ## Consuming the generated API
72
+ You can also use this to override the default `baseUrl` or to provide a custom `fetch` implementation.
73
+
74
+ > **Note**
75
+ > Instead of passing custom options to each function call, consider [overwriting the global defaults](#overriding-the-defaults).
76
+
77
+ ## Optimistic vs. explicit responses
78
+
79
+ Oazapfts supports two different modes to handle results,
80
+ an [explicit](#explicit-mode) mode (the default) and an [optimistic](#optimistic-mode) mode, that makes the response handling less verbose.
81
+
82
+ ## Explicit mode
83
+
84
+ By default, each function returns an `ApiResponse` object that exposes the `status` code, response `headers` and the `data`.
57
85
 
58
- For each operation defined in the spec the generated API will export a function with a name matching the `operationId`. If no id is specified, a reasonable name is generated from the HTTP verb and the path.
86
+ > **Note**
87
+ > This mode is best suited for APIs that return different types for different response codes or APIs where you need to access not only the response body, but also the response headers. If your API is simple, and you don't need this flexibility, consider using the [optimistic mode](#optimistic-mode) instead.
59
88
 
60
- The **last argument** of each function is an optional `RequestOpts` object that can be used to pass options to the `fetch` call, for example to pass additional headers or an `AbortSignal` to cancel the request later on.
89
+ In explicit mode, each function returns a Promise for an `ApiResponse` which is an object with a `status` and a `data` property, holding the HTTP status code and the properly typed data from the response body.
61
90
 
62
- Each function **returns** a Promise for an `ApiResponse` which is an object with a `status` and a `data` property, holding the HTTP status code and the properly typed data from the response body. Since an operation can return different types depending on the status code, the actual return type is a _union_ of all possible responses, discriminated by their status.
91
+ Since an operation can return different types depending on the status code, the actual return type is a _union_ of all possible responses, discriminated by their status.
63
92
 
64
93
  Consider the following code generated from the `petstore.json` example:
65
94
 
66
95
  ```ts
67
- export function getPetById(petId: number, opts?: RequestOpts) {
68
- return fetchJson<
96
+ /**
97
+ * Find pet by ID
98
+ */
99
+ export function getPetById(petId: number, opts?: Oazapfts.RequestOpts) {
100
+ return oazapfts.fetchJson<
69
101
  | {
70
102
  status: 200;
71
103
  data: Pet;
@@ -76,15 +108,14 @@ export function getPetById(petId: number, opts?: RequestOpts) {
76
108
  }
77
109
  | {
78
110
  status: 404;
79
- data: string;
80
111
  }
81
- >(`/pet/${petId}`, {
112
+ >(`/pet/${encodeURIComponent(petId)}`, {
82
113
  ...opts,
83
114
  });
84
115
  }
85
116
  ```
86
117
 
87
- In this case the `data` property is typed as `Pet|string`. We can use a type guard to narrow down the type to `Pet`:
118
+ In this case, the `data` property is typed as `Pet|string`. We can use a type guard to narrow down the type to `Pet`:
88
119
 
89
120
  ```ts
90
121
  const res = await api.getPetById(1);
@@ -115,7 +146,7 @@ await handle(api.getPetById(1), {
115
146
  });
116
147
  ```
117
148
 
118
- The helper will throw an `HttpError` error for any unhanled status code unless you add a `default` handler:
149
+ The helper will throw an `HttpError` error for any unhandled status code, unless you add a `default` handler:
119
150
 
120
151
  ```ts
121
152
  await handle(api.getPetById(1), {
@@ -128,9 +159,26 @@ await handle(api.getPetById(1), {
128
159
  });
129
160
  ```
130
161
 
131
- ## Optimistic APIs
162
+ ## Optimistic mode
163
+
164
+ You can opt into the _optimistic mode_ by using the `--optimistic` command line argument.
165
+
166
+ In this mode, each function will return a Promise for the happy path, i.e. the type specified for the first `2xx` response.
167
+
168
+ Looking back at our Pet Store example from above, consuming the response is now much easier and less verbose:
169
+
170
+ ```ts
171
+ const pet = await api.getPetById(1);
172
+ // pet is now typed as Pet!
173
+ ```
174
+
175
+ In case of a response other than `200` the promise will be rejected with a `HttpError`.
132
176
 
133
- Instead of handling errors right in place we can also use the `ok` helper:
177
+ ## Mixing both modes
178
+
179
+ Sometimes you might want to use the optimistic mode for some of your API calls, but need the full `ApiResponse` for others.
180
+
181
+ In that case, you can use the `ok`-helper function to selectively apply optimistic response handling:
134
182
 
135
183
  ```ts
136
184
  import { ok } from "oazapfts";
@@ -138,21 +186,34 @@ import { ok } from "oazapfts";
138
186
  const pet = await ok(api.getPetById(1));
139
187
  ```
140
188
 
141
- With this pattern `pet` will be typed as `Pet` and a `HttpError` will be thrown in case of an error.
189
+ ## Overriding the defaults
142
190
 
143
- You can even turn your whole API into an optimistic one:
191
+ The generated file exports a `defaults` constant that can be used to override the `basePath`, provide a custom `fetch` implementation or to send additional `headers` with each request. Basically, you can set a default for any [fetch option](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) you want.
144
192
 
145
193
  ```ts
146
- import { optimistic } from "oazapfts";
147
- import * as rawApi from "./api.ts";
194
+ import * as api from "./api.ts";
195
+ import nodeFetch from "node-fetch";
148
196
 
149
- const api = optimistic(rawApi);
150
- const pet = await api.getPetById(1);
197
+ // Override the spec's basePath
198
+ api.defaults.basePath = "https://example.com/api";
199
+
200
+ // Send this header with each request
201
+ api.defaults.headers = {
202
+ access_token: "secret",
203
+ };
204
+
205
+ // Include credentials in CORS requests, too
206
+ api.defaults.credentials = "include";
207
+
208
+ // Use this instead of the global fetch
209
+ api.defaults.fetch = nodeFetch;
151
210
  ```
152
211
 
153
- ### CLI
212
+ ## Alternatives and integrations
213
+
214
+ If this library doesn't fit your needs, take a look at [openapi-typescript-codegen](https://github.com/ferdikoomen/openapi-typescript-codegen) which follows a similar philosophy but creates many individual files instead of one single self-contained file.
154
215
 
155
- Since version 3.1.0 you can also use the `--optimistic` flag on the command line to generate an optimistic API by default.
216
+ If your frontend uses React, take a look at [react-api-query](https://www.npmjs.com/package/react-api-query) which makes it easy to use an oazapfts client with React hooks in a convenient and type-safe way.
156
217
 
157
218
  ## About the name
158
219
 
@@ -3,27 +3,29 @@ import { OpenAPIV3 } from "openapi-types";
3
3
  import { Opts } from ".";
4
4
  export declare const verbs: string[];
5
5
  type ContentType = "json" | "form" | "multipart";
6
- export declare const contentTypes: Record<string, ContentType>;
6
+ export declare function isMimeType(s: unknown): boolean;
7
+ export declare function isJsonMimeType(mime: string): boolean;
8
+ export declare function getBodyFormatter(body?: OpenAPIV3.RequestBodyObject): ContentType | undefined;
7
9
  type SchemaObject = OpenAPIV3.SchemaObject & {
8
10
  const?: unknown;
9
11
  };
10
12
  /**
11
13
  * Get the name of a formatter function for a given parameter.
12
14
  */
13
- export declare function getFormatter({ style, explode, }: OpenAPIV3.ParameterObject): "form" | "deep" | "explode" | "space" | "pipe";
15
+ export declare function getFormatter({ style, explode, content, }: OpenAPIV3.ParameterObject): "json" | "form" | "deep" | "explode" | "space" | "pipe";
14
16
  export declare function getOperationIdentifier(id?: string): string | undefined;
15
17
  /**
16
18
  * Create a method name for a given operation, either from its operationId or
17
19
  * the HTTP verb and path.
18
20
  */
19
21
  export declare function getOperationName(verb: string, path: string, operationId?: string): string;
20
- export declare function isNullable(schema: any): boolean;
21
- export declare function isReference(obj: any): obj is OpenAPIV3.ReferenceObject;
22
- export declare function getReference(spec: any, ref: string): any;
22
+ export declare function isNullable(schema?: SchemaObject | OpenAPIV3.ReferenceObject): boolean | undefined;
23
+ export declare function isReference(obj: unknown): obj is OpenAPIV3.ReferenceObject;
23
24
  /**
24
25
  * If the given object is a ReferenceObject, return the last part of its path.
25
26
  */
26
- export declare function getReferenceName(obj: any): string | undefined;
27
+ export declare function getReferenceName(obj: unknown): string | undefined;
28
+ export declare function toIdentifier(s: string): string;
27
29
  /**
28
30
  * Create a template string literal from the given OpenAPI urlTemplate.
29
31
  * Curly braces in the path are turned into identifier expressions,
@@ -69,12 +71,11 @@ export default class ApiGenerator {
69
71
  skip(tags?: string[]): boolean;
70
72
  getUniqueAlias(name: string): string;
71
73
  getEnumUniqueAlias(name: string, values: string): string;
72
- getRefBasename(ref: string): string;
73
74
  /**
74
75
  * Create a type alias for the schema referenced by the given ReferenceObject
75
76
  */
76
77
  getRefAlias(obj: OpenAPIV3.ReferenceObject): ts.TypeReferenceNode;
77
- getUnionType(variants: (OpenAPIV3.ReferenceObject | SchemaObject)[], discriminator?: OpenAPIV3.DiscriminatorObject): ts.TypeNode;
78
+ getUnionType(variants: (OpenAPIV3.ReferenceObject | SchemaObject)[], discriminator?: OpenAPIV3.DiscriminatorObject): ts.UnionTypeNode;
78
79
  /**
79
80
  * Creates a type node from a given schema.
80
81
  * Delegates to getBaseTypeFromSchema internally and
@@ -89,7 +90,7 @@ export default class ApiGenerator {
89
90
  /**
90
91
  * Creates literal type (or union) from an array of values
91
92
  */
92
- getTypeFromEnum(values: unknown[]): ts.LiteralTypeNode | ts.KeywordTypeNode<ts.KeywordTypeSyntaxKind> | ts.UnionTypeNode;
93
+ getTypeFromEnum(values: unknown[]): ts.LiteralTypeNode | ts.UnionTypeNode;
93
94
  getEnumValuesString(values: string[]): string;
94
95
  getTrueEnum(schema: OpenAPIV3.NonArraySchemaObject, propName: string): ts.TypeReferenceNode;
95
96
  /**
@@ -97,11 +98,12 @@ export default class ApiGenerator {
97
98
  */
98
99
  getTypeFromProperties(props: {
99
100
  [prop: string]: SchemaObject | OpenAPIV3.ReferenceObject;
100
- }, required?: string[], additionalProperties?: boolean | SchemaObject | OpenAPIV3.ReferenceObject): ts.TypeLiteralNode;
101
+ }, required?: string[], additionalProperties?: boolean | OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject): ts.TypeLiteralNode;
101
102
  getTypeFromResponses(responses: OpenAPIV3.ResponsesObject): ts.UnionTypeNode;
102
103
  getTypeFromResponse(resOrRef: OpenAPIV3.ResponseObject | OpenAPIV3.ReferenceObject): ts.TypeNode;
103
104
  getResponseType(responses?: OpenAPIV3.ResponsesObject): "json" | "text" | "blob";
104
- getSchemaFromContent(content: any): any;
105
+ getSchemaFromContent(content: Record<string, OpenAPIV3.MediaTypeObject>): OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject;
106
+ getTypeFromParameter(p: OpenAPIV3.ParameterObject): ts.TypeNode;
105
107
  wrapResult(ex: ts.Expression): ts.Expression;
106
108
  generateApi(): ts.SourceFile;
107
109
  }