Search
Duplicate

[오버뷰] 02.Contollers

Created
2021/07/02 02:51
Tags

Controllers

컨트롤러는 들어오는 요청을 처리하고 클라이언트에 응답을 반환하는 책임이 있다.
컨트롤러의 목적은 application 에 대한 특정 요청을 받는 것이다.
[routing] 메커니즘은은 어떤 컨트롤러가 어떤 요청을 수신하는 지 제어한다.
Frequently (자주), each controller has more than one route
and different routes can perform different actions
In order to create a basic controller, 우리는 [class]들과 [decorator]들을 사용합니다.
데코레이터는 class들을 요청된 메타데이터와 연관 짓고, 네스트가 라우팅맵을 생성할수 있도록 합니다.
(tie requests to the corresponding controllers) (요청을 상응하는 컨트롤러에 묶는 것)

HINT

For quickly creating a CRUD controller with the [validation] built-in, you may use the CLI's CRUD generator:
nest g resource [name]
Plain Text
복사

Routing

예제에서는 basic controller 를 정의하는데 [@Controller()] 데코레이터를 사용하였다.
We'll specify(지정하다) an optional route path prefix of [cats]
Using a path prefix in a [@Controller()] decorator allows us to easily group a set of related routes,
And minimize repetitve code.
For example, we may choose to group a set of routes that manage interactions with a customer entity under the rout /customers.
In that case, we could specify the path prefix [customers] in the [@Controllers()] decorator so that we don't have to repeat that portion of the path for each route in the file (@Contoller('cats') 라고 되어있다면, /cats 로 시작하는 모든 요청을 받는 다는 뜻인듯.
import { Controller, Get } from '@nestjs/common'; @Controller('cats') export class CatsController { @Get() findAll(): string { return 'This action returns all cats'; } }
Plain Text
복사

HINT

To create a controller using the CLI, simply execute the [nest g controller [path prefix]] command
The [@Get()] HTTP request method decorator before the findAll() method tells Nest to create a handler for specific endpoint for HTTP requests. (findAll() 메소드 앞에 있는 @Get() 는 네스트에게 HTTP 요청에 대한 특별한 엔드포인트 핸들러를 만들게 한다.)
Endpoint : (메소드는 같은 URL들에 대해서도 다른 요청을 하게끔 구별하게 해주는 항목이 바로 Endpoint입니다.)
The endpoint corresponds to (~에 해당하다) the HTTP request method (GET in this case) and the route path ('endpoint' 는 HTTP 요청과 Route Path 에 해당한다.)
What is the route path?
The route path for a handler is determined(결정된다) by concatenating(사슬같이 이어진) the (optional) prefix declared(선언된) for the controller, and any path specified in the request decorator (handler 를 위한 route path 는 컨트롤러에 선언된 이어진 prefix 와, 리퀘스트 데코레이터에 지정된 path 에 의해 결정된다. 뭔ㄱ 개소리야)
우리가 모든 route(cats) 에 prefix 를 선언했고, 어떠한 path information 도 데코레이터에 더하지 않았기 때문에, 네스트는 GET /cats 요청을 이 핸들러에 맵핑한다.
말했다 시피 path 는 두 가지(optional controller path prefix, any path string declared in the request method decorator) 를 모두 포함한다.
예를들어, path prefix 가 customers 로 데코레이터가 @Get('profile') 이면 GET /customers/profile 요청이 맵핑된다.
In our example above, when a GET request is made to this endpoint, Nest routes the request to our user-defined findAll() method.
Node that the method name we choose here is completely arbitrary(임의의)
We obviously must declare a method to bind the route to (우리는 분명하게 반드시 route 에 바인드되는 메소드를 선언해야 합니다.)
but Nest doesn't attach any significance the method name chosen (하지만 네스트는 선택한 메소드 이름에 어떤 의미도 부여하지 않습니다.)
This method will return a 200 status code and the associated response(관련된 응답), which in this case is just a string.
Why does that happen?
To explain, we'll first introduce the concept that Nest employs two different options for manipulating responses : (설명하기 위해, 우리는 Nest가 응답을 조작하기 위해 두가지 다른 옵션을 사용한 다는 컨셉을 소개하겠다. - 말 진짜 개어렵게하네)

Standard (recommended)

Using this built-in method, when a request handler returns a JS object or array,
it will Autometically be serialized to JSON. When it returns a JS primitive(original language) type (e.g., string, number, boolean)
However, Nest will send just the value without attempting to serialize it.
This make response handling simple: just return the value, and Nest takes care of the rest
Furthermore, the response's status code is always 200 by default, except for POST requests which use 201.
We can easily change this behavior by adding the @HttpCode(...) decorator at a hanlder-level

Request object

Handlers often need access to the client request details. Nest provides access to the request object of the underlying(밑에 있는) platform (Express by default)
We can access the request object by instructing Nest to inject it by adding the @Req() decorator to the handler's signature
import { Controller, Get, Req } from '@nestjs/common'; import { Request } from 'express'; @Controller('cats') export class CatsController { @Get() findAll(@Req() request: Request): string { return 'This action returns all cats'; } }
Plain Text
복사

HINT

In order to take advantage of express typings (as in the request: Request parameter example above), install @types/express package.

Request Object

The request object represents(나타내다, 대표하다) the HTTP request, and has properties for the request query_string, parameters, HTTP headers, and body
In most cases, it's not necessary to grab these properties manually
We can use dedicated decorators(전용 데코레이터들) instead,
such as @Body() or @Query(), which are available out of the box(기존 틀을 깨는 사고 or 설정(설치)없이 즉시 사용이 가능한).
Below is a list of the provided decorators and the plain platform-specific object they represent
@Request(), @Req() : req
@Response(), @Res() : res
@Next() : next
@Session() : req.session
@Param(key?: string) : req.params / req.params[key]
@Body(key?: string) : req.body / req.body[key]
@Query(key?: string) : req.query / req.query[key]
@Headers(name?: string) : req.headers / req.headers[name]
@Ip() : req.ip
@HostParam() : req.hosts
@Res() 는 단순히 @Response() 로 얼라이어스 되어있다. 이 기능을 온전히 사용하기 위해서는, 너가 사용하는 라이브러리를 import 해야 한다. (e.g., @types/express)

Resources

Earlier, we defined an endpoint to fetch(가져오는) the cats response (GET route).
We'll typically(일반적으로) also want to provide an endpoint that crates new records.
For this, let's create the POST handler :
import { Controller, Get, Post } from '@nestjs/common'; @Controller('cats') export class CatsController { @Post() create(): string { return 'This action adds a new cat'; } @Get() findAll(): string { return 'This action returns all cats'; } }
Plain Text
복사
It's that simple. Nest provides decorators for all of the standard HTTP methods : @Get(), @Post(), @Put(), @Delete(), @Patch(), @Options(), and @Head().
In addition, @All() defines an endpoint that handles all of them.

Route wildcards

Pattern based routes are supported as well. For instance, the asterisk is used as a wildcard, and will match any combination of characters.
@Get('ab*cd') findAll() { return 'This route uses a wildcard'; }
Plain Text
복사
The ab*cd route path will match abcd, ab_cd, abecd, and so on. The characters ?, +, , and () may be used in a route path.
And are subsets of their regular expression counterparts.
The hyphen () and the doy (.) are interpreted(해석된다) literally by string-based paths ( - 및 . 은 문자열 기반 경로로 문자 그대로 해석 됩니다.)

Status Code

As mentioned, the response status code is always 200 by default, except for POST requests which are 201.
We can easily change this behavior by adding the @HttpCode(...) decorator at a handler level.
@Post() @HttpCode(204) create() { return 'This action adds a new cat'; }
Plain Text
복사

HINT

Import HttpCode from the @nestjs/common package.
Often, your status code isn't static.
But depends on various factors.
In that case, you can use a library-specific response (inject using @Res()) object
(or, in case of an error, throw an exception).

Headers

To specify a custom response header, you can either use a @Header() decorator or a library-specific response object (and call res.header() directly).
@Post() @Header('Cache-Control', 'none') create() { return 'This action adds a new cat'; }
Plain Text
복사

HINT : Import Header from the @nestjs/common package.

Redirection

To redirect a response to a specific URL, you can either use a @Redirect() decorator or a library-specific response object (and call res.redirect() directly).
@Redirect() takes two arguments, url and statusCode, both are optional.
The default value of statusCode is 302 (Found) if omitted(생략된).
@Get() @Redirect('<https://nestjs.com>', 301)
Plain Text
복사
Sometimes you may want to determine the HTTP status code or the redirect URL dynamically. Do this by returning an object from the route handler method with the shape :
{ "url": string, "statusCode": number }
Plain Text
복사
Returned values will override any arguments passed to the @Redirect() decorator.
For example :
@Get('docs') @Redirect('<https://docs.nestjs.com>', 302) getDocs(@Query('version') version) { if (version && version === '5') { return { url: '<https://docs.nestjs.com/v5/>' }; } }
Plain Text
복사

Route parameters

Routes with static paths won't work when you need to accept dynamic data as part of the request (e.g., GET /cats/1 to get cat with id 1). - (요청의 일부로 동적 데이터를 수락해야 하는 경우, Route with static paths 는 동작하지 않는다.
In order to define routes with parameters, we can add route parameter tokens in the path of the route to capture the dynamic value at the position in the request URL.
The route parameter token in the @Get() decorator example below demonstrates this usage.
Route parameters declared in this way can be accessed using the @Param() decorator, which should be added to the method signature.
@Get(':id') findOne(@Param() params): string { console.log(params.id); return `This action returns a #${params.id} cat`; }
Plain Text
복사
@Param() is used to decorate a method parameter (params in the example above),
And makes the route parameters available as properties of that decorated method parameter inside the body of the method.
As seen in the code above, we can access the id parameter by referencing params.id.
You can also pass in a particular parameter token to the decorator, and then reference the route parameter directly by name in the method body.

HINT : import Param from @nestjs/common package.

@Get(':id') findOne(@Param('id') id: string): string { return `This action returns a #${id} cat`; }
Plain Text
복사

Sub-Domain Routing

The @Controller decorator can take a host option to require that the HTTP host of the incoming requests matches some specific value.
@Controller({ host: 'admin.example.com' }) export class AdminController { @Get() index(): string { return 'Admin page'; } }
Plain Text
복사
Similar to a route path, the hosts option can use tokens to capture the dynamic value at that position in the host name.
The host parameter token in the @Controller() decorator example below demonstrates this usage.
Host parameters declared in this way can be accessed using the @HostParam() decorator, which should be added to the method signature.

Scopes

다른 프로그래밍 언어 백그라운드에서 온 사람들은, 거의 모든 것이 들어오는 요청에서 공유되는 네스트를 배운은 것이 예상 밖일 수 있습니다.
우리는 database 에 접근하는 커넥션 풀을 가지고 있고, 글로벌 상태의 싱글톤 서비스 등 이 있습니다.
Node.js 는 모든 요청이 분리된 쓰레드에 의해서 처리되는 request/response Multi-Threaded Stateless Model 을 따르지 않는 것을 기억하십시오.
따라서 우리 어플리케이션들에서 싱글톤 인스턴스르 사용 하는 것은 fully safe 합니다.
However, there are edge-cases when request-based lifetime of the controller may be the desired behavior (대충 아닐 때가 있다는 말인듯)
예를들어, per-request caching in GraphQL applications, request tracking or multi-tenanacy. 가 있다. 어떻게 컨트롤 하는지는 나중에 배워보자.

Asynchronicity

We love modern JS and we know that data extraction(추출) is mostly asynchronous
That's why Nest supports and works well with async functions

HINT : Learn more about async / await feature HERE

Every async function has to return a Promise.
This means that you can return a deferred (연기된, 지연된) value that Nest will be able to resolve by itself. - 네스트가 자체적으로 해결 할 수 있는 지연된 벨류를 리턴 할수 있다는 뜻입니다.
Let's see an example of this :
@Get() async findAll(): Promise<any[]> { return []; }
Plain Text
복사
The above code is fully valid.

Request payloads

POST route handler 에서 클라이언트가 보낸 데이터를 DTO(Data Transfer Object) 로 받아서 사용 할 수 있는데,
DTO 는 interface 와 class 로 모두 사용 할수 있지만 class 로 사용 할 것을 추천한다.
interface 로 사용하면 이런 저런 이유 때문에 네스트가 일을 더 해야한다.
export class CreateCatDto { name: string; age: number; breed: string; } ... @Post() async create(@Body() createCatDto: CreateCatDto) { return 'This action adds a new cat'; }
Plain Text
복사

Handling errors

다른 챕터에 존재한다 HERE

Getting up and running

우리가 controller 를 완벽히 만들어도, 네스트는 CatsController 가 존재하는지 모른다.
컨트롤러는 항상 모듈에 속해있어야 한다.(우리가 컨트롤러의 배열을 @Module() 데코레이터에 포함하는 이유이다)
우리는 아직 root AppModule 을 제외하고 어떤 다른 모듈도 디파인 하지 않았기 떄문에, 우리는 CatsController 를 사용하기 위해 AppModule 을 사용한다.
import { Module } from '@nestjs/common'; import { CatsController } from './cats/cats.controller'; @Module({ controllers: [CatsController], }) export class AppModule {}
Plain Text
복사
우리는 @Module() 데코레이터를 사용하는 모듈 클레스에 메타데이터를 붙였다.
네스트는 쉽게 어떤 컨트롤러가 마운트 되었는지 반영 할 수 있다.