@twin.org/api-service 0.0.1-next.2

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.
@@ -0,0 +1,347 @@
1
+ import { ComponentFactory, Is } from '@twin.org/core';
2
+ import { HttpStatusCode } from '@twin.org/web';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ /**
6
+ * The tag to associate with the routes.
7
+ */
8
+ const tagsInformation = [
9
+ {
10
+ name: "Info",
11
+ description: "Information endpoints for the REST server."
12
+ }
13
+ ];
14
+ /**
15
+ * The REST routes for server information.
16
+ * @param baseRouteName Prefix to prepend to the paths.
17
+ * @param componentName The name of the component to use in the routes stored in the ComponentFactory.
18
+ * @returns The generated routes.
19
+ */
20
+ function generateRestRoutesInformation(baseRouteName, componentName) {
21
+ const rootRoute = {
22
+ operationId: "serverRoot",
23
+ summary: "Get the root blank page",
24
+ tag: tagsInformation[0].name,
25
+ method: "GET",
26
+ path: `${baseRouteName}/`,
27
+ handler: async () => ({}),
28
+ responseType: [
29
+ {
30
+ type: "INoContentResponse"
31
+ }
32
+ ],
33
+ excludeFromSpec: true,
34
+ skipAuth: true
35
+ };
36
+ const informationRoute = {
37
+ operationId: "serverInformation",
38
+ summary: "Get the information for the server",
39
+ tag: tagsInformation[0].name,
40
+ method: "GET",
41
+ path: `${baseRouteName}/info`,
42
+ handler: async (httpRequestContext, request) => serverInfo(httpRequestContext, componentName),
43
+ responseType: [
44
+ {
45
+ type: "IServerInfoResponse",
46
+ examples: [
47
+ {
48
+ id: "informationResponse",
49
+ description: "The response for the information request.",
50
+ response: {
51
+ body: {
52
+ name: "API Server",
53
+ version: "1.0.0"
54
+ }
55
+ }
56
+ }
57
+ ]
58
+ }
59
+ ],
60
+ skipAuth: true
61
+ };
62
+ const healthRoute = {
63
+ operationId: "serverHealth",
64
+ summary: "Get the health for the server",
65
+ tag: tagsInformation[0].name,
66
+ method: "GET",
67
+ path: `${baseRouteName}/health`,
68
+ handler: async (httpRequestContext, request) => serverHealth(httpRequestContext, componentName),
69
+ responseType: [
70
+ {
71
+ type: "IServerHealthResponse",
72
+ examples: [
73
+ {
74
+ id: "healthResponseOK",
75
+ description: "The response for the health request.",
76
+ response: {
77
+ body: {
78
+ status: "ok",
79
+ components: [
80
+ {
81
+ name: "Database",
82
+ status: "ok"
83
+ },
84
+ {
85
+ name: "Storage",
86
+ status: "ok"
87
+ }
88
+ ]
89
+ }
90
+ }
91
+ },
92
+ {
93
+ id: "healthResponseWarning",
94
+ description: "The response for the health request with warnings.",
95
+ response: {
96
+ body: {
97
+ status: "warning",
98
+ components: [
99
+ {
100
+ name: "Database",
101
+ status: "warning",
102
+ details: "The database is running slow."
103
+ },
104
+ {
105
+ name: "Storage",
106
+ status: "ok"
107
+ }
108
+ ]
109
+ }
110
+ }
111
+ },
112
+ {
113
+ id: "healthResponseError",
114
+ description: "The response for the health request with errors.",
115
+ response: {
116
+ body: {
117
+ status: "error",
118
+ components: [
119
+ {
120
+ name: "Database",
121
+ status: "ok"
122
+ },
123
+ {
124
+ name: "Storage",
125
+ status: "error",
126
+ details: "The storage is full."
127
+ }
128
+ ]
129
+ }
130
+ }
131
+ }
132
+ ]
133
+ }
134
+ ],
135
+ skipAuth: true
136
+ };
137
+ const specRoute = {
138
+ operationId: "serverSpec",
139
+ summary: "Get the OpenAPI specification for the endpoints",
140
+ tag: tagsInformation[0].name,
141
+ method: "GET",
142
+ path: `${baseRouteName}/spec`,
143
+ handler: async (httpRequestContext, request) => serverSpec(httpRequestContext, componentName),
144
+ responseType: [
145
+ {
146
+ type: "IServerSpecResponse",
147
+ examples: [
148
+ {
149
+ id: "specResponse",
150
+ description: "The response for the spec request.",
151
+ response: {
152
+ body: {
153
+ openapi: "3.1.0",
154
+ info: {},
155
+ paths: {}
156
+ }
157
+ }
158
+ }
159
+ ]
160
+ }
161
+ ],
162
+ skipAuth: true
163
+ };
164
+ return [rootRoute, informationRoute, healthRoute, specRoute];
165
+ }
166
+ /**
167
+ * Get the information for the server.
168
+ * @param httpRequestContext The request context for the API.
169
+ * @param componentName The name of the component to use in the routes.
170
+ * @param request The request.
171
+ * @returns The response object with additional http response properties.
172
+ */
173
+ async function serverInfo(httpRequestContext, componentName, request) {
174
+ const component = ComponentFactory.get(componentName);
175
+ return {
176
+ body: await component.info()
177
+ };
178
+ }
179
+ /**
180
+ * Get the health for the server.
181
+ * @param httpRequestContext The request context for the API.
182
+ * @param componentName The name of the component to use in the routes.
183
+ * @param request The request.
184
+ * @returns The response object with additional http response properties.
185
+ */
186
+ async function serverHealth(httpRequestContext, componentName, request) {
187
+ const component = ComponentFactory.get(componentName);
188
+ return {
189
+ body: await component.health()
190
+ };
191
+ }
192
+ /**
193
+ * Get the spec for the server.
194
+ * @param httpRequestContext The request context for the API.
195
+ * @param componentName The name of the component to use in the routes.
196
+ * @param request The request.
197
+ * @returns The response object with additional http response properties.
198
+ */
199
+ async function serverSpec(httpRequestContext, componentName, request) {
200
+ const component = ComponentFactory.get(componentName);
201
+ const spec = await component.spec();
202
+ if (Is.objectValue(spec)) {
203
+ return {
204
+ body: spec
205
+ };
206
+ }
207
+ return {
208
+ statusCode: HttpStatusCode.notFound
209
+ };
210
+ }
211
+
212
+ const restEntryPoints = [
213
+ {
214
+ name: "information",
215
+ defaultBaseRoute: "",
216
+ tags: tagsInformation,
217
+ generateRoutes: generateRestRoutesInformation
218
+ }
219
+ ];
220
+
221
+ // Copyright 2024 IOTA Stiftung.
222
+ // SPDX-License-Identifier: Apache-2.0.
223
+ /**
224
+ * The information service for the server.
225
+ */
226
+ class InformationService {
227
+ /**
228
+ * Runtime name for the class.
229
+ */
230
+ CLASS_NAME = "InformationService";
231
+ /**
232
+ * The server information.
233
+ * @internal
234
+ */
235
+ _serverInfo;
236
+ /**
237
+ * The server health.
238
+ * @internal
239
+ */
240
+ _healthInfo;
241
+ /**
242
+ * The path to the OpenAPI Spec.
243
+ * @internal
244
+ */
245
+ _openApiSpecPath;
246
+ /**
247
+ * The OpenAPI spec.
248
+ * @internal
249
+ */
250
+ _openApiSpec;
251
+ /**
252
+ * Create a new instance of InformationService.
253
+ * @param serverInfo The server information.
254
+ * @param openApiSpecPath The path to the spec file.
255
+ */
256
+ constructor(serverInfo, openApiSpecPath) {
257
+ this._serverInfo = serverInfo;
258
+ this._healthInfo = {
259
+ status: "ok"
260
+ };
261
+ this._openApiSpecPath = openApiSpecPath;
262
+ }
263
+ /**
264
+ * The service needs to be started when the application is initialized.
265
+ * @returns Nothing.
266
+ */
267
+ async start() {
268
+ const filename = this._openApiSpecPath;
269
+ if (Is.stringValue(filename)) {
270
+ const contentBuffer = await readFile(filename, "utf8");
271
+ this._openApiSpec = JSON.parse(contentBuffer);
272
+ }
273
+ }
274
+ /**
275
+ * Get the server information.
276
+ * @returns The service information.
277
+ */
278
+ async info() {
279
+ return this._serverInfo;
280
+ }
281
+ /**
282
+ * Get the OpenAPI spec.
283
+ * @returns The OpenAPI spec.
284
+ */
285
+ async spec() {
286
+ return this._openApiSpec;
287
+ }
288
+ /**
289
+ * Get the server health.
290
+ * @returns The service health.
291
+ */
292
+ async health() {
293
+ let errorCount = 0;
294
+ let warningCount = 0;
295
+ if (Is.arrayValue(this._healthInfo.components)) {
296
+ errorCount = this._healthInfo.components.filter(c => c.status === "error").length;
297
+ warningCount = this._healthInfo.components.filter(c => c.status === "warning").length;
298
+ }
299
+ if (errorCount > 0) {
300
+ this._healthInfo.status = "error";
301
+ }
302
+ else if (warningCount > 0) {
303
+ this._healthInfo.status = "warning";
304
+ }
305
+ else {
306
+ this._healthInfo.status = "ok";
307
+ }
308
+ return this._healthInfo;
309
+ }
310
+ /**
311
+ * Set the status of a component.
312
+ * @param name The component name.
313
+ * @param status The status of the component.
314
+ * @param details The details for the status.
315
+ * @returns Nothing.
316
+ */
317
+ async setComponentHealth(name, status, details) {
318
+ const component = this._healthInfo.components?.find(c => c.name === name);
319
+ if (Is.undefined(component)) {
320
+ this._healthInfo.components ??= [];
321
+ this._healthInfo.components.push({
322
+ name,
323
+ status,
324
+ details
325
+ });
326
+ }
327
+ else {
328
+ component.status = status;
329
+ component.details = details;
330
+ }
331
+ }
332
+ /**
333
+ * Remove the status of a component.
334
+ * @param name The component name.
335
+ * @returns Nothing.
336
+ */
337
+ async removeComponentHealth(name) {
338
+ if (Is.arrayValue(this._healthInfo.components)) {
339
+ const componentIndex = this._healthInfo.components.findIndex(c => c.name === name);
340
+ if (componentIndex >= 0) {
341
+ this._healthInfo.components.splice(componentIndex, 1);
342
+ }
343
+ }
344
+ }
345
+ }
346
+
347
+ export { InformationService, generateRestRoutesInformation, restEntryPoints, serverHealth, serverInfo, serverSpec, tagsInformation };
@@ -0,0 +1,3 @@
1
+ export * from "./informationRoutes";
2
+ export * from "./restEntryPoints";
3
+ export * from "./informationService";
@@ -0,0 +1,36 @@
1
+ import type { IHttpRequestContext, INoContentRequest, IRestRoute, IServerHealthResponse, IServerInfoResponse, IServerSpecResponse, ITag } from "@twin.org/api-models";
2
+ /**
3
+ * The tag to associate with the routes.
4
+ */
5
+ export declare const tagsInformation: ITag[];
6
+ /**
7
+ * The REST routes for server information.
8
+ * @param baseRouteName Prefix to prepend to the paths.
9
+ * @param componentName The name of the component to use in the routes stored in the ComponentFactory.
10
+ * @returns The generated routes.
11
+ */
12
+ export declare function generateRestRoutesInformation(baseRouteName: string, componentName: string): IRestRoute[];
13
+ /**
14
+ * Get the information for the server.
15
+ * @param httpRequestContext The request context for the API.
16
+ * @param componentName The name of the component to use in the routes.
17
+ * @param request The request.
18
+ * @returns The response object with additional http response properties.
19
+ */
20
+ export declare function serverInfo(httpRequestContext: IHttpRequestContext, componentName: string, request: INoContentRequest): Promise<IServerInfoResponse>;
21
+ /**
22
+ * Get the health for the server.
23
+ * @param httpRequestContext The request context for the API.
24
+ * @param componentName The name of the component to use in the routes.
25
+ * @param request The request.
26
+ * @returns The response object with additional http response properties.
27
+ */
28
+ export declare function serverHealth(httpRequestContext: IHttpRequestContext, componentName: string, request: INoContentRequest): Promise<IServerHealthResponse>;
29
+ /**
30
+ * Get the spec for the server.
31
+ * @param httpRequestContext The request context for the API.
32
+ * @param componentName The name of the component to use in the routes.
33
+ * @param request The request.
34
+ * @returns The response object with additional http response properties.
35
+ */
36
+ export declare function serverSpec(httpRequestContext: IHttpRequestContext, componentName: string, request: INoContentRequest): Promise<IServerSpecResponse>;
@@ -0,0 +1,50 @@
1
+ import type { HealthStatus, IHealthInfo, IInformationComponent, IServerInfo } from "@twin.org/api-models";
2
+ /**
3
+ * The information service for the server.
4
+ */
5
+ export declare class InformationService implements IInformationComponent {
6
+ /**
7
+ * Runtime name for the class.
8
+ */
9
+ readonly CLASS_NAME: string;
10
+ /**
11
+ * Create a new instance of InformationService.
12
+ * @param serverInfo The server information.
13
+ * @param openApiSpecPath The path to the spec file.
14
+ */
15
+ constructor(serverInfo: IServerInfo, openApiSpecPath?: string);
16
+ /**
17
+ * The service needs to be started when the application is initialized.
18
+ * @returns Nothing.
19
+ */
20
+ start(): Promise<void>;
21
+ /**
22
+ * Get the server information.
23
+ * @returns The service information.
24
+ */
25
+ info(): Promise<IServerInfo>;
26
+ /**
27
+ * Get the OpenAPI spec.
28
+ * @returns The OpenAPI spec.
29
+ */
30
+ spec(): Promise<unknown>;
31
+ /**
32
+ * Get the server health.
33
+ * @returns The service health.
34
+ */
35
+ health(): Promise<IHealthInfo>;
36
+ /**
37
+ * Set the status of a component.
38
+ * @param name The component name.
39
+ * @param status The status of the component.
40
+ * @param details The details for the status.
41
+ * @returns Nothing.
42
+ */
43
+ setComponentHealth(name: string, status: HealthStatus, details?: string): Promise<void>;
44
+ /**
45
+ * Remove the status of a component.
46
+ * @param name The component name.
47
+ * @returns Nothing.
48
+ */
49
+ removeComponentHealth(name: string): Promise<void>;
50
+ }
@@ -0,0 +1,2 @@
1
+ import type { IRestRouteEntryPoint } from "@twin.org/api-models";
2
+ export declare const restEntryPoints: IRestRouteEntryPoint[];
@@ -0,0 +1,5 @@
1
+ # @twin.org/api-service - Changelog
2
+
3
+ ## v0.0.1-next.2
4
+
5
+ - Initial Release
@@ -0,0 +1 @@
1
+ # @twin.org/api-service - Examples
@@ -0,0 +1,169 @@
1
+ # Class: InformationService
2
+
3
+ The information service for the server.
4
+
5
+ ## Implements
6
+
7
+ - `IInformationComponent`
8
+
9
+ ## Constructors
10
+
11
+ ### new InformationService()
12
+
13
+ > **new InformationService**(`serverInfo`, `openApiSpecPath`?): [`InformationService`](InformationService.md)
14
+
15
+ Create a new instance of InformationService.
16
+
17
+ #### Parameters
18
+
19
+ • **serverInfo**: `IServerInfo`
20
+
21
+ The server information.
22
+
23
+ • **openApiSpecPath?**: `string`
24
+
25
+ The path to the spec file.
26
+
27
+ #### Returns
28
+
29
+ [`InformationService`](InformationService.md)
30
+
31
+ ## Properties
32
+
33
+ ### CLASS\_NAME
34
+
35
+ > `readonly` **CLASS\_NAME**: `string`
36
+
37
+ Runtime name for the class.
38
+
39
+ #### Implementation of
40
+
41
+ `IInformationComponent.CLASS_NAME`
42
+
43
+ ## Methods
44
+
45
+ ### start()
46
+
47
+ > **start**(): `Promise`\<`void`\>
48
+
49
+ The service needs to be started when the application is initialized.
50
+
51
+ #### Returns
52
+
53
+ `Promise`\<`void`\>
54
+
55
+ Nothing.
56
+
57
+ #### Implementation of
58
+
59
+ `IInformationComponent.start`
60
+
61
+ ***
62
+
63
+ ### info()
64
+
65
+ > **info**(): `Promise`\<`IServerInfo`\>
66
+
67
+ Get the server information.
68
+
69
+ #### Returns
70
+
71
+ `Promise`\<`IServerInfo`\>
72
+
73
+ The service information.
74
+
75
+ #### Implementation of
76
+
77
+ `IInformationComponent.info`
78
+
79
+ ***
80
+
81
+ ### spec()
82
+
83
+ > **spec**(): `Promise`\<`unknown`\>
84
+
85
+ Get the OpenAPI spec.
86
+
87
+ #### Returns
88
+
89
+ `Promise`\<`unknown`\>
90
+
91
+ The OpenAPI spec.
92
+
93
+ #### Implementation of
94
+
95
+ `IInformationComponent.spec`
96
+
97
+ ***
98
+
99
+ ### health()
100
+
101
+ > **health**(): `Promise`\<`IHealthInfo`\>
102
+
103
+ Get the server health.
104
+
105
+ #### Returns
106
+
107
+ `Promise`\<`IHealthInfo`\>
108
+
109
+ The service health.
110
+
111
+ #### Implementation of
112
+
113
+ `IInformationComponent.health`
114
+
115
+ ***
116
+
117
+ ### setComponentHealth()
118
+
119
+ > **setComponentHealth**(`name`, `status`, `details`?): `Promise`\<`void`\>
120
+
121
+ Set the status of a component.
122
+
123
+ #### Parameters
124
+
125
+ • **name**: `string`
126
+
127
+ The component name.
128
+
129
+ • **status**: `HealthStatus`
130
+
131
+ The status of the component.
132
+
133
+ • **details?**: `string`
134
+
135
+ The details for the status.
136
+
137
+ #### Returns
138
+
139
+ `Promise`\<`void`\>
140
+
141
+ Nothing.
142
+
143
+ #### Implementation of
144
+
145
+ `IInformationComponent.setComponentHealth`
146
+
147
+ ***
148
+
149
+ ### removeComponentHealth()
150
+
151
+ > **removeComponentHealth**(`name`): `Promise`\<`void`\>
152
+
153
+ Remove the status of a component.
154
+
155
+ #### Parameters
156
+
157
+ • **name**: `string`
158
+
159
+ The component name.
160
+
161
+ #### Returns
162
+
163
+ `Promise`\<`void`\>
164
+
165
+ Nothing.
166
+
167
+ #### Implementation of
168
+
169
+ `IInformationComponent.removeComponentHealth`
@@ -0,0 +1,21 @@
1
+ # Function: generateRestRoutesInformation()
2
+
3
+ > **generateRestRoutesInformation**(`baseRouteName`, `componentName`): `IRestRoute`[]
4
+
5
+ The REST routes for server information.
6
+
7
+ ## Parameters
8
+
9
+ • **baseRouteName**: `string`
10
+
11
+ Prefix to prepend to the paths.
12
+
13
+ • **componentName**: `string`
14
+
15
+ The name of the component to use in the routes stored in the ComponentFactory.
16
+
17
+ ## Returns
18
+
19
+ `IRestRoute`[]
20
+
21
+ The generated routes.
@@ -0,0 +1,25 @@
1
+ # Function: serverHealth()
2
+
3
+ > **serverHealth**(`httpRequestContext`, `componentName`, `request`): `Promise`\<`IServerHealthResponse`\>
4
+
5
+ Get the health for the server.
6
+
7
+ ## Parameters
8
+
9
+ • **httpRequestContext**: `IHttpRequestContext`
10
+
11
+ The request context for the API.
12
+
13
+ • **componentName**: `string`
14
+
15
+ The name of the component to use in the routes.
16
+
17
+ • **request**: `INoContentRequest`
18
+
19
+ The request.
20
+
21
+ ## Returns
22
+
23
+ `Promise`\<`IServerHealthResponse`\>
24
+
25
+ The response object with additional http response properties.
@@ -0,0 +1,25 @@
1
+ # Function: serverInfo()
2
+
3
+ > **serverInfo**(`httpRequestContext`, `componentName`, `request`): `Promise`\<`IServerInfoResponse`\>
4
+
5
+ Get the information for the server.
6
+
7
+ ## Parameters
8
+
9
+ • **httpRequestContext**: `IHttpRequestContext`
10
+
11
+ The request context for the API.
12
+
13
+ • **componentName**: `string`
14
+
15
+ The name of the component to use in the routes.
16
+
17
+ • **request**: `INoContentRequest`
18
+
19
+ The request.
20
+
21
+ ## Returns
22
+
23
+ `Promise`\<`IServerInfoResponse`\>
24
+
25
+ The response object with additional http response properties.