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.
Related
I'm learning NestJS and now I'm working in a simple authentication application, at this point I configured global pipes to validations and I'm using dto classes for example to validate #Body() fields. I don't know if I can use DTO to validate #Request fields sent from login endpoint.
import { Controller, Post, Request, UseGuards } from '#nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from '#nestjs/passport';
#Controller()
export class AuthController {
constructor(private authService: AuthService) {}
#UseGuards(AuthGuard('local'))
#Post('auth/login')
async login(#Request() req: reqDto /* I would like to use DTO for validations*/) {
return this.authService.login(req.user);
}
}
PS: I'm using DTO to validate SingUp body In UserController.
#Post('/signup')
createUser(#Body() createUserDto: CreateUserDto) {
return this.userService.createUser(createUserDto);
}
#Request() and #Headers() are two decorators that skip validation via pipes. You can make a custom request decorator that does get called via pipes, but annotating the request object would be a lot of work. What would be better is to create a decorator that gets just the data you need off the request, and then make a DTO for that object and validate that as necessary
I have created a few onCall cloud functions using Firebase. These functions interact with Stripe through the API. When I use AngularFire, or more specifically, AngularFireFunctions to call these said cloud functions, I receive the error message A bad HTTP response code (404) was received when fetching the script. in Chrome developer console. Yet, the expected result is received with no problem and the Firebase console displays a 200 response with no error messages or warnings. The project is entirely hosted on Firebase.
The 404 error also does not display a file that it is connected to in the console as such errors typically do within that console.
UPDATE
I also feel it is relevant to include, the Stripe developer logs in the dashboard reflect no errors, but a successfull call upon checking.
I have also tried to remove the call to Stripe in the cloud function and simply only return a string return 'The customer ID is:'+ ${data.customerId}+'. Thank you.' and still received the same error message.
I have also tried this solution, https://github.com/angular/angularfire/issues/1933#issuecomment-432910986 with the following code being placed inside app.module.ts however, am unable to find where FunctionsRegionToken would be defined to be able to import it.
providers: [
{ provide: FunctionsRegionToken, useValue: 'us-central1' }
]
Although, I'm not sure how changing the region to the same region the function is being called from currently would make any difference.
When you explore the Network tab of the developer console and visit the page that calls the function, you see that something is trying to call http://localhost:4200/firebase-messaging-sw.js which doesn't exist. The amount of calls to this file and the errors in the console coincide with each other which leads me to believe they are related.
END OF UPDATE
I have tried to add CORS to my cloud function (and am using it in onRequest functions), I've tried rewriting my cloud function, and even tried changing the client side function that calls the onCall to no avail. The only way to remove the error is to remove the call to the function, thus I've narrowed it down to something with the AngularFireFunctions.
What I am using and the versions
Angular V13
Firebase 9.6.7
Angular Fire 7.2.1
Node 16.13.1
What follows is my code, broken up into sections.
Cloud function
const cors = require('cors')({origin: true});
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
const FieldValue = require('firebase-admin').firestore.FieldValue;
admin.initializeApp();
const firebaseApp = admin.app();
const firebaseDB = firebaseApp.firestore();
const Stripe = require('stripe');
const stripe = Stripe(functions.config().stripe.key);
export const retrieveCustomer = functions.https.onCall( async(data) => {
if(data.customerId) {
const customer = await stripe.customers.retrieve(data.customerId);
if(customer) {
return customer;
} else {
throw new functions.https.HttpsError('unknown', 'An unknown error occurred, please try again.');
}
} else {
throw new functions.https.HttpsError('invalid-argument', 'A customer ID must be provided.');
}
});
Angular Service
import { Injectable } from '#angular/core';
import { AngularFirestore } from '#angular/fire/compat/firestore';
import { AngularFireFunctions } from '#angular/fire/compat/functions';
#Injectable({
providedIn: 'root'
})
export class BillingService {
constructor( private aff: AngularFireFunctions, private afs: AngularFirestore ) { }
RetrieveCustomer(customerId:string) {
const callable = this.aff.httpsCallable('retrieveCustomer');
return callable({
customerId: customerId
});
}
}
Angular Component
import { Component, OnInit, AfterContentInit } from '#angular/core';
import { BillingService } from 'src/app/shared/services/billing/billing.service';
#Component({
selector: 'app-billing-settings',
templateUrl: './billing-settings.component.html',
styleUrls: ['./billing-settings.component.css']
})
export class BillingSettingsComponent implements OnInit, AfterContentInit {
public stripeCustomer!: any;
constructor( private billingService: BillingService ) { }
ngOnInit(): void {
}
ngAfterContentInit(): void {
this.billingService.RetrieveCustomer('cus_LGRX8TPVF3Xh0w').subscribe((customer:any) => {
console.log(customer);
});
}
}
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.
I want to save each request (path, method, and userId) that comes to the server without having to hit the database twice, and also without messing up the main logic in services files with transactions.
Initially, I was trying to use an interceptor because it gets invoked after auth guards "which attaches the user to request" and before request handlers, but I faced two issues.
first, the fact that the interceptor will call the database to save a new record and then forward the request to handlers which will again hit DB again to handle the request. Secondly, It didn't work anyway because of dependancy injection problems.
code below is not working due to dependency errors as I mentioned, but It will give u an idea about what I need to acheive.
import { Injectable,
NestInterceptor,
Inject,
ExecutionContext,
CallHandler,
HttpException,
HttpStatus } from '#nestjs/common';
import { Observable } from 'rxjs';
import { getRepositoryToken } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { HistoryEntity } from '../../modules/history/history.entity';
#Injectable()
export class HistoryInterceptor implements NestInterceptor {
constructor(
#Inject(getRepositoryToken(HistoryEntity))
private readonly historyRepo: Repository<HistoryEntity>
) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const { user, path, method } = request
if (!user) {
throw new HttpException('something terrible happened!', HttpStatus.BAD_GATEWAY);
}
const history = this.historyRepo.create({
path,
userId: user.id,
});
this.historyRepo.save(history);
return next.handle();
}
}
PS. from a performance point of view, It would also be great to not halt the request execution to save these info in db, in other words, Is it ok to NOT use await in this particular situation? because essecntially this is a system related operation and so, Node [rocess shouldn't wait for this step to process and return response to client.
Thanks in advance.
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.