@@ -21,46 +21,59 @@ export type { ResponseEncoder } from './response';
2121const isHttpVerb = ( verb : string ) : verb is 'get' | 'put' | 'post' | 'delete' =>
2222 verb === 'get' || verb === 'put' || verb === 'post' || verb === 'delete' ;
2323
24- export const createServerWithResponseEncoder =
25- ( encoder : ResponseEncoder ) =>
26- < Spec extends ApiSpec > (
27- spec : ApiSpec ,
28- configureExpressApplication : ( app : express . Application ) => {
29- [ ApiName in keyof Spec ] : {
30- [ Method in keyof Spec [ ApiName ] ] : RouteHandler < Spec [ ApiName ] [ Method ] > ;
31- } ;
32- } ,
33- ) => {
34- const app : express . Application = express ( ) ;
35- const routes = configureExpressApplication ( app ) ;
36-
37- const router = express . Router ( ) ;
38- for ( const apiName of Object . keys ( spec ) ) {
39- const resource = spec [ apiName ] as Spec [ string ] ;
40- for ( const method of Object . keys ( resource ) ) {
41- if ( ! isHttpVerb ( method ) ) {
42- continue ;
43- }
44- const httpRoute : HttpRoute = resource [ method ] ! ;
45- const routeHandler = routes [ apiName ] ! [ method ] ! ;
46- const expressRouteHandler = decodeRequestAndEncodeResponse (
47- apiName ,
48- httpRoute ,
49- // FIXME: TS is complaining that `routeHandler` is not necessarily guaranteed to be a
50- // `ServiceFunction`, because subtypes of Spec[string][string] can have arbitrary extra keys.
51- getServiceFunction ( routeHandler as any ) ,
52- encoder ,
53- ) ;
54- const handlers = [ ...getMiddleware ( routeHandler ) , expressRouteHandler ] ;
24+ type CreateRouterProps < Spec extends ApiSpec > = {
25+ spec : Spec ;
26+ routeHandlers : {
27+ [ ApiName in keyof Spec ] : {
28+ [ Method in keyof Spec [ ApiName ] ] : RouteHandler < Spec [ ApiName ] [ Method ] > ;
29+ } ;
30+ } ;
31+ encoder ?: ResponseEncoder ;
32+ } ;
5533
56- const expressPath = apiTsPathToExpress ( httpRoute . path ) ;
57- router [ method ] ( expressPath , handlers ) ;
34+ export function routerForApiSpec < Spec extends ApiSpec > ( {
35+ spec,
36+ routeHandlers,
37+ encoder = defaultResponseEncoder ,
38+ } : CreateRouterProps < Spec > ) {
39+ const router = express . Router ( ) ;
40+ for ( const apiName of Object . keys ( spec ) ) {
41+ const resource = spec [ apiName ] as Spec [ string ] ;
42+ for ( const method of Object . keys ( resource ) ) {
43+ if ( ! isHttpVerb ( method ) ) {
44+ continue ;
5845 }
59- }
46+ const httpRoute : HttpRoute = resource [ method ] ! ;
47+ const routeHandler = routeHandlers [ apiName ] ! [ method ] ! ;
48+ const expressRouteHandler = decodeRequestAndEncodeResponse (
49+ apiName ,
50+ httpRoute ,
51+ // FIXME: TS is complaining that `routeHandler` is not necessarily guaranteed to be a
52+ // `ServiceFunction`, because subtypes of Spec[string][string] can have arbitrary extra keys.
53+ getServiceFunction ( routeHandler as any ) ,
54+ encoder ,
55+ ) ;
56+ const handlers = [ ...getMiddleware ( routeHandler ) , expressRouteHandler ] ;
6057
61- app . use ( router ) ;
58+ const expressPath = apiTsPathToExpress ( httpRoute . path ) ;
59+ router [ method ] ( expressPath , handlers ) ;
60+ }
61+ }
6262
63- return app ;
64- } ;
63+ return router ;
64+ }
6565
66- export const createServer = createServerWithResponseEncoder ( defaultResponseEncoder ) ;
66+ export const createServer = < Spec extends ApiSpec > (
67+ spec : Spec ,
68+ configureExpressApplication : ( app : express . Application ) => {
69+ [ ApiName in keyof Spec ] : {
70+ [ Method in keyof Spec [ ApiName ] ] : RouteHandler < Spec [ ApiName ] [ Method ] > ;
71+ } ;
72+ } ,
73+ ) => {
74+ const app = express ( ) ;
75+ const routeHandlers = configureExpressApplication ( app ) ;
76+ const router = routerForApiSpec ( { spec, routeHandlers } ) ;
77+ app . use ( router ) ;
78+ return app ;
79+ } ;
0 commit comments