Skip to content

Commit 85674fe

Browse files
committed
Refactored type definitions (#1119)
* Updated types generation script * Refactored api method definitions * Updated test - Removed old test code - Added tsd dev dependency - Rewritten test with tsd * Removed unused dependencies * Fixed definition * Updated test * Updated docs * Improved events type definitions * Updated test * Minor fixes in the type definitons * More type test * Improved Transport type definitions * Updated test * Addressed comments * Code generation * Use RequestBody, Response and Context everywhere, also default Context to unknown * Updated test * body -> hasBody * Fixed conflicts * Updated code generation * Improved request body type definition * Updated code generation * Use BodyType for both request and reponses generics - Use extends for defining the RequestBody generic to force the user following the same shape. - BodyType and NDBodyType now accepts a generics to allow injecting more specific types in the future * API generation * Updated test * Updated docs * Use BodyType also in ReponseError * Removed useless client generics * Renamed generics and types - prefixed all generics with a T - BodyType => RequestBody - NDBodyType => RequestNDBody - Added ResponseBody * Updated test * Updated docs * Test ResponseBody as well * Simplify overloads * API generation * Updated test * Updated error types
1 parent 9892d63 commit 85674fe

23 files changed

+4071
-631
lines changed

api/requestParams.d.ts

Lines changed: 308 additions & 100 deletions
Large diffs are not rendered by default.

docs/typescript.asciidoc

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ request for instance, you can access them via `RequestParams.Search`.
1313
Every API that supports a body, accepts a
1414
https://www.typescriptlang.org/docs/handbook/generics.html[generics] which
1515
represents the type of the request body, if you don't configure anything, it
16-
will default to `any`.
16+
will default to `RequestBody`. +
17+
`RequestBody`, along with `RequestNDBody` and `ResponseBody` are defined inside the client, and it looks like this:
18+
[source,ts]
19+
----
20+
type RequestBody<T = Record<string, any>> = T | string | Buffer | ReadableStream
21+
type RequestNDBody<T = Record<string, any>[]> = T | string[] | Buffer | ReadableStream
22+
type ResponseBody<T = Record<string, any>> = T | string | boolean | ReadableStream
23+
----
1724

1825
For example:
1926

@@ -49,7 +56,7 @@ const searchParams: RequestParams.Search = {
4956

5057
You can find the type definiton of a response in `ApiResponse`, which accepts a
5158
generics as well if you want to specify the body type, otherwise it defaults to
52-
`any`.
59+
`BodyType`.
5360

5461
[source,ts]
5562
----
@@ -137,19 +144,43 @@ interface Source {
137144
foo: string
138145
}
139146
140-
async function run (): Promise<void> {
141-
// Define the search parameters
142-
const searchParams: RequestParams.Search<SearchBody> = {
147+
async function run () {
148+
// All of the examples below are valid code, by default,
149+
// the request body will be `RequestBody` and response will be `ResponseBody`.
150+
const response = await client.search({
143151
index: 'test',
144152
body: {
145153
query: {
146154
match: { foo: 'bar' }
147155
}
148156
}
149-
}
157+
})
158+
// body here is `ResponseBody`
159+
console.log(response.body)
150160
151-
// Craft the final type definition
152-
const response: ApiResponse<SearchResponse<Source>> = await client.search(searchParams)
161+
// The first generic is the request body
162+
const response = await client.search<SearchBody>({
163+
index: 'test',
164+
// Here the body must follow the `SearchBody` interface
165+
body: {
166+
query: {
167+
match: { foo: 'bar' }
168+
}
169+
}
170+
})
171+
// body here is `ResponseBody`
172+
console.log(response.body)
173+
174+
const response = await client.search<SearchBody, SearchResponse<Source>>({
175+
index: 'test',
176+
// Here the body must follow the `SearchBody` interface
177+
body: {
178+
query: {
179+
match: { foo: 'bar' }
180+
}
181+
}
182+
})
183+
// Now you can have full type definition of the response
153184
console.log(response.body)
154185
}
155186

index.d.ts

Lines changed: 2295 additions & 258 deletions
Large diffs are not rendered by default.

lib/Connection.d.ts

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,43 @@
55
/// <reference types="node" />
66

77
import { URL } from 'url';
8-
import { inspect, InspectOptions } from 'util';
8+
import { inspect, InspectOptions } from 'util'
9+
import { Readable as ReadableStream } from 'stream';
910
import { ApiKeyAuth, BasicAuth } from './pool'
10-
import * as http from 'http';
11-
import { ConnectionOptions as TlsConnectionOptions } from 'tls';
11+
import * as http from 'http'
12+
import { ConnectionOptions as TlsConnectionOptions } from 'tls'
1213

1314
export declare type agentFn = () => any;
1415

1516
interface ConnectionOptions {
1617
url: URL;
1718
ssl?: TlsConnectionOptions;
1819
id?: string;
19-
headers?: any;
20+
headers?: Record<string, any>;
2021
agent?: AgentOptions | agentFn;
2122
status?: string;
22-
roles?: any;
23+
roles?: ConnectionRoles;
2324
auth?: BasicAuth | ApiKeyAuth;
2425
}
2526

27+
interface ConnectionRoles {
28+
master?: boolean
29+
data?: boolean
30+
ingest?: boolean
31+
ml?: boolean
32+
}
33+
2634
interface RequestOptions extends http.ClientRequestArgs {
2735
asStream?: boolean;
28-
body?: any;
36+
body?: string | Buffer | ReadableStream;
2937
querystring?: string;
3038
}
3139

3240
export interface AgentOptions {
33-
keepAlive: boolean;
34-
keepAliveMsecs: number;
35-
maxSockets: number;
36-
maxFreeSockets: number;
41+
keepAlive?: boolean;
42+
keepAliveMsecs?: number;
43+
maxSockets?: number;
44+
maxFreeSockets?: number;
3745
}
3846

3947
export default class Connection {
@@ -47,27 +55,26 @@ export default class Connection {
4755
INGEST: string;
4856
ML: string;
4957
};
50-
url: URL;
51-
ssl: TlsConnectionOptions | null;
52-
id: string;
53-
headers: any;
54-
deadCount: number;
55-
resurrectTimeout: number;
56-
statuses: any;
57-
roles: any;
58-
makeRequest: any;
59-
_openRequests: number;
60-
_status: string;
61-
_agent: http.Agent;
62-
constructor(opts?: ConnectionOptions);
63-
request(params: RequestOptions, callback: (err: Error | null, response: http.IncomingMessage | null) => void): http.ClientRequest;
64-
close(): Connection;
65-
setRole(role: string, enabled: boolean): Connection;
66-
status: string;
67-
buildRequestObject(params: any): http.ClientRequestArgs;
58+
url: URL
59+
ssl: TlsConnectionOptions | null
60+
id: string
61+
headers: Record<string, any>
62+
status: string
63+
roles: ConnectionRoles
64+
deadCount: number
65+
resurrectTimeout: number
66+
makeRequest: any
67+
_openRequests: number
68+
_status: string
69+
_agent: http.Agent
70+
constructor(opts?: ConnectionOptions)
71+
request(params: RequestOptions, callback: (err: Error | null, response: http.IncomingMessage | null) => void): http.ClientRequest
72+
close(): Connection
73+
setRole(role: string, enabled: boolean): Connection
74+
buildRequestObject(params: any): http.ClientRequestArgs
6875
// @ts-ignore
69-
[inspect.custom](object: any, options: InspectOptions): string;
70-
toJSON(): any;
76+
[inspect.custom](object: any, options: InspectOptions): string
77+
toJSON(): any
7178
}
7279

7380
export {};

lib/Transport.d.ts

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,16 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
import { Readable as ReadableStream } from 'stream';
56
import { ConnectionPool, CloudConnectionPool } from './pool';
67
import Connection from './Connection';
78
import Serializer from './Serializer';
9+
import * as errors from './errors';
10+
11+
export type ApiError = errors.ConfigurationError | errors.ConnectionError |
12+
errors.DeserializationError | errors.SerializationError |
13+
errors.NoLivingConnectionsError | errors.ResponseError |
14+
errors.TimeoutError
815

916
export interface nodeSelectorFn {
1017
(connections: Connection[]): Connection;
@@ -18,36 +25,33 @@ export interface generateRequestIdFn {
1825
(params: TransportRequestParams, options: TransportRequestOptions): any;
1926
}
2027

21-
declare type noopFn = (...args: any[]) => void;
22-
declare type emitFn = (event: string | symbol, ...args: any[]) => boolean;
23-
2428
interface TransportOptions {
25-
emit: emitFn & noopFn;
29+
emit: (event: string | symbol, ...args: any[]) => boolean;
2630
connectionPool: ConnectionPool | CloudConnectionPool;
2731
serializer: Serializer;
2832
maxRetries: number;
2933
requestTimeout: number | string;
30-
suggestCompression: boolean;
34+
suggestCompression?: boolean;
3135
compression?: 'gzip';
32-
sniffInterval: number;
33-
sniffOnConnectionFault: boolean;
36+
sniffInterval?: number;
37+
sniffOnConnectionFault?: boolean;
3438
sniffEndpoint: string;
35-
sniffOnStart: boolean;
39+
sniffOnStart?: boolean;
3640
nodeFilter?: nodeFilterFn;
3741
nodeSelector?: string | nodeSelectorFn;
38-
headers?: anyObject;
42+
headers?: Record<string, any>;
3943
generateRequestId?: generateRequestIdFn;
40-
name: string;
44+
name?: string;
4145
opaqueIdPrefix?: string;
4246
}
4347

44-
export interface RequestEvent<T = any, C = any> {
45-
body: T;
48+
export interface RequestEvent<TResponse = ResponseBody, TContext = unknown> {
49+
body: TResponse;
4650
statusCode: number | null;
47-
headers: anyObject | null;
51+
headers: Record<string, any> | null;
4852
warnings: string[] | null;
4953
meta: {
50-
context: C;
54+
context: TContext;
5155
name: string;
5256
request: {
5357
params: TransportRequestParams;
@@ -66,31 +70,31 @@ export interface RequestEvent<T = any, C = any> {
6670

6771
// ApiResponse and RequestEvent are the same thing
6872
// we are doing this for have more clear names
69-
export interface ApiResponse<T = any, C = any> extends RequestEvent<T, C> {}
73+
export interface ApiResponse<TResponse = ResponseBody, TContext = unknown> extends RequestEvent<TResponse, TContext> {}
7074

71-
declare type anyObject = {
72-
[key: string]: any;
73-
};
75+
export type RequestBody<T = Record<string, any>> = T | string | Buffer | ReadableStream
76+
export type RequestNDBody<T = Record<string, any>[]> = T | string[] | Buffer | ReadableStream
77+
export type ResponseBody<T = Record<string, any>> = T | string | boolean | ReadableStream
7478

7579
export interface TransportRequestParams {
7680
method: string;
7781
path: string;
78-
body?: anyObject;
79-
bulkBody?: anyObject;
80-
querystring?: anyObject;
82+
body?: RequestBody;
83+
bulkBody?: RequestNDBody;
84+
querystring?: Record<string, any>;
8185
}
8286

8387
export interface TransportRequestOptions {
8488
ignore?: number[];
8589
requestTimeout?: number | string;
8690
maxRetries?: number;
8791
asStream?: boolean;
88-
headers?: anyObject;
89-
querystring?: anyObject;
90-
compression?: string;
92+
headers?: Record<string, any>;
93+
querystring?: Record<string, any>;
94+
compression?: 'gzip';
9195
id?: any;
9296
context?: any;
93-
warnings?: [string];
97+
warnings?: string[];
9498
opaqueId?: string;
9599
}
96100

@@ -114,7 +118,7 @@ export default class Transport {
114118
SNIFF_ON_CONNECTION_FAULT: string;
115119
DEFAULT: string;
116120
};
117-
emit: emitFn & noopFn;
121+
emit: (event: string | symbol, ...args: any[]) => boolean;
118122
connectionPool: ConnectionPool | CloudConnectionPool;
119123
serializer: Serializer;
120124
maxRetries: number;
@@ -130,9 +134,7 @@ export default class Transport {
130134
_isSniffing: boolean;
131135
constructor(opts: TransportOptions);
132136
request(params: TransportRequestParams, options?: TransportRequestOptions): Promise<ApiResponse>;
133-
request(params: TransportRequestParams, options?: TransportRequestOptions, callback?: (err: Error | null, result: ApiResponse) => void): TransportRequestCallback;
137+
request(params: TransportRequestParams, options?: TransportRequestOptions, callback?: (err: ApiError, result: ApiResponse) => void): TransportRequestCallback;
134138
getConnection(opts: TransportGetConnectionOptions): Connection | null;
135139
sniff(opts?: TransportSniffOptions, callback?: (...args: any[]) => void): void;
136140
}
137-
138-
export {};

lib/errors.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5-
import { ApiResponse } from './Transport'
5+
import { ApiResponse, ResponseBody } from './Transport'
66

77
export declare class ElasticsearchClientError extends Error {
88
name: string;
@@ -33,8 +33,8 @@ export declare class NoLivingConnectionsError extends ElasticsearchClientError {
3333
export declare class SerializationError extends ElasticsearchClientError {
3434
name: string;
3535
message: string;
36-
data: object;
37-
constructor(message: string, data: object);
36+
data: any;
37+
constructor(message: string, data: any);
3838
}
3939

4040
export declare class DeserializationError extends ElasticsearchClientError {
@@ -54,8 +54,8 @@ export declare class ResponseError extends ElasticsearchClientError {
5454
name: string;
5555
message: string;
5656
meta: ApiResponse;
57-
body: any;
57+
body: ResponseBody;
5858
statusCode: number;
59-
headers: any;
59+
headers: Record<string, any>;
6060
constructor(meta: ApiResponse);
6161
}

lib/pool/index.d.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
/// <reference types="node" />
66

7+
import { URL } from 'url'
78
import { SecureContextOptions } from 'tls';
89
import Connection, { AgentOptions } from '../Connection';
910
import { nodeFilterFn, nodeSelectorFn } from '../Transport';
@@ -13,14 +14,12 @@ interface BaseConnectionPoolOptions {
1314
agent?: AgentOptions;
1415
auth?: BasicAuth | ApiKeyAuth;
1516
emit: (event: string | symbol, ...args: any[]) => boolean;
16-
pingTimeout?: number;
1717
Connection: typeof Connection;
18-
resurrectStrategy?: string;
1918
}
2019

2120
interface ConnectionPoolOptions extends BaseConnectionPoolOptions {
2221
pingTimeout?: number;
23-
resurrectStrategy?: string;
22+
resurrectStrategy?: 'ping' | 'optimistic' | 'none';
2423
sniffEnabled?: boolean;
2524
}
2625

@@ -65,6 +64,8 @@ interface ResurrectEvent {
6564

6665
declare class BaseConnectionPool {
6766
connections: Connection[];
67+
size: number;
68+
emit: (event: string | symbol, ...args: any[]) => boolean;
6869
_ssl: SecureContextOptions | null;
6970
_agent: AgentOptions | null;
7071
auth: BasicAuth | ApiKeyAuth;
@@ -137,7 +138,7 @@ declare class BaseConnectionPool {
137138
* @param {string} url
138139
* @returns {object} host
139140
*/
140-
urlToHost(url: string): any;
141+
urlToHost(url: string): { url: URL };
141142
}
142143

143144
declare class ConnectionPool extends BaseConnectionPool {
@@ -167,7 +168,7 @@ declare class ConnectionPool extends BaseConnectionPool {
167168
declare class CloudConnectionPool extends BaseConnectionPool {
168169
cloudConnection: Connection | null
169170
constructor(opts?: BaseConnectionPoolOptions);
170-
getConnection(): Connection;
171+
getConnection(): Connection | null;
171172
}
172173

173174
declare function defaultNodeFilter(node: Connection): boolean;

0 commit comments

Comments
 (0)