Skip to content

Commit

Permalink
Added SchemaCompiler, TypeProvider, and Logger to types. (#225)
Browse files Browse the repository at this point in the history
* Added SchemaCompiler, TypeProvider, and Logger to types.

* Added tests for schema based type inference.

* Fixed type specifications in tests and added contextconfig to request types.
  • Loading branch information
teastman committed Oct 4, 2022
1 parent 7566a9e commit 66b70eb
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 14 deletions.
55 changes: 43 additions & 12 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
/// <reference types="node" />
import { IncomingMessage, ServerResponse, Server } from 'http';
import { FastifyRequest, FastifyPluginCallback, RawServerBase, RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RequestGenericInterface, ContextConfigDefault, FastifyInstance} from 'fastify';
import { FastifyRequest, FastifyPluginCallback, RawServerBase, RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RequestGenericInterface, ContextConfigDefault, FastifyInstance, FastifySchema, FastifyTypeProvider, FastifyTypeProviderDefault, FastifyBaseLogger } from 'fastify';
import * as fastify from 'fastify';
import * as WebSocket from 'ws';
import { Duplex, DuplexOptions } from 'stream';
import { FastifyReply } from 'fastify/types/reply';
import { RouteGenericInterface } from 'fastify/types/route';

interface WebsocketRouteOptions<RawServer extends RawServerBase = RawServerDefault, RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>, RequestGeneric extends RequestGenericInterface = RequestGenericInterface> {
wsHandler?: WebsocketHandler<RawServer, RawRequest, RequestGeneric>;
interface WebsocketRouteOptions<
RawServer extends RawServerBase = RawServerDefault,
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
RequestGeneric extends RequestGenericInterface = RequestGenericInterface,
ContextConfig = ContextConfigDefault,
SchemaCompiler extends FastifySchema = FastifySchema,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger
> {
wsHandler?: WebsocketHandler<RawServer, RawRequest, RequestGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger>;
}

declare module 'fastify' {
Expand All @@ -31,29 +39,43 @@ declare module 'fastify' {
RawServer extends RawServerBase = RawServerDefault,
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
> {
<RequestGeneric extends RequestGenericInterface = RequestGenericInterface, ContextConfig = ContextConfigDefault>(
<RequestGeneric extends RequestGenericInterface = RequestGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler extends FastifySchema = FastifySchema, Logger extends FastifyBaseLogger = FastifyBaseLogger>(
path: string,
opts: RouteShorthandOptions<RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig> & { websocket: true }, // this creates an overload that only applies these different types if the handler is for websockets
handler?: WebsocketHandler<RawServer, RawRequest, RequestGeneric>
): FastifyInstance<RawServer, RawRequest, RawReply>;
opts: RouteShorthandOptions<RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger> & { websocket: true }, // this creates an overload that only applies these different types if the handler is for websockets
handler?: WebsocketHandler<RawServer, RawRequest, RequestGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger>
): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
}

interface RouteOptions<RawServer extends RawServerBase = RawServerDefault, RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>, RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>, RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault,SchemaCompiler = fastify.FastifySchema> extends WebsocketRouteOptions<RawServer, RawRequest, RouteGeneric> {}
interface RouteOptions<
RawServer extends RawServerBase = RawServerDefault,
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
ContextConfig = ContextConfigDefault,
SchemaCompiler = fastify.FastifySchema,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger
> extends WebsocketRouteOptions<RawServer, RawRequest, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger> { }
}

declare const websocketPlugin: FastifyPluginCallback<WebsocketPluginOptions>;

interface WebSocketServerOptions extends Omit<WebSocket.ServerOptions, "path"> {}
interface WebSocketServerOptions extends Omit<WebSocket.ServerOptions, "path"> { }

export type WebsocketHandler<
RawServer extends RawServerBase = RawServerDefault,
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
RequestGeneric extends RequestGenericInterface = RequestGenericInterface
RequestGeneric extends RequestGenericInterface = RequestGenericInterface,
ContextConfig = ContextConfigDefault,
SchemaCompiler extends FastifySchema = FastifySchema,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger
> = (
this: FastifyInstance<Server, IncomingMessage, ServerResponse>,
connection: SocketStream,
request: FastifyRequest<RequestGeneric, RawServer, RawRequest>,
request: FastifyRequest<RequestGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider, ContextConfig, Logger>
) => void | Promise<any>;

export interface SocketStream extends Duplex {
Expand All @@ -66,6 +88,15 @@ export interface WebsocketPluginOptions {
connectionOptions?: DuplexOptions;
}

export interface RouteOptions<RawServer extends RawServerBase = RawServerDefault, RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>, RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>, RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler extends fastify.FastifySchema = fastify.FastifySchema> extends fastify.RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler>, WebsocketRouteOptions<RawServer, RawRequest, RouteGeneric> {}
export interface RouteOptions<
RawServer extends RawServerBase = RawServerDefault,
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
ContextConfig = ContextConfigDefault,
SchemaCompiler extends fastify.FastifySchema = fastify.FastifySchema,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger
> extends fastify.RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger>, WebsocketRouteOptions<RawServer, RawRequest, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger> { }

export default websocketPlugin;
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
"homepage": "https://github.com/fastify/fastify-websocket#readme",
"devDependencies": {
"@fastify/pre-commit": "^2.0.2",
"@fastify/type-provider-typebox": "^2.3.0",
"@sinclair/typebox": "^0.24.44",
"@types/ws": "^8.2.2",
"fastify": "^4.0.0-rc.2",
"snazzy": "^9.0.0",
Expand Down
95 changes: 93 additions & 2 deletions test/types/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import wsPlugin, { WebsocketHandler, SocketStream } from '../..';
import type {IncomingMessage} from "http";
import fastify, { RouteOptions, FastifyRequest, FastifyInstance, FastifyReply, RequestGenericInterface } from 'fastify';
import type { IncomingMessage } from "http";
import fastify, { RouteOptions, FastifyRequest, FastifyInstance, FastifyReply, RequestGenericInterface, FastifyBaseLogger, RawServerDefault, FastifySchema, RawRequestDefaultExpression, RawServerBase, ContextConfigDefault, RawReplyDefaultExpression } from 'fastify';
import { expectType } from 'tsd';
import { Server } from 'ws';
import { RouteGenericInterface } from 'fastify/types/route';
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
import { Static, Type } from '@sinclair/typebox'
import { ResolveFastifyRequestType } from 'fastify/types/type-provider';

const app: FastifyInstance = fastify();
app.register(wsPlugin);
Expand Down Expand Up @@ -105,3 +108,91 @@ app.route<{ Params: { foo: string }, Body: { bar: string }, Querystring: { searc
expectType<IncomingMessage['headers'] & { auth: string }>(request.headers);
},
});


const schema = {
params: Type.Object({
foo: Type.String()
}),
querystring: Type.Object({
search: Type.String()
}),
body: Type.Object({
bar: Type.String()
}),
headers: Type.Object({
auth: Type.String()
})
};
type SchemaType = {
params: Static<typeof schema.params>;
querystring: Static<typeof schema.querystring>;
body: Static<typeof schema.body>;
headers: Static<typeof schema.headers>;
};

const server = app.withTypeProvider<TypeBoxTypeProvider>();

server.route({
method: 'GET',
url: '/longhand-type-inference',
schema,
handler: (request, _reply) => {
expectType<{ foo: string }>(request.params);
expectType<{ bar: string }>(request.body);
expectType<{ search: string }>(request.query);
expectType<IncomingMessage['headers'] & { auth: string }>(request.headers);
},
wsHandler: (connection, request) => {
expectType<SocketStream>(connection);
expectType<{ foo: string }>(request.params);
expectType<{ bar: string }>(request.body);
expectType<{ search: string }>(request.query);
expectType<IncomingMessage['headers'] & { auth: string }>(request.headers);
},
});

server.get('/websockets-type-inference',
{
websocket: true,
schema
},
async function (connection, request) {
expectType<FastifyInstance>(this);
expectType<SocketStream>(connection);
expectType<Server>(app.websocketServer);
expectType<FastifyRequest<RequestGenericInterface, RawServerDefault, IncomingMessage, SchemaType, TypeBoxTypeProvider, unknown, FastifyBaseLogger>>(request);
expectType<boolean>(request.ws);
expectType<{ foo: string }>(request.params);
expectType<{ bar: string }>(request.body);
expectType<{ search: string }>(request.query);
expectType<IncomingMessage['headers'] & { auth: string }>(request.headers);
});

server.get('/not-websockets-type-inference',
{
websocket: false,
schema
},
async (request, reply) => {
expectType<FastifyRequest<RouteGenericInterface, RawServerDefault, IncomingMessage, SchemaType, TypeBoxTypeProvider, unknown, FastifyBaseLogger, ResolveFastifyRequestType<TypeBoxTypeProvider, FastifySchema, RouteGenericInterface>>>(request);
expectType<FastifyReply<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, SchemaType, TypeBoxTypeProvider>>(reply);
expectType<{ foo: string }>(request.params);
expectType<{ bar: string }>(request.body);
expectType<{ search: string }>(request.query);
expectType<IncomingMessage['headers'] & { auth: string }>(request.headers);
});

server.get('/websockets-no-type-inference',
{ websocket: true },
async function (connection, request) {
expectType<FastifyInstance>(this);
expectType<SocketStream>(connection);
expectType<Server>(app.websocketServer);
expectType<FastifyRequest<RequestGenericInterface, RawServerDefault, RawRequestDefaultExpression, FastifySchema, TypeBoxTypeProvider, unknown, FastifyBaseLogger>>(request);
expectType<boolean>(request.ws);
expectType<unknown>(request.params);
expectType<unknown>(request.body);
expectType<unknown>(request.query);
expectType<IncomingMessage['headers']>(request.headers);
});

0 comments on commit 66b70eb

Please sign in to comment.