Hi,
It's possible to inherit parent controller methods? I tried to create kind of RestController
with CRUD methods, but the child seems to not get any of them.
Any idea?
There is no such thing as a "parent controller" in Nest; you can't extend another controller with the expectation of inheriting the routes. Can you share your use case?
Hi @cojack,
Example would be helpful 馃檪
export class RestController {
@Get('/')
async findAll() {
return [];
}
}
@Controller('/someurl')
export class SomeController extends RestController {
}
Some url for me should have @GET at /someurl but it doesn't. Any idea how to implement this kind of thing?
Hi
I need this feature ,too.
Seems to me that it would be really hard to have a clue which routes ends up in the extending controller.
By the way why do you want to do such a thing ?
Maybe an interface would be a better option but I don't know if it would be really reusable.
No, interfaces would not be reusable. Really, by nature controllers should not be extendable. My recommendation would be to put the functionality in a component, and reuse it in your controllers.
Hi 馃檪
I'm also not convinced to make controllers extending possibly. Hope you'll forgive me @cojack 馃檪
I have this exact use case and was surprised to find it didn't work. A more concrete example (Using TypeORM):
export abstract class EntityController<T> {
constructor(protected readonly service: EntityService<T>) { }
@Get()
async findAll() {
return this.service.findAll();
}
@Get(':id')
async getById(@Param() params) {
return this.service.getById(params.id);
}
@Post()
async create(@Body() data: Partial<T>) {
return this.service.create(data);
}
}
Every single one of my TypeORM entities should expose basically the same restful CRUD interface and, using generics, be type safe about the underlying Entity model. I've already done this with the service that wraps the typeorm repository (EntityService
// ThingService extends EntityService<Thing>
@ApiUseTags('things')
@Controller('things')
export class ThingController extends EntityController<Thing> {
constructor(private readonly thingService: ThingService) { super(thingService) }
}
This seems like a perfectly valid pattern to me, and one which will save me tons of boilerplate/copy and pasting. None of the essential CRUD logic differs between any of my entities. And, if it did, the most appropriate place to handle it would be the Service or Middleware/Interceptors/Pipes/Guards, not the controller. The value of REST is that the interface is based on the shape of the state being transferred and a set of known verbs. The verbs don't change between controllers and the shape of the state is determined by the generic type argument.
If there is a limitation or difficulty in supporting this pattern I understand not being willing to support it. But to say there isn't a valid use case is unfair.
This feature is available since v4.6.0
馃帀
@kamilmysliwiec HELL YEAH! You don't even know how much work u've saved for me!
Thanks for getting this in, but I'm running into an issue where the Swagger UI isn't picking up the model objects for each endpoint. Making requests works fine, but the Swagger UI shows nothing under the "Example Value" and "Model" in the documentation.
Is this related to this issue https://github.com/nestjs/swagger/issues/41 or am I just misconfiguring the generic controller?
@jgj, @omar do you have an example project of using generics , nestjs and typeorm ? I'm wanting to ditch loopback and are evaluating various frameworks
Dear @kamilmysliwiec, @cojack could you provide some sample on that?
Controller inheritance does not work for me using v5.1.0.
Routes are correctly mapped to function calls, but any other decorator is omitted. Is this expected behavior or am I doing something wrong here?
export class ParentController<T> {
constructor(public service: Service) {}
@Patch('/:id')
@UseInterceptors(Interceptor1, Interceptor2)
public update(@Body() dto: UpdateDto): Promise<T> {
return this.service.update(dto);
}
}
@Controller('my-route')
export class ChildController extends ParentController<ChildResource> {
constructor(private _service: ChildService) {
super(_service);
}
}
If I call PATCH /my-route/:id
, then the interceptors are never called, but the update function is executed.
This could possibly be fixed in #907. I will let you know when I've tested it :-)
I can confirm that #907 fixes my controller inheritance issue thx 馃憤 馃憤
First of all, amazing library. Blew my mind when I learned of it at AngularMix and I'm now having a blast playing with it.
Is the expectation that, given
export class EntityController<EntityType> {
protected abstract _repository: Repository<EntityType>
@Get()
public async list() {
return this._repository.list()
}
// [...]
}
I should be able to create
@Controller('foo')
export class FooController extends EntityController<Foo> {
constructor(
@Inject(FooRepository) protected _repository: Repository<Foo>,
@Inject(SomeService) private _someService: SomeService
) { super() }
@Get()
public async list() {
return this._someService.specialList()
}
}
and the @Get()
metadata from EntityController#list
will be safely overridden?
@kamilmysliwiec in same case like @bitflut's example i'm trying to create default CRUD controller for my entities. And want to ask about dto validation.
My version:
export class CRUDController<T extends BaseEntity, DTO extends DeepPartial<T>> {
constructor(protected readonly crudService: CRUDService<T>) {}
@Post()
public create(@Body() data: DTO): Promise<T> {
return this.crudService.create(data);
}
}
@Controller('example')
export class ExampleController extends CRUDController<ExampleEntity, ExampleDto> {
constructor(protected readonly exampleService: ExampleService) {
super(exampleService);
}
}
In this case i want to use generic type DTO for validation but like i understood it needs to be a class, not type.
Is there any way to validate request body?
@iofedurin have you found the solution to pass the DTO?
I am struggling with this right now and so far no solution.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
This feature is available since
v4.6.0
馃帀