Is it ok to use controller and graphql resolver together in nestJs? - nestjs

For my next project I would like to use Graphql inside the FrontEnd. Furthermore this project should also offer a Rest-Api.
Now I have discovered this extremely great framework "nestjs", where it is theoretically possible to combine a Graphql endpoint and a rest endpoint.
Unfortunately I can't find anything in the documentation if this can lead to problems. Is the following code usable without problems?
Artikel controller:
#Controller('article')
#Resolver('Article')
export class ArticleController {
constructor(private articleService: ArticleService){}
#Get()
#Query(returns => CArticle)
async Article() {
const dbElement=await this.articleService.getById("xy");
return dbElement;
}
}
Article module:
#Module({
controllers:[ArticleController],
providers:[ArticleService,ArticleController]
})
export class ArticleModule {}

As this would work in this specific example, it may not work well in other use cases you may reach.
In my experience with using both Rest and gRPC - there are eventually different things that the controllers need to take care of.
I would highly recommend having dedicated controllers/resolvers for each API - with these taking care of API entry (i.e. authenticating, taking care of context) and having the Business Logic in a separate Provider.
So your example would look like so:
Article.controller.ts:
#Controller('article')
export class ArticleController {
constructor(private articleService: ArticleService){}
#Get()
async Article() {
return this.articleService.getById("xy");
}
}
Article.resolver.ts:
#Resolver('Article')
export class ArticleResolver {
constructor(private articleService: ArticleService){}
#Query(returns => CArticle)
async Article() {
return this.articleService.getById("xy");
}
}
Article.module.ts:
#Module({
controllers:[ArticleController, ArticleResolver],
providers:[ArticleService]
})
export class ArticleModule {}

As I understand nestjs now, there should be no problems, as the decorators do not change the code but only create new code.

Related

MIssing TERMINUS_ERROR_LOGGER argument/dependency - NestJS HealthCheck controller

I'm trying to implement a simple HealtCheck controller in my NestJS api by following the offical example Healthchecks (Terminus): https://docs.nestjs.com/recipes/terminus#setting-up-a-healthcheck but I'm getting this error:
Nest can't resolve dependencies of the HealthCheckService (HealthCheckExecutor, ?). Please make sure that the argument TERMINUS_ERROR_LOGGER at index [1] is available in the HealthCheckModule context.
Since TERMINUS_ERROR_LOGGER seems like some kind of a enum, I'm not able to import it or add it as a provider inside my HealthModule and I haven't found any documentation/blog/post related to this.
Here's my HealthCHeck controller code:
import { Controller, Get } from '#nestjs/common';
import { HealthCheckService, HttpHealthIndicator, HealthCheck, TypeOrmHealthIndicator } from '#nestjs/terminus';
#Controller('health-check')
export class HealthCheckController {
constructor(
private readonly health: HealthCheckService,
private db: TypeOrmHealthIndicator,
) { }
#Get()
#HealthCheck()
readiness() {
return this.health.check([
async () => this.db.pingCheck('postgres', { timeout: 300 }),
]);
}
}
I just want to create a HealtCheck controller to check if the api is connected to my db and implement future health checks.

NestJS - How to add a dynamic routing to the controller?

I have the following problem. Let's say I have an array of routes & paths to static resources, e.g.
const routes = [{ url: '/', path: 'assets/www' }]
What I would like to do is to create a set of dynamic routes to serve static resources. In express application I would do smth like:
const router = express.Router();
routes.forEach(route => {
router.use(route.url, express.static(path.join(__dirname, route.path)))
})
But is it possible to create such a logic inside a NestJS controller?
#Controller()
export class ItemsController {
constructor() {}
#Get()
findAll() {}
#Get(':id')
findOne() {}
....
}
As far as I can see all HTTP request handlers should be predefined using the corresponding decorators.
I would opt for an approach where you create your controllers fully dynamic. This is not natively supported in Nest, but you can actually create dynamic controllers and dynamic services using a mixin approach (what is actually quite common), also see this answer at GitHub:
import { Post, Get, Controller } from '#nestjs/common';
interface Options {
basePath: string
entityName: string // you could even pass down DTO classes here, for maximum flexibility.
providerName: string
}
// this service is generated dynamically as well
// preferably use a custom providerName.
interface DynamicService {
foo: () => void
bar: () => void
}
export const createDynamicController = (controllerOptions: Options) => {
#Controller(controllerOptions.basePath)
class MyController {
constructor(
#Inject(options.providerName) myProvider: DynamicProvider
){}
#Get(options.entityName)
findOne(){
return this.myProvider.foo()
}
#Post(options.entityName)
create(){
return this.myProvider.foo()
}
}
return MyController
}
Using that approach you can create all controllers in theory dynamically, but it asks a bit more about understanding of the NestJS dependency tree.
You can now create the controller like:
{
controllers: [createDynamicController({
basePath: 'foo',
entityName: 'barz',
providerName: 'custom-provider-name'
})
]
}
What you could do is have a dynamic controller -> with say Parameters identifiers -> the as if it were like an event handler id... (not really just using that as an way to think of the process.)
Then in your the connected service -> you can have the 5 crud operations however in your service you inject the static resources -> and use that Identifier to route the call.
query dto
export class QueryDto {
readonly params?: any[];
readonly body: any;
}
controller
#Post(':serviceId')
async create(#Param('serviceId') serviceId: string, #Body() queryDto: QueryDto) {
return await this.rootService.create(serviceId, queryDto);
}
inside your root service
// childService = used to route the request dynamically ->
// body = your body or if you dont need a body this is where any parameters would go. which is why it's any (for if it was a get)
// params last => incase your doing a put or something where you need a body and parameters -> but it also allows it to be optional.
async create(childService: string, data: any, params: any[]): Promise<any> {
if (!id) {
return await this[childService].create(data.body, ...data.params).exec()
}
just an idea, but if everything static then this should do it for you. just use the root service as a passthrough. from the single controller -> to the various services.

Is there a way to get request context within a decorator in Nest JS

I am trying to build a decorator to "log" request info
export const Tracking = () => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const method = descriptor.value;
descriptor.value = async function(...args: any[]) {
console.log(/** Request info */)
console.log(/** Headers, Body, Method, URL...*/)
return method.call(this, ...args);
}
}
}
and try to use it on a controller method like this.
export class Controller {
#Get('/path')
#Tracking()
public async getData(#Headers('user') user: User) {
return this.service.getData(user.id);
}
}
If this is impossible, is there a way to apply interceptor to some method of controller?
Or is there a thread(like)-level context for request?
Thanks!!
Decorators don't have access to the request information because of what a decorator is. It's a higher order function that is called to set metadata for the class, class member, class method, or class method parameter. This metadata can be read at runtime, but it is called and set essentially as soon the file is imported. Due to this, there's no way to call a decorator on each request, even Nest's #Body() and #Req() are called at the time of import and read at the time of the request (actually earlier but that's besides the point).
What you're looking for here sounds more like an interceptor, like Micael Levi and hoangdv have already mentioned. The Nest docs show a basic logging example, and there are packages out there like #ogma/nestjs-module (disclaimer: I'm the author) that handle this request logging/tracking for you including the addition of correlation IDs.

Two endpoints for same controller (route aliases) in NestJS

I want to change an entity name from Person to Individual. I want to keep the old /person endpoint (for temporary backward compatibility) and add a new /individual endpoint.
What would be the easiest way to do it in Node.js using Nest?
I can copy the code but I'm hoping for a better solution that won't require duplication
The #Controller() decorator accepts an array of prefix, thus you can use like this:
import { Controller, Get } from '#nestjs/common';
#Controller(['person', 'individual'])
export class IndividualController {
#Get()
findAll(): { /* ... */ }
}
to me this is the easiest way.
source
In NestJS, We can have multiple routes for the whole controller or for a single route. This is supported for all HTTP methods (POST, GET, PATCH etc., )
#Controller(['route-1', 'route-2'])
export class IndividualController {
#Get(['/sub-route-1','/sub-route-2'])
public async getSomething(...){...}
All HTTP methods support either a single string route or an array of string routes. We could use this technique to deprecate a bad route and start introducing a better route without breaking the consumers immediately.
if you mean expressjs instead of jestjs (which is a testing framework), my approach would be the following:
simply exclude your controller code into a function and pass it to your routes.
// your controller code
const doSomethingWithPersonEntity = (req, res, next) => {
res.status(200).json(persons);
}
router.get("/person", doSomethingWithPersonEntity);
router.get("/individual", doSomethingWithPersonEntity);

How to make database request in Nest.js decorator?

I want to find a table row by request parameter. I know how to do it in service but I'm trying
to do it also in decorator.
My decorator:
import { BadRequestException, createParamDecorator, ExecutionContext } from '#nestjs/common';
export const GetEvent = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const { eventId } = request.params;
// Something like in service:
// const event = await this.eventModel.findByPk(eventId);
// return event;
});
I know that it's impossible to inject service in decorator but maybe some hacks to make database requests before calling service methods?
Theoretically, you could use a pacakge directly (like if you use TypeORM you could use the typeorm package), but there's a few things to note:
decorators really shouldn't be calling databases, it'll lead to crazy difficult stack traces
decorator methods can't be async, so you'd need callbacks, which decorators don't really work well with
querying the database really should be done in the controller or service. Just a best practice.

Resources