+ Almost everything is a component – Service, Repository, Factory [...] and they can be injected into controllers or to another components through constructor.
+
+
+
+ In the previous article, we've built a simple CatsController.
+
+
+ The controllers should only handle HTTP requests and delegate more complex tasks to the components.
+ The components are a plain TypeScript classes with @Component() decorator.
+
+
+ Hint Since Nest enables the possibility to design, organize the dependencies in more OO-way, we strongly recommend
+ to follow the SOLID principles.
+
+
+ Let's create a CatsService component:
+
+ cats.service.ts
+
{{ catsService }}
+
+ There's nothing specifically about components. Here's a CatsService, basic class with one property and two methods.
+ The only difference is that it has the @Component() decorator. The @Component() attaches the metadata, so Nest knows that this class is a Nest component.
+
+
+ Notice There's a Cat interface here. I didn't mention about it, because the schema is exact same as in CreateCatDto class.
+
+
+ Since we've the service class already done, let's use it inside the CatsController:
+
+ cats.controller.ts
+
{{ catsController }}
+
+ The CatsService is injected through the class constructor.
+ Don't be afraid about the private readonly shortened syntax.
+ It means that we've created and initialized the catsService member in the same location.
+
+
Dependency Injection
+
+ Nest is built around the strong design pattern, which is commonly known as a Dependency Injection.
+ There's a great article about this concept in the offical Angular documentation.
+
+
+ Hint Learn more about the Dependency Injection in Nest here.
+
+
+ It's extremely easy to manage dependencies with TypeScript, because Nest will recognize your dependencies just by type.
+ This single line:
+
+
{{ constructorSyntax }}
+
+ Is everything what you have to do. There is one important thing to know — you must have emitDecoratorMetadata option set to true in your tsconfig.json file.
+ That's it.
+
+
Last step
+
+ The last thing is to tell the module that something called CatsService truly exists.
+ The only way to do it is to open the app.module.ts file, and add the service into the components array of the @Module() decorator.
+
+ app.module.ts
+
{{ appModule }}
+
+ Now Nest will smoothly resolve the dependencies of the CatsController class.
+
The controllers layer is responsible for handling incoming requests (mostly HTTP).
+
+
+ To tell Nest that CatsController is a controller, you have to attach metadata to the class.
+ Metadata can be attached using decorators.
+
+ cats.controller.ts
+
{{ catsController }}
+
Metadata
+
+ We're using @Controller('cats') here. This decorator is obligatory.
+ The cats is a prefix for each route in the class. The prefix is optional, but it reduces redundant boilerplate code,
+ so you don't have to repeat yourself every time, when you'd decide to create new endpoint.
+
+
+ There's a single public method, the findAll(), which returns an empty array.
+ The @Get() decorator tells Nest that it's necessary to create an endpoint for this route path,
+ and map every appropriate request to this handler. Since we declared the prefix for every route (cats),
+ Nest will map every /cats GET request here.
+
+
+ When client would call this endpoint, Nest will return with 200 status code, and the parsed JSON, so in this case - just an empty array.
+ How is that possible?
+
+
+ There're two possible approaches of manipulating the response:
+
+
+
+
Standard (recommended)
+
+ We're treating the handlers in the same way as a plain functions. When we return the JavaScript object or array, it'd be automatically
+ transformed to JSON. When we return the string, Nest will send just a string.
+
+
+ Furthermore, the response status code is always 200 by default, except POST requests, when it's 201.
+ We can easily change this behaviour by adding the @HttpCode(...) decorator at a handler-level.
+
+
+
+
Express
+
+ We can use the express response object,
+ which we can inject using @Res() decorator in the function signature, for example findAll(@Res() response)
+
+
+
+
+ Notice! It's forbidden to use both two approaches at the same time. Nest detects whether handler is using @Res(), and if it's thruth - the standard way is disabled for this single route.
+
+
Request object
+
+ A lot of endpoints need an access to the client request details.
+ In fact, Nest is using express request object.
+ We can force Nest to inject the request object into handler using @Req() decorator.
+
+
+ Hint There's a @types/express package and we strongly recommend to use it.
+
+ cats.controller.ts
+
{{ requestObject }}
+
+ The request object contains headers, params, and e.g. body of the request, but in most cases, it's not necessary to grab them manually.
+ We can use dedicated decorators instead, such as @Body() or @Query(), which are available out of the box.
+ Below is a comparision of the decorators with the plain express objects.
+
+
+
+
+
@Request()
+
req
+
+
+
@Response()
+
res
+
+
+
@Next()
+
next
+
+
+
@Session()
+
req.session
+
+
+
@Param(param?: string)
+
req.params / req.params[param]
+
+
+
@Body(param?: string)
+
req.body / req.body[param]
+
+
+
@Query(param?: string)
+
req.query / req.query[param]
+
+
+
@Headers(param?: string)
+
req.headers / req.headers[param]
+
+
+
+
More endpoints
+
+ We've already created an endpoint to fetch the data. It'd be great to provide a way of creating the new records too.
+ So.. What we're waiting for?! Let's create the POST handler:
+
+ cats.controller.ts
+
{{ postEndpoint }}
+
+ It's really easy. Nest provides the rest of those endpoints decorators in the same fashion -
+ @Put(), @Delete() etc..
+
+
Async / await
+
+ We love modern JavaScript, and we know that the data extraction is mostly asynchronous.
+ That's why Nest supports async functions, and works pretty well with them.
+
+ Every async function has to return the Promise. It means that you can return deffered value and
+ Nest will resolve it by itself. Let's have a look on the below example:
+
+ cats.controller.ts
+
{{ asyncExample }}
+
+ It's fully valid.
+
+
+ Furthermore, Nest route handlers are even more powerful. They can return the RxJS
+ observable streams.
+ It makes the migration between simple web application and the Nest microservice much easier.
+
+ cats.controller.ts
+
{{ observableExample }}
+
POST handler
+
+ That's weird that the POST route handler doesn't accept any client params. We should definitely
+ expect the @Body() argument here.
+
+
+ Firstly, we need to establish the DTO (Data Transfer Object) schema. We could do it using TypeScript
+ interfaces, or by simple classes. What may be surprising, we recommend to use classes. Why?
+ The classes are the part of the JavaScript ES6 standard, so they're just plain functions. On the other hand, TypeScript interfaces are removed
+ during the transpilation, Nest can't refer to them. It's important, because features such as Pipes enables additional possibilities when they've access to the metatype
+ of the variable.
+
+
+ Let's create the CreateCatDto:
+
+ dto/create-cat.dto.ts
+
{{ createCatSchema }}
+
+ It has only three basic properties. All of them are marked as a readonly, because we should
+ always try to make our functions as pure as possible.
+
+
+ Now we can use the schema inside the CatsController:
+
+ cats.controller.ts
+
{{ exampleWithBody }}
+
+ Expressjs doesn't parse the body by default.
+ We need the middleware, which name is body-parser.
+ The usage is really simple, because Nest instance provides the use() method. It's a wrapper to the native express use() function:
+
+ server.ts
+
{{ bodyParser }}
+
Last step
+
+ The controller is prepared, and ready to use, but Nest doesn't know that CatsController exists,
+ so it won't create an instance of this class. We need to tell about it.
+
+
+ The controller always belongs to the module, which mentioned about its in controllers array within @Module() decorator.
+ Since we don't have any other modules except the root AppModule, let's use it for now:
+
+ app.module.ts
+
{{ appModule }}
+
+ Tada! We attached the metadata to the module class, so now Nest can easily reflect which controllers have to be initialized.
+
+
Express approach
+
+ The second way of manipulating the response is to use express response object.
+ It was the only available option until Nest 4. To inject the response object, we need to use @Res() decorator.
+ To show the differences, i'm going to rewrite the CatsController:
+
+
{{ expressWay }}
+
+ This manner is much less clear from my point of view. I definitely prefer the first approach, but to make the Nest backward compatible
+ with the previous versions, this method is still available. Also, the response object gives more flexibility - you've full control of the response.
+
+
diff --git a/src/app/homepage/pages/controllers/controllers.component.scss b/src/app/homepage/pages/controllers/controllers.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/app/homepage/pages/controllers/controllers.component.spec.ts b/src/app/homepage/pages/controllers/controllers.component.spec.ts
new file mode 100644
index 0000000000..dc6634989c
--- /dev/null
+++ b/src/app/homepage/pages/controllers/controllers.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ControllersComponent } from './controllers.component';
+
+describe('ControllersComponent', () => {
+ let component: ControllersComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ControllersComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ControllersComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/homepage/pages/controllers/controllers.component.ts b/src/app/homepage/pages/controllers/controllers.component.ts
new file mode 100644
index 0000000000..05ebcc4ef2
--- /dev/null
+++ b/src/app/homepage/pages/controllers/controllers.component.ts
@@ -0,0 +1,132 @@
+import { Component, ChangeDetectionStrategy } from '@angular/core';
+import { BasePageComponent } from '../page/page.component';
+
+@Component({
+ selector: 'app-controllers',
+ templateUrl: './controllers.component.html',
+ styleUrls: ['./controllers.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class ControllersComponent extends BasePageComponent {
+ get catsController(): string {
+ return `
+import { Controller, Get } from '@nestjs/common';
+
+@Controller('cats')
+export class CatsController {
+ @Get()
+ findAll() {
+ return [];
+ }
+}`;
+ }
+
+ get requestObject(): string {
+ return `
+import { Controller, Get, Req } from '@nestjs/common';
+
+@Controller('cats')
+export class CatsController {
+ @Get()
+ findAll(@Req() request) {
+ return [];
+ }
+}`;
+ }
+
+ get postEndpoint() {
+ return `
+import { Controller, Get, Post } from '@nestjs/common';
+
+@Controller('cats')
+export class CatsController {
+ @Post()
+ create() {
+ // TODO: Add some logic here
+ }
+
+ @Get()
+ findAll() {
+ return [];
+ }
+}`;
+ }
+
+ get asyncExample() {
+ return `
+@Get()
+async findAll(): Promise {
+ return [];
+}`;
+ }
+
+ get observableExample() {
+ return `
+@Get()
+findAll(): Observable {
+ return Observable.of([]);
+}`;
+ }
+
+ get createCatSchema() {
+ return `
+export class CreateCatDto {
+ readonly name: string;
+ readonly age: number;
+ readonly breed: string;
+}`;
+ }
+
+ get exampleWithBody() {
+ return `
+@Post()
+async create(@Body() createCatDto: CreateCatDto) {
+ // TODO: Add some logic here
+}`;
+ }
+
+ get appModule() {
+ return `
+import { Module } from '@nestjs/common';
+import { CatsController } from './cats/cats.controller';
+
+@Module({
+ controllers: [CatsController],
+})
+export class ApplicationModule {}`;
+ }
+
+ get bodyParser() {
+ return `
+import * as bodyParser from 'body-parser';
+import { NestFactory } from '@nestjs/core';
+import { ApplicationModule } from './modules/app.module';
+
+async function bootstrap() {
+ const app = await NestFactory.create(ApplicationModule);
+ app.use(bodyParser.json());
+ await app.listen(3000);
+}
+bootstrap();`;
+ }
+
+ get expressWay() {
+ return `
+import { Controller, Get, Post, Res, Body, HttpStatus } from '@nestjs/common';
+import { CreateCatDto } from './dto/create-cat.dto';
+
+@Controller('cats')
+export class CatsController {
+ @Post()
+ create(@Res() res, @Body() createCatDto: CreateCatDto) {
+ // TODO: Add some logic here
+ res.status(HttpStatus.CREATED).send();
+ }
+
+ @Get()
+ findAll(@Res() res) {
+ res.status(HttpStatus.OK).json([]);
+ }
+}`;
+ }
+}
diff --git a/src/app/homepage/pages/exception-filters/exception-filters.component.html b/src/app/homepage/pages/exception-filters/exception-filters.component.html
new file mode 100644
index 0000000000..13474ac03f
--- /dev/null
+++ b/src/app/homepage/pages/exception-filters/exception-filters.component.html
@@ -0,0 +1,11 @@
+
+
Exception Filters
+
+ In Nest there's an exceptions layer, which responsibility is to catch the unhandled exceptions and
+ return the appropriate response to the end-user.
+
+
+
+ Every unrecognized exception is handled, and when it was HTTP request, user receives the below response:
+
+ In this set of articles you'll learn the core fundamentals of Nest.
+ The main idea is to get familiar with essential Nest application building blocks.
+ You'll build a basic CRUD application which features covers a lot of ground at an introductory level.
+
+
Setup
+
+ Setting up a new project is quite simple with Starter repository.
+ Just make sure that you have npm installed then use following commands in your OS terminal:
+
+
+$ git clone https://github.com/kamilmysliwiec/nest-typescript-starter.git project
+$ cd project
+$ npm install
+$ npm run start
+
The project directory will contain several core files inside src directory.
+ Following the convention, newly created modules should be placed inside modules directory.
+
+
+
server.ts
+
The entry file of the application. It uses NestFactory to create the Nest application instance.
+
+
+
modules/app.module.ts
+
Defines AppModule, the root module of the application. Right now it doesn't declare any metadata, because we didn't create any component and controller yet.
+
+
+
+ The server.ts contains single async function, which responsibility is to bootstrap our application:
+
+ server.ts
+
{{ bootstrap }}
+
+ We should always create the Nest application instance using the NestFactory.
+ The create() method returns object, which fulfils INestApplication interface, and provides a set of usable methods, which are well described in the next articles.
+
Nest is a powerful web framework for Node.js, which helps you effortlessly build efficient, scalable applications. It uses modern JavaScript, is built with TypeScript and combines best concepts of both OOP (Object Oriented Progamming) and FP (Functional Programming).
+
Nest is using well-known—Express library under the hood. This means that you can quickly start using Nest without worrying about third party plugins.
+
Installation
+
Install the TypeScript Starter Project with Git:
+
+$ git clone https://github.com/kamilmysliwiec/nest-typescript-starter.git project
+$ cd project
+$ npm install
+$ npm run start
JavaScript is awesome. Now, the front end world is rich in variety of tools. We have a lot of amazing projects / libraries such as Angular, React or Vue, which improves our development process and makes our applications fast and extensible.
+
Node.js gave us a possibility to use this language also on the server side. There are a lot of superb libraries, helpers and tools for node, but non of them do not solve the main problem - the architecture.
+
We want to create scalable, loosely coupled and easy to maintain applications. That's why the Nest has been introduced. Let's show the entire world node.js potential together!
Based on well-known libraries (Express / socket.io) so it’s a familiar experience
+
Supremely useful Dependency Injection support, built-in asynchronous Inversion of Control container
+
Hierarchical injector - increase abstraction in your application by creating reusable, loosely coupled modules with type injection
+
WebSockets module (based on socket.io, although you can use any other library using WsAdapter)
+
Own modularity system (split your system into reusable modules)
+
Reactive microservices support with message patterns (built-in transport via TCP / Redis, but you can use any other type of communication using CustomTransportStrategy)
diff --git a/src/app/homepage/pages/introduction/introduction.component.scss b/src/app/homepage/pages/introduction/introduction.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/app/homepage/pages/introduction/introduction.component.spec.ts b/src/app/homepage/pages/introduction/introduction.component.spec.ts
new file mode 100644
index 0000000000..a5f68f55c5
--- /dev/null
+++ b/src/app/homepage/pages/introduction/introduction.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { IntroductionComponent } from './introduction.component';
+
+describe('IntroductionComponent', () => {
+ let component: IntroductionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ IntroductionComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(IntroductionComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/homepage/pages/introduction/introduction.component.ts b/src/app/homepage/pages/introduction/introduction.component.ts
new file mode 100644
index 0000000000..74508cb949
--- /dev/null
+++ b/src/app/homepage/pages/introduction/introduction.component.ts
@@ -0,0 +1,10 @@
+import { Component, ChangeDetectionStrategy } from '@angular/core';
+import { BasePageComponent } from '../page/page.component';
+
+@Component({
+ selector: 'app-introduction',
+ templateUrl: './introduction.component.html',
+ styleUrls: ['./introduction.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class IntroductionComponent extends BasePageComponent {}
\ No newline at end of file
diff --git a/src/app/homepage/pages/middlewares/middlewares.component.html b/src/app/homepage/pages/middlewares/middlewares.component.html
new file mode 100644
index 0000000000..5114270ac3
--- /dev/null
+++ b/src/app/homepage/pages/middlewares/middlewares.component.html
@@ -0,0 +1,89 @@
+
+
Middlewares
+
+ The middleware is a function, which is called before route handler.
+ Middleware functions have an access to the request
+ and response objects, so they can modify them. They can also be something like a barrier - if middleware function won't call next(),
+ the request will never be handled by the route handler.
+
+
+
+ Middleware is a class with @Middleware() decorator. This class should implement the NestMiddleware interface.
+ Let's create an example, the LoggerMiddleware class.
+
+ logger.middleware.ts
+
{{ loggerMiddleware }}
+
+ The resolve() method has to return the regular expressjs middleware (req, res, next) => void.
+
+
Dependency Injection
+
+ There's no exception when it comes to the middlewares. Same as components and controllers, they can inject dependencies which belong to the same module.
+
+
Where to put the middlewares?
+
+ The middlewares shouldn't be listed in the @Module() decorator.
+ We've to setup them using configure() method of the module class.
+ Modules which include middlewares have to implement the NestModule interface.
+ Let's setup the LoggerMiddleware at the ApplicationModule level.
+
+ app.module.ts
+
{{ applicationModule }}
+
+ Hint We could pass here (inside forRoutes()) the single object and just use RequestMethod.ALL.
+
+
+ In above example we setuped LoggerMiddleware for /cats route handlers, which we've registered inside CatsController.
+ The MiddlewareConsumer is a helper class. It provides several methods to work with the middlewares. All of them can be simply chained.
+ Let's go through those methods.
+
+
+ The forRoutes() can take single object, multiple objects, controller class and even multiple controller classes.
+ In most cases you'll probably just pass the controllers and separate them by comma. Below is an example with the single controller:
+
+ app.module.ts
+
{{ applicationModuleByControllers }}
+
+ Hint The apply() method can take single middleware or an array of middlewares.
+
+
Pass arguments to the middleware
+
+ Sometimes the behaviour of the middleware depends on the custom values e.g. array of user roles, options object etc.
+ We can pass additional arguments to the resolve() using with() method. See below example:
+
+ app.module.ts
+
{{ applicationModuleWithMethod }}
+
+ We passed custom string - ApplicationModule to the with() method.
+ Now we've to adjust the resolve() method of the LoggerMiddleware.
+
+ logger.middleware.ts
+
{{ loggerMiddlewareWithArgs }}
+
+ The value of the name property would be ApplicationModule.
+
+
Async Middlewares
+
+ There's no contraindications to return the async function from the resolve() method.
+ Also, it's possible to make the resolve() method async too. This pattern is called deffered middleware.
+
+ logger.middleware.ts
+
{{ defferedMiddleware }}
+
Functional Middlewares
+
+ The LoggerMiddleware is quite short. It has no members, no additional methods, no dependencies.
+ Why we can't just use simple function? It's a good question, cause in fact - we can do it.
+ This type of the middleware is called functional middleware.
+ Let's transform the logger into the function.
+
+ logger.middleware.ts
+
{{ functionalMiddleware }}
+
+ Now use it within the ApplicationModule.
+
+ app.module.ts
+
{{ applyFunctionalMiddleware }}
+
+ Notice Let's consider to use functional middlewares everytime when your middleware doesn't have any dependencies.
+
+ Module is a class with @Module() decorator. The @Module() decorator provides metadata, which Nest is using to organize the application structure.
+
+
+
+ Every Nest application has at least one module, the root module.
+ The root module is the place, where Nest is starting to arrange the application tree.
+ In fact, the root module could be the only module in your application, especially when the app is small, but it doesn't make sense.
+ In most cases you'll have several modules, each with closely related set of capabilities.
+
+
+ The @Module() decorator takes the single object whose properties describe the module.
+ Read about them in the below table:
+
+
+
+
components
+
the components that will be instantiated by the Nest injector and may be shared at least across this module.
+
+
+
controllers
+
the set of controllers which have to be created
+
+
+
modules
+
the list of imported modules that export the components which are necessary in this module
+
+
+
exports
+
the subset of components that should be available in the other modules
+
+
+
+ The module encapsulates components by default. It means that it isn't possible to inject the components which aren't directly the part of the current module, or they're not exported from the imported modules.
+
+
CatsModule
+
+ The CatsController and CatsService belong to the same application domain.
+ They should be moved to the feature module, the CatsModule.
+
+ cats/cats.module.ts
+
{{ catsModule }}
+
+ I've created the cats.module.ts file and moved everything related to this module into the
+ cats directory. The last thing we need to do is to import this module into the root module which name is ApplicationModule.
+
+ app.module.ts
+
{{ appModule }}
+
+ It's everything. Now Nest knows that besides ApplicationModule, it's essential to register the CatsModule too.
+
+
Shared Module
+
+ In Nest, modules are singletons by default, so you can share the same instance of the component between 2..* modules without any effort.
+
+
+ Notice In the previous versions of the Nest (< 4), modules weren't singletons, we had to use @Shared() decorator which now is deprecated.
+
+
+
+ Every module is a Shared Module in fact. Once created is reused by the each module.
+ Let's imagine that we're gonna share the CatsService instance between few modules.
+
+ cats.module.ts
+
{{ catsModuleShared }}
+
+ Now each module which would import the CatsModule has an access to the CatsService, and will share the same instance with all of the modules which import this module too.
+
+
+ Notice Never export the controller!
+
+
Single Scope
+
+ They're modules which shouldn't be shared at all. To prevent module from being singleton, you can use @SingleScope()
+ decorator, which makes that Nest will always create the new instance of the module, when it's imported by another one.
+
+
{{ singleScope }}
+
Dependency Injection
+
+ It's natural that module can inject components, which belongs to it (e.g. for the configuration purposes):
+
+ cats.module.ts
+
{{ catsModuleDi }}
+
+ However, modules can't be injected by the components, because it creates a circular dependency.
+