Skip to content

Commit

Permalink
feature(http): allow to resolve parameter resolver from parent modules
Browse files Browse the repository at this point in the history
fixes #335
  • Loading branch information
marcj committed Aug 1, 2022
1 parent c94175b commit c3242b9
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 12 deletions.
20 changes: 14 additions & 6 deletions packages/http/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
ReflectionFunction,
ReflectionKind,
ReflectionParameter,
resolveReceiveType,
SerializationOptions,
serializer,
Serializer,
Expand Down Expand Up @@ -751,10 +752,10 @@ export class HttpRouter {

setParameters.push(`${parameterResolverFoundVar} = false;`);

const resolver = routeConfig.resolverForParameterName.get(parameter.getName()) || routeConfig.resolverForToken.get(injectorToken);
const resolverType = routeConfig.resolverForParameterName.get(parameter.getName()) || routeConfig.resolverForToken.get(injectorToken);

//make sure all parameter values from the path are available
if (resolver && !setParametersFromPath) {
if (resolverType && !setParametersFromPath) {
for (const i in parsedRoute.pathParameterNames) {
setParametersFromPath += `parameters.${i} = _match[${1 + parsedRoute.pathParameterNames[i]}];`;
}
Expand All @@ -763,14 +764,21 @@ export class HttpRouter {
let injector = '_injector';
const moduleVar = routeConfig.module ? ', ' + compiler.reserveConst(routeConfig.module, 'module') : '';

if (resolver) {
const resolverProvideTokenVar = compiler.reserveVariable('resolverProvideToken', resolver);
if (resolverType) {
requiresAsyncParameters = true;
let instanceFetcher = '';
if (routeConfig.module && routeConfig.module.injector) {
const resolverResolverVar = compiler.reserveVariable('resolverProvideToken', routeConfig.module.injector.createResolver(resolveReceiveType(resolverType)));
instanceFetcher = `${resolverResolverVar}(${injector}.scope)`;
} else {
const resolverProvideTokenVar = compiler.reserveVariable('resolverProvideToken', resolverType);
instanceFetcher = `${injector}.get(${resolverProvideTokenVar}${moduleVar})`;
}
const instance = compiler.reserveVariable('resolverInstance');

setParameters.push(`
//resolver ${getClassName(resolver)} for ${parameter.getName()}
${instance} = ${injector}.get(${resolverProvideTokenVar}${moduleVar});
//resolver ${getClassName(resolverType)} for ${parameter.getName()}
${instance} = ${instanceFetcher};
if (!${parameterResolverFoundVar}) {
${parameterResolverFoundVar} = true;
parameters.${parameter.parameter.name} = await ${instance}.resolve({
Expand Down
42 changes: 36 additions & 6 deletions packages/http/tests/parameter-resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { App, AppModule } from '@deepkit/app';
import { expect, jest, test } from '@jest/globals';
import { http } from '../src/decorator';
import { HttpRequest } from '../src/model';
import {
RouteConfig,
RouteParameterResolver,
RouteParameterResolverContext,
} from '../src/router';
import { RouteConfig, RouteParameterResolver, RouteParameterResolverContext, } from '../src/router';
import { createHttpKernel } from './utils';
import { HttpModule } from '../src/module.js';
import { HttpKernel } from '../src/kernel.js';

test('parameter resolver by name', async () => {
class Resolver implements RouteParameterResolver {
Expand All @@ -18,7 +17,8 @@ test('parameter resolver by name', async () => {
@http.controller()
class Controller {
@http.GET().resolveParameterByName('value', Resolver)
route(value: unknown) {}
route(value: unknown) {
}
}

jest.spyOn(Resolver.prototype, 'resolve');
Expand All @@ -39,3 +39,33 @@ test('parameter resolver by name', async () => {
expect(Resolver.prototype.resolve).toHaveBeenCalledWith(expectedContext);
expect(Controller.prototype.route).toHaveBeenCalledWith('value');
});

test('parameter resolver can be retrieved from parent module', async () => {
class Resolver implements RouteParameterResolver {
resolve(context: RouteParameterResolverContext) {
return 'value';
}
}

@http.controller()
class Controller {
@http.GET().resolveParameterByName('value', Resolver)
route(value: unknown) {
return value;
}
}

const module = new AppModule({
controllers: [Controller],
});

const app = new App({
providers: [Resolver],
imports: [module, new HttpModule()],
});

const kernel = app.get(HttpKernel);

const response = await kernel.request(HttpRequest.GET('/'));
expect(response.json).toBe('value');
});

0 comments on commit c3242b9

Please sign in to comment.