@furystack/rest 8.0.31 → 8.0.33
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/CHANGELOG.md +11 -64
- package/README.md +157 -11
- package/esm/api-endpoint-schema.d.ts +25 -8
- package/esm/api-endpoint-schema.d.ts.map +1 -1
- package/esm/rest-api.d.ts +1 -1
- package/esm/rest-api.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/api-endpoint-schema.ts +27 -8
- package/src/rest-api.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,74 +1,21 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
3
|
+
## [8.0.33] - 2026-01-26
|
|
5
4
|
|
|
6
|
-
###
|
|
5
|
+
### ⬆️ Dependencies
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
- Updated `@furystack/inject` with fix for singleton injector reference being overwritten by child injectors
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
## [8.0.32] - 2026-01-22
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
### ⬆️ Dependencies
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
- Dependency updates
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
### 📚 Documentation
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
- Expanded README with detailed API definition examples and type documentation
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
### 🔧 Chores
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
**Note:** Version bump only for package @furystack/rest
|
|
25
|
-
|
|
26
|
-
### [3.1.3](https://github.com/furystack/furystack/compare/@furystack/rest@3.1.2...@furystack/rest@3.1.3) (2021-12-08)
|
|
27
|
-
|
|
28
|
-
**Note:** Version bump only for package @furystack/rest
|
|
29
|
-
|
|
30
|
-
### [3.1.2](https://github.com/furystack/furystack/compare/@furystack/rest@3.1.1...@furystack/rest@3.1.2) (2021-11-30)
|
|
31
|
-
|
|
32
|
-
**Note:** Version bump only for package @furystack/rest
|
|
33
|
-
|
|
34
|
-
### [3.1.1](https://github.com/furystack/furystack/compare/@furystack/rest@3.1.0...@furystack/rest@3.1.1) (2021-11-29)
|
|
35
|
-
|
|
36
|
-
**Note:** Version bump only for package @furystack/rest
|
|
37
|
-
|
|
38
|
-
## [3.1.0](https://github.com/furystack/furystack/compare/@furystack/rest@3.0.21...@furystack/rest@3.1.0) (2021-11-19)
|
|
39
|
-
|
|
40
|
-
### 🚀 What's new
|
|
41
|
-
|
|
42
|
-
- **@furystack/rest:** Extended allowed HTTP methods with HEAD, CONNECT and TRACE ([85b91f2](https://github.com/furystack/furystack/commit/85b91f2254a7459d4cb121caeccec792880467fa))
|
|
43
|
-
|
|
44
|
-
### [3.0.21](https://github.com/furystack/furystack/compare/@furystack/rest@3.0.20...@furystack/rest@3.0.21) (2021-11-09)
|
|
45
|
-
|
|
46
|
-
**Note:** Version bump only for package @furystack/rest
|
|
47
|
-
|
|
48
|
-
### [3.0.20](https://github.com/furystack/furystack/compare/@furystack/rest@3.0.19...@furystack/rest@3.0.20) (2021-10-15)
|
|
49
|
-
|
|
50
|
-
**Note:** Version bump only for package @furystack/rest
|
|
51
|
-
|
|
52
|
-
### [3.0.19](https://github.com/furystack/furystack/compare/@furystack/rest@3.0.18...@furystack/rest@3.0.19) (2021-10-05)
|
|
53
|
-
|
|
54
|
-
**Note:** Version bump only for package @furystack/rest
|
|
55
|
-
|
|
56
|
-
### [3.0.18](https://github.com/furystack/furystack/compare/@furystack/rest@3.0.17...@furystack/rest@3.0.18) (2021-09-16)
|
|
57
|
-
|
|
58
|
-
**Note:** Version bump only for package @furystack/rest
|
|
59
|
-
|
|
60
|
-
### [3.0.17](https://github.com/furystack/furystack/compare/@furystack/rest@3.0.16...@furystack/rest@3.0.17) (2021-08-27)
|
|
61
|
-
|
|
62
|
-
**Note:** Version bump only for package @furystack/rest
|
|
63
|
-
|
|
64
|
-
### [3.0.16](https://github.com/furystack/furystack/compare/@furystack/rest@3.0.15...@furystack/rest@3.0.16) (2021-08-19)
|
|
65
|
-
|
|
66
|
-
**Note:** Version bump only for package @furystack/rest
|
|
67
|
-
|
|
68
|
-
### [3.0.15](https://github.com/furystack/furystack/compare/@furystack/rest@1.3.2...@furystack/rest@3.0.15) (2021-08-19)
|
|
69
|
-
|
|
70
|
-
**Note:** Version bump only for package @furystack/rest
|
|
71
|
-
|
|
72
|
-
### [3.0.14](https://github.com/furystack/furystack/compare/@furystack/rest@1.3.2...@furystack/rest@3.0.14) (2021-07-30)
|
|
73
|
-
|
|
74
|
-
**Note:** Version bump only for package @furystack/rest
|
|
21
|
+
- Migrated to centralized changelog management system
|
package/README.md
CHANGED
|
@@ -1,17 +1,163 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @furystack/rest
|
|
2
2
|
|
|
3
|
-
REST API
|
|
3
|
+
REST API type definitions and contracts for FuryStack.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This package provides the foundation for building type-safe REST APIs that are shared between your backend and frontend.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Installation
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
```bash
|
|
10
|
+
npm install @furystack/rest
|
|
11
|
+
# or
|
|
12
|
+
yarn add @furystack/rest
|
|
13
|
+
```
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
+
## Concept
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
The FuryStack REST approach works as follows:
|
|
18
|
+
|
|
19
|
+
1. **Define** your REST API as a TypeScript interface in a shared package
|
|
20
|
+
2. **Implement** the API on the backend using `@furystack/rest-service`
|
|
21
|
+
3. **Consume** the API on the frontend using `@furystack/rest-client-fetch`
|
|
22
|
+
4. **Benefit** from end-to-end type safety
|
|
23
|
+
|
|
24
|
+
## Defining an API
|
|
25
|
+
|
|
26
|
+
Create an API interface that describes all endpoints:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import type { RestApi } from '@furystack/rest'
|
|
30
|
+
|
|
31
|
+
// Define your models
|
|
32
|
+
interface User {
|
|
33
|
+
id: string
|
|
34
|
+
name: string
|
|
35
|
+
email: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface CreateUserDto {
|
|
39
|
+
name: string
|
|
40
|
+
email: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Define your API
|
|
44
|
+
export interface MyApi extends RestApi {
|
|
45
|
+
GET: {
|
|
46
|
+
// Simple endpoint returning a list
|
|
47
|
+
'/users': { result: User[] }
|
|
48
|
+
|
|
49
|
+
// Endpoint with URL parameters
|
|
50
|
+
'/users/:id': {
|
|
51
|
+
result: User
|
|
52
|
+
url: { id: string }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Endpoint with query parameters
|
|
56
|
+
'/users/search': {
|
|
57
|
+
result: User[]
|
|
58
|
+
query: { name?: string; email?: string }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
POST: {
|
|
63
|
+
// Endpoint with request body
|
|
64
|
+
'/users': {
|
|
65
|
+
result: User
|
|
66
|
+
body: CreateUserDto
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Endpoint with custom headers
|
|
70
|
+
'/users/import': {
|
|
71
|
+
result: { imported: number }
|
|
72
|
+
body: User[]
|
|
73
|
+
headers: { 'X-Import-Mode': 'merge' | 'replace' }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
PATCH: {
|
|
78
|
+
'/users/:id': {
|
|
79
|
+
result: User
|
|
80
|
+
url: { id: string }
|
|
81
|
+
body: Partial<CreateUserDto>
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
DELETE: {
|
|
86
|
+
'/users/:id': {
|
|
87
|
+
result: { success: boolean }
|
|
88
|
+
url: { id: string }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Endpoint Schema
|
|
95
|
+
|
|
96
|
+
Each endpoint can define:
|
|
97
|
+
|
|
98
|
+
| Property | Type | Description |
|
|
99
|
+
| --------- | ------ | --------------------------------- |
|
|
100
|
+
| `result` | any | The response body type (required) |
|
|
101
|
+
| `url` | object | URL path parameters (e.g., `:id`) |
|
|
102
|
+
| `query` | object | Query string parameters |
|
|
103
|
+
| `body` | any | Request body type |
|
|
104
|
+
| `headers` | object | Required headers |
|
|
105
|
+
|
|
106
|
+
## HTTP Methods
|
|
107
|
+
|
|
108
|
+
The `RestApi` type supports all standard HTTP methods:
|
|
109
|
+
|
|
110
|
+
- `GET` - Retrieve resources
|
|
111
|
+
- `POST` - Create resources
|
|
112
|
+
- `PUT` - Replace resources
|
|
113
|
+
- `PATCH` - Partially update resources
|
|
114
|
+
- `DELETE` - Remove resources
|
|
115
|
+
- `HEAD` - Retrieve headers only
|
|
116
|
+
- `OPTIONS` - Retrieve supported methods
|
|
117
|
+
- `CONNECT` - Establish tunnel
|
|
118
|
+
- `TRACE` - Diagnostic trace
|
|
119
|
+
|
|
120
|
+
## Schema Endpoint
|
|
121
|
+
|
|
122
|
+
You can expose your API schema for documentation:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import type { WithSchemaAction, RestApi } from '@furystack/rest'
|
|
126
|
+
|
|
127
|
+
// Add schema endpoints to your API
|
|
128
|
+
export type MyApiWithSchema = WithSchemaAction<MyApi>
|
|
129
|
+
|
|
130
|
+
// This adds:
|
|
131
|
+
// GET /schema - Returns the API schema
|
|
132
|
+
// GET /swagger.json - Returns Swagger/OpenAPI documentation
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Utilities
|
|
136
|
+
|
|
137
|
+
### Query String Serialization
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { serializeToQueryString, deserializeQueryString } from '@furystack/rest'
|
|
141
|
+
|
|
142
|
+
const queryString = serializeToQueryString({ name: 'John', active: true })
|
|
143
|
+
// Returns: 'name=John&active=true'
|
|
144
|
+
|
|
145
|
+
const params = deserializeQueryString('name=John&active=true')
|
|
146
|
+
// Returns: { name: 'John', active: 'true' }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Request Error
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import { RequestError } from '@furystack/rest'
|
|
153
|
+
|
|
154
|
+
// Throw typed errors in your API
|
|
155
|
+
throw new RequestError('User not found', 404)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Best Practices
|
|
159
|
+
|
|
160
|
+
1. **Shared Package**: Put your API interface in a shared package that both frontend and backend can import
|
|
161
|
+
2. **Consistent Naming**: Use RESTful naming conventions for endpoints
|
|
162
|
+
3. **Explicit Types**: Define explicit types for all request/response bodies
|
|
163
|
+
4. **Documentation**: Use JSDoc comments on your API interface for documentation
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import type { Method } from './methods.js';
|
|
2
|
+
import type { RestApi } from './rest-api.js';
|
|
2
3
|
/**
|
|
3
4
|
* The JSON schema type used for API endpoint definitions.
|
|
4
5
|
*/
|
|
5
6
|
export type Schema = unknown;
|
|
6
7
|
/**
|
|
7
|
-
* Represents the definition of an API endpoint, including its
|
|
8
|
+
* Represents the definition of an API endpoint, including its path, schema, and schema name.
|
|
9
|
+
* The HTTP method is now implicit in the structure key.
|
|
8
10
|
*/
|
|
9
11
|
export type ApiEndpointDefinition = {
|
|
10
|
-
/**
|
|
11
|
-
* The HTTP method for the endpoint (e.g., GET, POST, PUT, DELETE).
|
|
12
|
-
*/
|
|
13
|
-
method: Method;
|
|
14
12
|
/**
|
|
15
13
|
* The path of the endpoint, which is the URL pattern that the endpoint responds to.
|
|
16
14
|
*/
|
|
@@ -32,12 +30,31 @@ export type ApiEndpointDefinition = {
|
|
|
32
30
|
isAuthenticated: boolean;
|
|
33
31
|
};
|
|
34
32
|
/**
|
|
35
|
-
* Represents the schema for an API,
|
|
33
|
+
* Represents the schema for an API, organized by HTTP method and then by path.
|
|
34
|
+
* This structure allows multiple endpoints with the same path but different methods.
|
|
35
|
+
* @typeParam TApi - The REST API type this schema represents. When provided, the endpoint
|
|
36
|
+
* paths are preserved for better type safety and autocomplete.
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* type MyApi = {
|
|
40
|
+
* GET: { '/users': { result: User[] }, '/users/:id': { result: User } }
|
|
41
|
+
* POST: { '/users': { result: User, body: CreateUser } }
|
|
42
|
+
* }
|
|
43
|
+
* // ApiEndpointSchema<MyApi> will have:
|
|
44
|
+
* // endpoints: {
|
|
45
|
+
* // GET?: { '/users': ApiEndpointDefinition, '/users/:id': ApiEndpointDefinition }
|
|
46
|
+
* // POST?: { '/users': ApiEndpointDefinition }
|
|
47
|
+
* // }
|
|
48
|
+
* ```
|
|
36
49
|
*/
|
|
37
|
-
export type ApiEndpointSchema = {
|
|
50
|
+
export type ApiEndpointSchema<TApi extends RestApi = RestApi> = {
|
|
38
51
|
name: string;
|
|
39
52
|
description: string;
|
|
40
53
|
version: string;
|
|
41
|
-
endpoints:
|
|
54
|
+
endpoints: {
|
|
55
|
+
[TMethod in Method]?: TMethod extends keyof TApi ? TApi[TMethod] extends Record<string, unknown> ? {
|
|
56
|
+
[TPath in keyof TApi[TMethod] & string]: ApiEndpointDefinition;
|
|
57
|
+
} : Record<string, ApiEndpointDefinition> : Record<string, ApiEndpointDefinition>;
|
|
58
|
+
};
|
|
42
59
|
};
|
|
43
60
|
//# sourceMappingURL=api-endpoint-schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-endpoint-schema.d.ts","sourceRoot":"","sources":["../src/api-endpoint-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"api-endpoint-schema.d.ts","sourceRoot":"","sources":["../src/api-endpoint-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE5C;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,OAAO,CAAA;AAE5B;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,eAAe,EAAE,OAAO,CAAA;CACzB,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,iBAAiB,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO,IAAI;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE;SACR,OAAO,IAAI,MAAM,CAAC,CAAC,EAAE,OAAO,SAAS,MAAM,IAAI,GAC5C,IAAI,CAAC,OAAO,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3C;aAAG,KAAK,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,qBAAqB;SAAE,GAClE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,GACvC,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC;KAC1C,CAAA;CACF,CAAA"}
|
package/esm/rest-api.d.ts
CHANGED
package/esm/rest-api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../src/rest-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAE5D,MAAM,MAAM,OAAO,GAAG;KACnB,OAAO,IAAI,MAAM,CAAC,CAAC,EAAE;QACpB,CAAC,IAAI,EAAE,MAAM,GAAG;YAAE,MAAM,EAAE,OAAO,CAAC;YAAC,GAAG,CAAC,EAAE,OAAO,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,CAAC;YAAC,OAAO,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KACvG;CACF,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,OAAO,IAAI,CAAC,GAAG;IACpD,GAAG,EAAE;QACH,SAAS,EAAE;YAAE,MAAM,EAAE,iBAAiB,CAAC;YAAC,OAAO,EAAE;gBAAE,MAAM,EAAE,yBAAyB,CAAA;aAAE,CAAA;SAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../src/rest-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAE5D,MAAM,MAAM,OAAO,GAAG;KACnB,OAAO,IAAI,MAAM,CAAC,CAAC,EAAE;QACpB,CAAC,IAAI,EAAE,MAAM,GAAG;YAAE,MAAM,EAAE,OAAO,CAAC;YAAC,GAAG,CAAC,EAAE,OAAO,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,CAAC;YAAC,OAAO,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KACvG;CACF,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,OAAO,IAAI,CAAC,GAAG;IACpD,GAAG,EAAE;QACH,SAAS,EAAE;YAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAAC,OAAO,EAAE;gBAAE,MAAM,EAAE,yBAAyB,CAAA;aAAE,CAAA;SAAE,CAAA;QAC3F,eAAe,EAAE;YAAE,MAAM,EAAE,eAAe,CAAA;SAAE,CAAA;KAC7C,CAAA;CACF,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/rest",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.33",
|
|
4
4
|
"description": "Generic REST package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
},
|
|
38
38
|
"homepage": "https://github.com/furystack/furystack",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@furystack/core": "^15.0.
|
|
41
|
-
"@furystack/inject": "^12.0.
|
|
40
|
+
"@furystack/core": "^15.0.33",
|
|
41
|
+
"@furystack/inject": "^12.0.27"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@types/node": "^25.0.
|
|
44
|
+
"@types/node": "^25.0.10",
|
|
45
45
|
"typescript": "^5.9.3",
|
|
46
|
-
"vitest": "^4.0.
|
|
46
|
+
"vitest": "^4.0.17"
|
|
47
47
|
},
|
|
48
48
|
"gitHead": "1045d854bfd8c475b7035471d130d401417a2321"
|
|
49
49
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Method } from './methods.js'
|
|
2
|
+
import type { RestApi } from './rest-api.js'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* The JSON schema type used for API endpoint definitions.
|
|
@@ -6,13 +7,10 @@ import type { Method } from './methods.js'
|
|
|
6
7
|
export type Schema = unknown // TODO: Fix me
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Represents the definition of an API endpoint, including its
|
|
10
|
+
* Represents the definition of an API endpoint, including its path, schema, and schema name.
|
|
11
|
+
* The HTTP method is now implicit in the structure key.
|
|
10
12
|
*/
|
|
11
13
|
export type ApiEndpointDefinition = {
|
|
12
|
-
/**
|
|
13
|
-
* The HTTP method for the endpoint (e.g., GET, POST, PUT, DELETE).
|
|
14
|
-
*/
|
|
15
|
-
method: Method
|
|
16
14
|
/**
|
|
17
15
|
* The path of the endpoint, which is the URL pattern that the endpoint responds to.
|
|
18
16
|
*/
|
|
@@ -35,11 +33,32 @@ export type ApiEndpointDefinition = {
|
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
/**
|
|
38
|
-
* Represents the schema for an API,
|
|
36
|
+
* Represents the schema for an API, organized by HTTP method and then by path.
|
|
37
|
+
* This structure allows multiple endpoints with the same path but different methods.
|
|
38
|
+
* @typeParam TApi - The REST API type this schema represents. When provided, the endpoint
|
|
39
|
+
* paths are preserved for better type safety and autocomplete.
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* type MyApi = {
|
|
43
|
+
* GET: { '/users': { result: User[] }, '/users/:id': { result: User } }
|
|
44
|
+
* POST: { '/users': { result: User, body: CreateUser } }
|
|
45
|
+
* }
|
|
46
|
+
* // ApiEndpointSchema<MyApi> will have:
|
|
47
|
+
* // endpoints: {
|
|
48
|
+
* // GET?: { '/users': ApiEndpointDefinition, '/users/:id': ApiEndpointDefinition }
|
|
49
|
+
* // POST?: { '/users': ApiEndpointDefinition }
|
|
50
|
+
* // }
|
|
51
|
+
* ```
|
|
39
52
|
*/
|
|
40
|
-
export type ApiEndpointSchema = {
|
|
53
|
+
export type ApiEndpointSchema<TApi extends RestApi = RestApi> = {
|
|
41
54
|
name: string
|
|
42
55
|
description: string
|
|
43
56
|
version: string
|
|
44
|
-
endpoints:
|
|
57
|
+
endpoints: {
|
|
58
|
+
[TMethod in Method]?: TMethod extends keyof TApi
|
|
59
|
+
? TApi[TMethod] extends Record<string, unknown>
|
|
60
|
+
? { [TPath in keyof TApi[TMethod] & string]: ApiEndpointDefinition }
|
|
61
|
+
: Record<string, ApiEndpointDefinition>
|
|
62
|
+
: Record<string, ApiEndpointDefinition>
|
|
63
|
+
}
|
|
45
64
|
}
|
package/src/rest-api.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type RestApi = {
|
|
|
14
14
|
*/
|
|
15
15
|
export type WithSchemaAction<T extends RestApi> = T & {
|
|
16
16
|
GET: {
|
|
17
|
-
'/schema': { result: ApiEndpointSchema
|
|
17
|
+
'/schema': { result: ApiEndpointSchema<T>; headers: { accept: 'application/schema+json' } }
|
|
18
18
|
'/swagger.json': { result: SwaggerDocument }
|
|
19
19
|
}
|
|
20
20
|
}
|