Base features
The base features of the TypeScript NestJS stack are available for any project based on the stack by default and are not related to special extensions. The features will be enabled by using the provided Nest Application setup functions and K5SDKModule within your application, which also offer configuration options to customize the behavior according to your needs.
NestJS Application setup
The k5 SDK
offers functions to easily create and setup a NestApplication with a default configuration. It is recommended to use these functions wihtin your applications for the initial setup, to make sure that your NestApplication is prepared for further features of the K5SDK.
Get default NestApplicationOptions
, which applies the K5LoggerService
as default logger and default https options:
import { getNestApplicationOptions } from 'k5-sdk';
// get default nest application options
const options = await getNestApplicationOptions();
Create a new NestApplication
using the NestApplicationOptions
:
import { createNestApplication } from 'k5-sdk';
// create nest app
const app = await createNestApplication(AppModule, options);
Setup the NestApplication
with extra configuration (e.g. applying default middlewares, enabling CORS protection, enabling tracing):
import { setupNestApplication } from 'k5-sdk';
// setup nest app and apply middlewares
await setupNestApplication(app, {
dotenvConfig: { path: '.env' }
});
K5SDKModule
The K5SDKModule
is a module that is meant to be imported into the root module of your project. It bundles different modules provided in the k5 sdk
and enable their features. To ensure flexibility, you have various configuration possibilities like flags for disabling certain modules or setting specific configurations for it. The K5SDKModule
is defined as a global module and therefore all it's providers can be easily used within custom code.
Even though the individual modules could be also imported without the K5SDKModule, it is recommended to rather use K5SDKModule as new features shipped will be automatically applied through it.
Use the K5SDKModule
within your root module:
import { ConfigModule } from '@nestjs/config';
import { Module } from '@nestjs/common';
import { K5SDKModule } from 'k5-sdk';
@Module({
imports: [
ConfigModule.forRoot(),
// import K5SDKModule with default settings
K5SDKModule.forRoot({}),
],
controllers: [],
providers: [],
})
export class AppModule {}
Logging
The K5LoggerService
is a logging service provided by the K5SDKModule
, which is part of the K5 SDK. It is built on top of winston and provides structured logging with automatic log level configuration from the LOG_LEVEL
environment variable.
Usage
By default, the K5LoggerService
is used as the default logger in the generated NestJS application.
Additionally, K5LoggerService
is globally provided by the K5SDKModule
, making it available for injection into controllers and services:
@Injectable()
export class SomeService {
constructor(private readonly logger: K5LoggerService) {}
someMethod() {
this.logger.info('Executing someMethod');
}
}
Environment Configuration
For deployed services, the pipeline automatically sets the LOG_LEVEL
environment variable.
For local development, LOG_LEVEL
should be set in the local .env
file. If not set, it defaults to 'INFO'
.
Logging Methods
The following logging methods are available:
Method | Alias | Description |
---|---|---|
error | Logs an error message with stack trace (if provided) | |
warn | Logs a warning message | |
info | log | Logs an informational message |
debug | Logs a debug message | |
verbose | Logs a verbose message |
Logging Method Arguments
info
, warn
, debug
, verbose
this.logger.info('message', ...args);
- message - The log message
- args - Optional arguments (if the first argument is a string, it is used as the log statement context)
Example:
this.logger.info('Pet added successfully', 'Pet Ctx', { foo: 'bar' });
[2025-02-11 16:23:47] [INFO] [Pet Ctx] [traceId: 892dee5801bdb06e] [spanId: 892dee5801bdb06e]: Pet added successfully params: {"foo":"bar"}
error
this.logger.error('message', error.stack, ...args);
- message - The log message
- stack - Stack trace of the error
- args - Optional arguments (if the first argument is a string, it is used as the log statement context)
Log Output Format
Each log statement includes the following information:
- Timestamp
- Log Level
- Context (defaults to caller file name and line number)
- Trace ID & Span ID (from tracing middleware)
- Message
- Additional arguments
Example:
this.logger.log(`Starting "addPet" operation`);
[2025-02-10 16:32:30] [INFO] [src/api/pet/pet.controller.ts:32:17] [traceId: bcee7a9a2b60257e] [spanId: bcee7a9a2b60257e]: Starting "addPet" operation
For more details on tracing integration and traceId
/spanId
, see Tracing Documentation.
Production Logging Format: In production environments, log messages are structured as JSON objects
Custom Log Format
The K5LoggerService
can be customised to use a custom log format with Winston:
import * as winston from 'winston';
providers: [
{
provide: K5LoggerService,
useFactory: () =>
new K5LoggerService({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(({ timestamp, level, message }) => {
return `[${timestamp}] [${level.toUpperCase()}]: ${message}`;
})
),
}),
},
],
Customizing K5LoggerService
When importing the K5SDKModule
, the global K5LoggerService
instance options can be configured by setting k5LoggerServiceOptions
:
imports: [
ConfigModule.forRoot(),
K5SDKModule.forRoot({
k5LoggerServiceOptions: {
level: 'debug',
},
}),
],
If K5LoggerService
is explicitely provided from a NestJS module, the log level is determined by the LOG_LEVEL
environment variable.
However, it can also be customized using standard Winston logger options:
providers: [
{
provide: K5LoggerService,
useFactory: () => new K5LoggerService({ level: 'error' }), // Generic winston LoggerOptions
},
],
Setting Context for a Module
The setContext
function allows setting a context for logs emitted by a K5LoggerService
instance within a specific module:
providers: [
{
provide: K5LoggerService,
useFactory: () => new K5LoggerService().setContext('Pet Context'),
},
],
[2025-02-10 16:39:00] [INFO] [Pet Context] [traceId: 5af8d2390a3a44f3] [spanId: 5af8d2390a3a44f3]: Starting "addPet" operation
Tracing
The TypeScript NestJS stack by default enables tracing for all incoming requests. The tracing information will automatically be applied to all log statements of the service. To access the tracing context, the k5 sdk
provides the function getTracingContext()
.
import { getTracingContext } from 'k5-sdk';
// get tracing context to access traceId, spanId, parentId
const ctx = getTracingContext();
const traceId = ctx.traceId;
const spanId = ctx.spanId;
const parentId = ctx.parentId;
HTTP requests
To trigger HTTP requests to external services, the k5 sdk
offers useful classes and functions.
The K5HttpService
offers common methods to trigger HTTP requests based on axios
and automatically applies the tracing context to the request. It is provided through the global K5SDKModule
and therefore the default instance of K5HttpService
can be easily used across the application.
Example usage:
import { K5HttpService } from 'k5-sdk';
export class MyController {
constructor(private httpService: K5HttpService) {
super();
}
async myMethod() {
// trigger a GET request
await this.httpService.get('/my/get/operation');
}
Besides that, common NestJS Dependency Injection can be used to inject the K5HttpService
wherever it is required. This way, it is also possible to apply a specific configuration for the used axios instance (see below example) whenever this is needed for a use case.
Example to include the K5HttpService into your module as provider with specific configuration:
import { K5HttpService } from 'k5-sdk';
import { MyController } from './my.controller';
@Module({
imports: [],
controllers: [MyController],
providers: [
{
provide: K5HttpService,
useFactory: () =>
new K5HttpService({
// add specific axios configuration
baseURL: 'https://some.base.url.com'
}),
},
],
})
export class MyModule {}
Besides the K5HttpService, it is possible to directly make use of the tracedAxios
instance, exported by the k5 sdk
.
JWT based authentication
In services built with the TypeScript NestJS stack, any incoming HTTP request is secured by default. The authentication policy is automatically applied by the K5AuthModule
, which is included in the K5SDKModule
. It expects a valid JWT as bearer token within the Authentication
header of the request. If the provided JWT is invalid or it is even completely missing, the request will be rejected automatically and a meaningful error will be returned to the consumer.
Required environment variable
To be able to validate the JWT, the service requires the URI to the issuer of the OIDC provider. It is expected that it is provided within the environment variable OIDC_ISSUER_URI
. For the deployed service, the pipeline is taking care for setting the variable, but for local development, please make sure that it is provided in your local .env
.
Disable JWT based authentication
If you want to disable the authentication check for your use case, you have two options:
- Disable JWT check for special routes
- Disable JWT for the whole application
Disabling the JWT check for dedicated endpoints within your application could be useful in some situations. To do that, you can make use of the @Public
decorator offered by the k5-sdk
within a controller:
import { Controller, Get } from '@nestjs/common';
import { Public } from 'k5-sdk';
@Controller('/api')
export class AppController {
@Get('/public-route')
@Public()
getPublic(): string {
// no authentication was required to get here
// ...
}
}
Disabling the JWT checks for the whole application can be done by disabling the overall K5AuthModule
within the configuration of the K5SDKModule
in the root module of your application:
import { Module } from '@nestjs/common';
import { K5SDKModule } from 'k5-sdk';
@Module({
imports: [
K5SDKModule.forRoot({
// disable authentication
disableK5AuthModule: true,
}),
],
})
export class AppModule {}
Health checks
The K5SDKModule
automatically comes with built-in endpoints for health checks, liveness and readiness probes which guarantees, that the service is compliant with the common software design standards.
The K5HealthModule
by default enables 3 public routes which are not secured by the default authentication checks so that they can be used e.g. for health checks. The health checks, liveness and readiness probes are automatically set up by the pipeline and don't require any specific settings to work.
By default, the following endpoints are provided:
- GET /health
- GET /liveness
- GET /readiness
Configuration
To configure the health module, you can make use of the available configuration options in the K5SDKModule
:
import { Module } from '@nestjs/common';
import { K5SDKModule } from 'k5-sdk';
@Module({
imports: [
K5SDKModule.forRoot({
k5HealthModuleOptions: {
// The timeout to wait in ms before the application shuts down
gracefulShutdownTimeoutMs: 3000
}
}),
],
})
export class AppModule {}
To completely customize the endpoints and their behavior, it is recommended to disable the K5HealthModule
completely and re-implement the health feature in your application. In this case, please make sure that the helm chart is in sync with the customizations made.
Disable default routes
To disable the default routes, you can use the configuration option in the K5SDKModule
:
import { Module } from '@nestjs/common';
import { K5SDKModule } from 'k5-sdk';
@Module({
imports: [
K5SDKModule.forRoot({
// disable health, readiness and liveness routes
disableK5HealthModule: true
}),
],
})
export class AppModule {}
Rate Limit Module
The K5SDKModule
automatically comes with built-in support for rate limit to protect your service by controlling the number of requests a client can make within a specified time window.
The K5RateLimitModule
is disabled by default. When enabled, it comes with predefined default values.
- TTL (Time to Live): 60000 milliseconds
- Limit: 100
Configuration
To configure the rate limit module, you can make use of the available configuration options in the K5SDKModule
:
import { Module } from '@nestjs/common';
import { K5SDKModule } from 'k5-sdk';
@Module({
imports: [
K5SDKModule.forRoot({
enableK5RateLimitModule: true,
k5RateLimitModuleOptions: [
{
limit: 20,
ttl: 120000,
},
],
}),
],
})
export class AppModule {}
CORS protection
The TypeScript NestJS stack offers an easy way to enable Cross-Origin Resource Sharing protection within the service project.
The CORS protection is configured through the setupNestApplication() function provided in the k5 SDK
and mainly relies on the provided environment variables.
Environment variables
The following environment variables can be used to configure the CORS protection:
CORS_POLICY_ENABLED
: A boolean value (true
orfalse
) to enable or disable CORS.CORS_ORIGIN
: A comma-separated list of allowed origins. Each origin must be a valid URL or*
.CORS_METHODS
: A comma-separated list of allowed HTTP methods (e.g.,GET, POST
).CORS_HEADERS
: A comma-separated list of allowed headers (e.g.,Content-Type, Authorization
).
Configure CORS in local development
To enable and configure CORS for local development, please ensure that the above described environment variables are set according to your needs in the local .env
file.
Configure CORS for a deployed service
Enable CORS protection from hub
- Go to Hub and from "k5-projects" tab select the environment that has the service deployment.
- Click "Service deployment" tab and search for the service deployment
- Choose "Deployment configuration" tab.
- Expand "Features" section.
- Toggle the "Enable CORS" button to enable it.
- Click on "Save" button.
- Redeploy the service by rerunning the pipeline from the designer.
Enable CORS protection from configuration management service
Use the Configuration Management API to send the following CORS configuration in request body (in yaml format):
feature:
corsPolicy: true // enable/disable the CORS policy
corsConfiguration:
corsOrigin: '*' // for allowed CORS origin
corsMethods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS' // the allowed CORS methods
corsHeaders: '' // CORS headers that are allowed
This will override the CORS default configured values.
Helmet
The TypeScript NestJS stack offers an easy way to enable helmet protection within the service project.
The helmet protection can be enabled through the Nest Application Setup. To switch it on, use the configuration option enableHelmetProtection
. To configure helmet according to your needs, use the helmetOptions
configuration option.
Example:
// setup nest app and enable helmet protection
await setupNestApplication(app, {
enableHelmetProtection: true,
helmetOptions: {
// ...
}
});