Skip to content

Commit 30a6e60

Browse files
authored
Add TypeScript/JavaScript client support for SSE events (#75)
1 parent 9830674 commit 30a6e60

22 files changed

+809
-143
lines changed

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project>
22

33
<PropertyGroup>
4-
<VersionPrefix>3.5.0</VersionPrefix>
5-
<PackageValidationBaselineVersion>3.4.0</PackageValidationBaselineVersion>
4+
<VersionPrefix>3.6.0</VersionPrefix>
5+
<PackageValidationBaselineVersion>3.5.0</PackageValidationBaselineVersion>
66
<LangVersion>12.0</LangVersion>
77
<Nullable>enable</Nullable>
88
<ImplicitUsings>enable</ImplicitUsings>

ReleaseNotes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
These are the NuGet package releases. See also [npm Release Notes](ReleaseNotesNpm.md).
44

5+
## 3.6.0
6+
7+
* Add client support for events (Server-Sent Events).
8+
59
## 3.5.0
610

711
* Add option to omit generated HTTP client.

ReleaseNotesNpm.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
These are `facility-core` npm package releases. See also [Release Notes](ReleaseNotes.md).
44

5+
## 2.3.0
6+
7+
* Add support for Server-Sent Events.
8+
59
## 2.2.0
610

711
* Add `context` to request methods.

conformance/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

conformance/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"fastify-cli": "^7.3.0",
2323
"mocha": "^10.0.0",
2424
"node-fetch": "^2.6.7",
25-
"typescript": "^5.7.2"
25+
"typescript": "~5.7.2"
2626
},
2727
"dependencies": {
2828
"facility-core": "file:../ts",

conformance/src/conformanceApi.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
/* eslint-disable */
33

44
import { HttpClientUtility, IServiceResult, IHttpClientOptions } from 'facility-core';
5-
import { IConformanceApi, IGetApiInfoRequest, IGetApiInfoResponse, IGetWidgetsRequest, IGetWidgetsResponse, ICreateWidgetRequest, ICreateWidgetResponse, IGetWidgetRequest, IGetWidgetResponse, IDeleteWidgetRequest, IDeleteWidgetResponse, IGetWidgetBatchRequest, IGetWidgetBatchResponse, IMirrorFieldsRequest, IMirrorFieldsResponse, ICheckQueryRequest, ICheckQueryResponse, ICheckPathRequest, ICheckPathResponse, IMirrorHeadersRequest, IMirrorHeadersResponse, IMixedRequest, IMixedResponse, IRequiredRequest, IRequiredResponse, IMirrorBytesRequest, IMirrorBytesResponse, IMirrorTextRequest, IMirrorTextResponse, IBodyTypesRequest, IBodyTypesResponse, IWidget, IAny, IAnyArray, IAnyMap, IAnyResult, IAnyNullable, IHasWidget, Answer, ApiErrors } from './conformanceApiTypes';
5+
import { IConformanceApi, IGetApiInfoRequest, IGetApiInfoResponse, IGetWidgetsRequest, IGetWidgetsResponse, ICreateWidgetRequest, ICreateWidgetResponse, IGetWidgetRequest, IGetWidgetResponse, IDeleteWidgetRequest, IDeleteWidgetResponse, IGetWidgetBatchRequest, IGetWidgetBatchResponse, IMirrorFieldsRequest, IMirrorFieldsResponse, ICheckQueryRequest, ICheckQueryResponse, ICheckPathRequest, ICheckPathResponse, IMirrorHeadersRequest, IMirrorHeadersResponse, IMixedRequest, IMixedResponse, IRequiredRequest, IRequiredResponse, IMirrorBytesRequest, IMirrorBytesResponse, IMirrorTextRequest, IMirrorTextResponse, IBodyTypesRequest, IBodyTypesResponse, IFibonacciRequest, IFibonacciResponse, IWidget, IAny, IAnyArray, IAnyMap, IAnyResult, IAnyNullable, IHasWidget, Answer, ApiErrors } from './conformanceApiTypes';
66
export * from './conformanceApiTypes';
77

88
/** Provides access to ConformanceApi over HTTP via fetch. */
99
export function createHttpClient(options: IHttpClientOptions): IConformanceApi {
1010
return new ConformanceApiHttpClient(options);
1111
}
1212

13-
const { fetchResponse, createResponseError, createRequiredRequestFieldError } = HttpClientUtility;
13+
const { fetchResponse, createResponseError, createRequiredRequestFieldError, createFetchEventStream } = HttpClientUtility;
1414
type IFetch = HttpClientUtility.IFetch;
1515
type IFetchRequest = HttpClientUtility.IFetchRequest;
1616

@@ -603,6 +603,19 @@ export class ConformanceApiHttpClient implements IConformanceApi {
603603
});
604604
}
605605

606+
public fibonacci(request: IFibonacciRequest, context?: unknown): Promise<IServiceResult<AsyncIterable<IServiceResult<IFibonacciResponse>>>> {
607+
let uri = 'fibonacci';
608+
const query: string[] = [];
609+
request.count == null || query.push('count=' + request.count.toString());
610+
if (query.length) {
611+
uri = uri + '?' + query.join('&');
612+
}
613+
const fetchRequest: IFetchRequest = {
614+
method: 'GET',
615+
};
616+
return HttpClientUtility.createFetchEventStream<IFibonacciResponse>(this._fetch, this._baseUri + uri, fetchRequest, context);
617+
}
618+
606619
private _fetch: IFetch;
607620
private _baseUri: string;
608621
}
Lines changed: 120 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,39 @@
11
import { IServiceError, IServiceResult } from "facility-core";
2-
import { IConformanceApi, IGetApiInfoRequest, IGetApiInfoResponse, IGetWidgetsRequest, IGetWidgetsResponse, ICreateWidgetRequest, ICreateWidgetResponse, IGetWidgetRequest, IGetWidgetResponse, IDeleteWidgetRequest, IDeleteWidgetResponse, IGetWidgetBatchRequest, IGetWidgetBatchResponse, IMirrorFieldsRequest, IMirrorFieldsResponse, ICheckQueryRequest, ICheckQueryResponse, ICheckPathRequest, ICheckPathResponse, IMirrorHeadersRequest, IMirrorHeadersResponse, IMixedRequest, IMixedResponse, IRequiredRequest, IRequiredResponse, IMirrorBytesRequest, IMirrorBytesResponse, IMirrorTextRequest, IMirrorTextResponse, IBodyTypesRequest, IBodyTypesResponse } from "./conformanceApiTypes";
2+
import {
3+
IConformanceApi,
4+
IGetApiInfoRequest,
5+
IGetApiInfoResponse,
6+
IGetWidgetsRequest,
7+
IGetWidgetsResponse,
8+
ICreateWidgetRequest,
9+
ICreateWidgetResponse,
10+
IGetWidgetRequest,
11+
IGetWidgetResponse,
12+
IDeleteWidgetRequest,
13+
IDeleteWidgetResponse,
14+
IGetWidgetBatchRequest,
15+
IGetWidgetBatchResponse,
16+
IMirrorFieldsRequest,
17+
IMirrorFieldsResponse,
18+
ICheckQueryRequest,
19+
ICheckQueryResponse,
20+
ICheckPathRequest,
21+
ICheckPathResponse,
22+
IMirrorHeadersRequest,
23+
IMirrorHeadersResponse,
24+
IMixedRequest,
25+
IMixedResponse,
26+
IRequiredRequest,
27+
IRequiredResponse,
28+
IMirrorBytesRequest,
29+
IMirrorBytesResponse,
30+
IMirrorTextRequest,
31+
IMirrorTextResponse,
32+
IBodyTypesRequest,
33+
IBodyTypesResponse,
34+
IFibonacciRequest,
35+
IFibonacciResponse,
36+
} from "./conformanceApiTypes";
337

438
export type ConformanceApiTest = {
539
test: string;
@@ -14,68 +48,127 @@ export class ConformanceApiService implements IConformanceApi {
1448
this._tests = tests;
1549
}
1650

17-
getApiInfo(request: IGetApiInfoRequest, context?: unknown): Promise<IServiceResult<IGetApiInfoResponse>> {
51+
getApiInfo(
52+
request: IGetApiInfoRequest,
53+
context?: unknown
54+
): Promise<IServiceResult<IGetApiInfoResponse>> {
1855
return this.execute("getApiInfo", request);
1956
}
2057

21-
getWidgets(request: IGetWidgetsRequest, context?: unknown): Promise<IServiceResult<IGetWidgetsResponse>> {
58+
getWidgets(
59+
request: IGetWidgetsRequest,
60+
context?: unknown
61+
): Promise<IServiceResult<IGetWidgetsResponse>> {
2262
return this.execute("getWidgets", request);
2363
}
2464

25-
createWidget(request: ICreateWidgetRequest, context?: unknown): Promise<IServiceResult<ICreateWidgetResponse>> {
65+
createWidget(
66+
request: ICreateWidgetRequest,
67+
context?: unknown
68+
): Promise<IServiceResult<ICreateWidgetResponse>> {
2669
return this.execute("createWidget", request);
2770
}
2871

29-
getWidget(request: IGetWidgetRequest, context?: unknown): Promise<IServiceResult<IGetWidgetResponse>> {
72+
getWidget(
73+
request: IGetWidgetRequest,
74+
context?: unknown
75+
): Promise<IServiceResult<IGetWidgetResponse>> {
3076
return this.execute("getWidget", request);
3177
}
3278

33-
deleteWidget(request: IDeleteWidgetRequest, context?: unknown): Promise<IServiceResult<IDeleteWidgetResponse>> {
79+
deleteWidget(
80+
request: IDeleteWidgetRequest,
81+
context?: unknown
82+
): Promise<IServiceResult<IDeleteWidgetResponse>> {
3483
return this.execute("deleteWidget", request);
3584
}
3685

37-
getWidgetBatch(request: IGetWidgetBatchRequest, context?: unknown): Promise<IServiceResult<IGetWidgetBatchResponse>> {
86+
getWidgetBatch(
87+
request: IGetWidgetBatchRequest,
88+
context?: unknown
89+
): Promise<IServiceResult<IGetWidgetBatchResponse>> {
3890
return this.execute("getWidgetBatch", request);
3991
}
4092

41-
mirrorFields(request: IMirrorFieldsRequest, context?: unknown): Promise<IServiceResult<IMirrorFieldsResponse>> {
93+
mirrorFields(
94+
request: IMirrorFieldsRequest,
95+
context?: unknown
96+
): Promise<IServiceResult<IMirrorFieldsResponse>> {
4297
return this.execute("mirrorFields", request);
4398
}
4499

45-
checkQuery(request: ICheckQueryRequest, context?: unknown): Promise<IServiceResult<ICheckQueryResponse>> {
100+
checkQuery(
101+
request: ICheckQueryRequest,
102+
context?: unknown
103+
): Promise<IServiceResult<ICheckQueryResponse>> {
46104
return this.execute("checkQuery", request);
47105
}
48106

49-
checkPath(request: ICheckPathRequest, context?: unknown): Promise<IServiceResult<ICheckPathResponse>> {
107+
checkPath(
108+
request: ICheckPathRequest,
109+
context?: unknown
110+
): Promise<IServiceResult<ICheckPathResponse>> {
50111
return this.execute("checkPath", request);
51112
}
52113

53-
mirrorHeaders(request: IMirrorHeadersRequest, context?: unknown): Promise<IServiceResult<IMirrorHeadersResponse>> {
114+
mirrorHeaders(
115+
request: IMirrorHeadersRequest,
116+
context?: unknown
117+
): Promise<IServiceResult<IMirrorHeadersResponse>> {
54118
return this.execute("mirrorHeaders", request);
55119
}
56120

57-
mixed(request: IMixedRequest, context?: unknown): Promise<IServiceResult<IMixedResponse>> {
121+
mixed(
122+
request: IMixedRequest,
123+
context?: unknown
124+
): Promise<IServiceResult<IMixedResponse>> {
58125
return this.execute("mixed", request);
59126
}
60127

61-
required(request: IRequiredRequest, context?: unknown): Promise<IServiceResult<IRequiredResponse>> {
128+
required(
129+
request: IRequiredRequest,
130+
context?: unknown
131+
): Promise<IServiceResult<IRequiredResponse>> {
62132
return this.execute("required", request);
63133
}
64134

65-
mirrorBytes(request: IMirrorBytesRequest, context?: unknown): Promise<IServiceResult<IMirrorBytesResponse>> {
135+
mirrorBytes(
136+
request: IMirrorBytesRequest,
137+
context?: unknown
138+
): Promise<IServiceResult<IMirrorBytesResponse>> {
66139
return this.execute("mirrorBytes", request);
67140
}
68141

69-
mirrorText(request: IMirrorTextRequest, context?: unknown): Promise<IServiceResult<IMirrorTextResponse>> {
142+
mirrorText(
143+
request: IMirrorTextRequest,
144+
context?: unknown
145+
): Promise<IServiceResult<IMirrorTextResponse>> {
70146
return this.execute("mirrorText", request);
71147
}
72148

73-
bodyTypes(request: IBodyTypesRequest, context?: unknown): Promise<IServiceResult<IBodyTypesResponse>> {
149+
bodyTypes(
150+
request: IBodyTypesRequest,
151+
context?: unknown
152+
): Promise<IServiceResult<IBodyTypesResponse>> {
74153
return this.execute("bodyTypes", request);
75154
}
76155

77-
private async execute<TRequest, TResponse>(methodName: string, request: TRequest): Promise<IServiceResult<TResponse>> {
78-
const testsWithMethodName = this._tests.filter((x) => x.method === methodName);
156+
fibonacci(
157+
request: IFibonacciRequest,
158+
context?: unknown
159+
): Promise<
160+
IServiceResult<AsyncIterable<IServiceResult<IFibonacciResponse>>>
161+
> {
162+
return this.execute("fibonacci", request);
163+
}
164+
165+
private async execute<TRequest, TResponse>(
166+
methodName: string,
167+
request: TRequest
168+
): Promise<IServiceResult<TResponse>> {
169+
const testsWithMethodName = this._tests.filter(
170+
(x) => x.method === methodName
171+
);
79172

80173
if (testsWithMethodName.length === 0) {
81174
return this.failure({
@@ -96,13 +189,18 @@ export class ConformanceApiService implements IConformanceApi {
96189
}
97190

98191
var testInfo = testsWithMatchingRequest[0];
99-
return testInfo.error ? this.failure(testInfo.error) : this.success(testInfo.response as TResponse);
192+
return testInfo.error
193+
? this.failure(testInfo.error)
194+
: this.success(testInfo.response as TResponse);
100195
}
101196

102-
private success<T>(result: T): IServiceResult<T> { return { value: result }; }
197+
private success<T>(result: T): IServiceResult<T> {
198+
return { value: result };
199+
}
103200

104-
private failure<T>(error: IServiceError): IServiceResult<T> { return { error}; }
201+
private failure<T>(error: IServiceError): IServiceResult<T> {
202+
return { error };
203+
}
105204

106205
private readonly _tests: readonly ConformanceApiTest[];
107-
108206
}

conformance/src/conformanceApiTypes.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export interface IConformanceApi {
4040
mirrorText(request: IMirrorTextRequest, context?: unknown): Promise<IServiceResult<IMirrorTextResponse>>;
4141

4242
bodyTypes(request: IBodyTypesRequest, context?: unknown): Promise<IServiceResult<IBodyTypesResponse>>;
43+
44+
fibonacci(request: IFibonacciRequest, context?: unknown): Promise<IServiceResult<AsyncIterable<IServiceResult<IFibonacciResponse>>>>;
4345
}
4446

4547
/** Request for GetApiInfo. */
@@ -330,6 +332,16 @@ export interface IBodyTypesResponse {
330332
content?: string;
331333
}
332334

335+
/** Request for Fibonacci. */
336+
export interface IFibonacciRequest {
337+
count: number;
338+
}
339+
340+
/** Response for Fibonacci. */
341+
export interface IFibonacciResponse {
342+
value: number;
343+
}
344+
333345
/** A widget. */
334346
export interface IWidget {
335347
/** A unique identifier for the widget. */

conformance/src/fastify/conformanceApiPlugin.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,8 @@ export interface IConformanceApi {
874874
mirrorText(request: IMirrorTextRequest, context?: unknown): Promise<IServiceResult<IMirrorTextResponse>>;
875875

876876
bodyTypes(request: IBodyTypesRequest, context?: unknown): Promise<IServiceResult<IBodyTypesResponse>>;
877+
878+
fibonacci(request: IFibonacciRequest, context?: unknown): Promise<IServiceResult<AsyncIterable<IServiceResult<IFibonacciResponse>>>>;
877879
}
878880

879881
/** Request for GetApiInfo. */
@@ -1164,6 +1166,16 @@ export interface IBodyTypesResponse {
11641166
content?: string;
11651167
}
11661168

1169+
/** Request for Fibonacci. */
1170+
export interface IFibonacciRequest {
1171+
count: number;
1172+
}
1173+
1174+
/** Response for Fibonacci. */
1175+
export interface IFibonacciResponse {
1176+
value: number;
1177+
}
1178+
11671179
/** A widget. */
11681180
export interface IWidget {
11691181
/** A unique identifier for the widget. */

conformance/src/jsConformanceApi.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function createHttpClient(options) {
99
return new JsConformanceApiHttpClient(options);
1010
}
1111

12-
const { fetchResponse, createResponseError, createRequiredRequestFieldError } = HttpClientUtility;
12+
const { fetchResponse, createResponseError, createRequiredRequestFieldError, createFetchEventStream } = HttpClientUtility;
1313

1414
function parseBoolean(value) {
1515
if (typeof value === 'string') {
@@ -599,4 +599,17 @@ export class JsConformanceApiHttpClient {
599599
return { value: value };
600600
});
601601
}
602+
603+
fibonacci(request, context) {
604+
let uri = 'fibonacci';
605+
const query = [];
606+
request.count == null || query.push('count=' + request.count.toString());
607+
if (query.length) {
608+
uri = uri + '?' + query.join('&');
609+
}
610+
const fetchRequest = {
611+
method: 'GET',
612+
};
613+
return createFetchEventStream(this._fetch, this._baseUri + uri, fetchRequest, context);
614+
}
602615
}

0 commit comments

Comments
 (0)