Пошук уроків, статей та іншого контенту
Розглянете доступ до HTTP-запиту й відповіді, заголовків, статус-кодів і методів надсилання даних клієнту.
HTTP-взаємодія складається з двох частин:
Request — запит клієнта до сервера;
Response — відповідь сервера клієнту.
У NestJS контролер зазвичай отримує дані запиту через параметри методів, а результат методу автоматично стає HTTP-відповіддю.
@Get('users')
getUsers() {
return [
{ id: 1, name: 'Anna' },
{ id: 2, name: 'Oleh' },
];
}NestJS перетворить масив на JSON і відправить його клієнту зі статус-кодом 200 OK.
Іноді потрібно отримати доступ до всього HTTP-запиту або вручну керувати відповіддю. Для цього використовують об’єкти Request і Response.
Об’єкт запиту можна отримати за допомогою декоратора @Req().
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller('info')
export class InfoController {
@Get()
getRequestInfo(@Req() request: Request) {
return {
method: request.method,
url: request.url,
headers: request.headers,
};
}
}Тепер запит:
GET /infoможе повернути приблизно такі дані:
{
"method": "GET",
"url": "/info",
"headers": {
"host": "localhost:3000",
"user-agent": "Mozilla/5.0",
"accept": "*/*"
}
}У прикладі використано тип Request з пакета express. Стандартний HTTP-адаптер NestJS зазвичай використовує Express.
Найчастіше використовують такі властивості:
request.method — HTTP-метод запиту;
request.url — URL запиту;
request.headers — заголовки;
request.params — параметри маршруту;
request.query — параметри рядка запиту;
request.body — тіло запиту.
У цій темі зосередимося на заголовках і загальній інформації про запит.
Заголовки передають додаткову інформацію про запит: тип даних, токен авторизації, мову клієнта та інші значення.
Отримати заголовок можна через request.headers:
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller('headers')
export class HeadersController {
@Get()
getHeaders(@Req() request: Request) {
return {
userAgent: request.headers['user-agent'],
authorization: request.headers.authorization,
contentType: request.headers['content-type'],
};
}
}Назви заголовків у Node.js зазвичай доступні в нижньому регістрі. Тому для заголовка User-Agent використовується ключ 'user-agent'.
Значення заголовка може бути відсутнім. У такому випадку його значенням буде undefined.
Для доступу до одного заголовка також можна використовувати метод Express request.get():
@Get('language')
getLanguage(@Req() request: Request) {
return {
language: request.get('accept-language') ?? 'uk',
};
}Оператор ?? використовується, щоб установити значення 'uk', якщо заголовок не було передано.
Об’єкт відповіді можна отримати за допомогою декоратора @Res().
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
@Controller('response')
export class ResponseController {
@Get()
sendResponse(@Res() response: Response) {
response.status(200).json({
message: 'Відповідь сформовано вручну',
});
}
}Метод response.json() перетворює переданий об’єкт на JSON і надсилає його клієнту.
Коли використовується @Res() без додаткових параметрів, відповідальність за надсилання відповіді переходить до розробника. Тому в методі потрібно викликати один із методів:
response.send();
response.json();
response.end().
send()Метод send() надсилає відповідь клієнту. Його можна використовувати для тексту, HTML або інших простих даних.
@Get('message')
sendMessage(@Res() response: Response) {
response.send('Вітаємо у NestJS!');
}json()Метод json() використовується для надсилання JSON-відповіді:
@Get('data')
sendData(@Res() response: Response) {
response.json({
success: true,
data: {
id: 1,
name: 'Anna',
},
});
}У REST API найчастіше використовують саме json().
Статус-код повідомляє клієнту, чим завершився запит.
Поширені статус-коди:
200 OK — запит успішно виконано;
201 Created — ресурс створено;
204 No Content — запит успішний, але відповідь не містить даних;
400 Bad Request — некоректний запит;
401 Unauthorized — потрібна автентифікація;
403 Forbidden — доступ заборонено;
404 Not Found — ресурс не знайдено;
500 Internal Server Error — помилка на сервері.
Статус можна встановити методом status():
import { Controller, Get, HttpStatus, Res } from '@nestjs/common';
import { Response } from 'express';
@Controller('products')
export class ProductsController {
@Get()
getProducts(@Res() response: Response) {
response.status(HttpStatus.OK).json({
items: [],
});
}
@Get('created')
createResult(@Res() response: Response) {
response.status(HttpStatus.CREATED).json({
message: 'Ресурс створено',
});
}
}HttpStatus.OK і HttpStatus.CREATED — іменовані константи NestJS для відповідних числових кодів.
Також можна передати число безпосередньо:
response.status(201).json({
message: 'Ресурс створено',
});Використання HttpStatus зазвичай робить код зрозумілішим.
Сервер також може додавати заголовки до відповіді.
Для цього в Express використовується метод setHeader():
@Get('version')
getVersion(@Res() response: Response) {
response.setHeader('X-Application-Version', '1.0.0');
response.json({
message: 'Заголовок додано',
});
}У результаті клієнт отримає заголовок:
X-Application-Version: 1.0.0Заголовки потрібно встановити до надсилання тіла відповіді. Після виклику json() або send() відповідь зазвичай уже відправляється клієнту.
Нижче наведено контролер, який демонструє роботу із запитом, його заголовками, статус-кодом і заголовками відповіді.
import {
Controller,
Get,
HttpStatus,
Req,
Res,
} from '@nestjs/common';
import { Request, Response } from 'express';
@Controller('http')
export class HttpController {
@Get('request')
getRequest(@Req() request: Request) {
return {
method: request.method,
url: request.url,
userAgent: request.headers['user-agent'] ?? 'Невідомий клієнт',
language: request.headers['accept-language'] ?? 'Не вказано',
};
}
@Get('response')
getResponse(@Res() response: Response) {
// Додаємо власний заголовок відповіді
response.setHeader('X-Application', 'NestJS Demo');
// Встановлюємо статус і надсилаємо JSON
response.status(HttpStatus.OK).json({
success: true,
message: 'Відповідь успішно надіслано',
});
}
@Get('created')
getCreated(@Res() response: Response) {
response.status(HttpStatus.CREATED).json({
success: true,
message: 'Дані створено',
});
}
@Get('text')
getText(@Res() response: Response) {
response.status(HttpStatus.OK).send('Текстова відповідь');
}
}Якщо цей контролер підключено до модуля, доступними будуть такі маршрути:
GET /http/request — інформація про запит;
GET /http/response — JSON-відповідь із власним заголовком;
GET /http/created — відповідь зі статусом 201;
GET /http/text — текстова відповідь.
У NestJS є два основні підходи до формування відповіді.
Метод повертає дані, а NestJS самостійно формує відповідь:
@Get('automatic')
getAutomaticResponse() {
return {
message: 'NestJS сформував відповідь автоматично',
};
}Цей підхід є простішим і рекомендованим для більшості звичайних маршрутів.
Метод отримує @Res() і самостійно формує відповідь:
@Get('manual')
getManualResponse(@Res() response: Response) {
response.status(HttpStatus.OK).json({
message: 'Відповідь сформовано вручну',
});
}Ручний підхід потрібен, коли необхідно безпосередньо керувати:
статус-кодом;
заголовками;
форматом надсилання даних;
особливостями HTTP-відповіді.
Якщо потрібно лише змінити статус або додати заголовок, можна залишити NestJS відповідальність за надсилання даних.
Для цього використовується параметр { passthrough: true }:
import {
Controller,
Get,
Header,
HttpCode,
HttpStatus,
Res,
} from '@nestjs/common';
import { Response } from 'express';
@Controller('settings')
export class SettingsController {
@Get('status')
@HttpCode(HttpStatus.CREATED)
getWithStatus() {
return {
message: 'Відповідь має статус 201',
};
}
@Get('header')
getWithHeader(@Res({ passthrough: true }) response: Response) {
response.setHeader('X-Application', 'NestJS');
return {
message: 'NestJS сам надішле цю відповідь',
};
}
}У такому випадку:
@Res({ passthrough: true }) дозволяє змінити об’єкт відповіді;
повернення об’єкта залишається відповідальністю NestJS;
не потрібно викликати response.json() вручну.
Для зміни стандартного статусу також можна застосовувати декоратор @HttpCode():
@HttpCode(HttpStatus.CREATED)
@Get('created')
getCreated() {
return {
message: 'Ресурс створено',
};
}Не потрібно одночасно викликати response.json() і повертати значення:
@Get('wrong')
wrong(@Res() response: Response) {
response.json({ message: 'Готово' });
return {
message: 'Це зайве повернення',
};
}У цьому випадку відповідь уже було надіслано через response.json().
Використовуйте один із підходів:
@Get('correct')
correct() {
return {
message: 'NestJS надішле відповідь автоматично',
};
}або:
@Get('also-correct')
alsoCorrect(@Res() response: Response) {
response.json({
message: 'Відповідь надіслано вручну',
});
}send() або json()Якщо метод отримує @Res(), але не надсилає відповідь, клієнт може довго чекати:
@Get('incomplete')
incomplete(@Res() response: Response) {
response.status(200);
// Відповідь не надіслано
}Потрібно завершити відповідь:
@Get('complete')
complete(@Res() response: Response) {
response.status(200).json({
message: 'Відповідь завершено',
});
}Неправильно спочатку надсилати відповідь, а потім змінювати її заголовки:
@Get('wrong-header')
wrongHeader(@Res() response: Response) {
response.json({ message: 'Готово' });
response.setHeader('X-Test', 'value');
}Заголовки потрібно встановлювати перед json() або send():
@Get('correct-header')
correctHeader(@Res() response: Response) {
response.setHeader('X-Test', 'value');
response.json({ message: 'Готово' });
}Статус 200 не підходить для кожної успішної операції. Наприклад, після створення нового ресурсу часто використовують 201 Created.
Вибирайте статус-код відповідно до результату операції.
@Req() надає доступ до HTTP-запиту.
Через Request можна прочитати метод, URL і заголовки запиту.
@Res() надає прямий доступ до HTTP-відповіді.
Метод json() надсилає JSON, а send() — текст або інші прості дані.
Статус відповіді встановлюється через response.status() або @HttpCode().
Заголовки відповіді додаються до її надсилання.
Не потрібно змішувати автоматичне повернення даних із ручним викликом response.json().
Для більшості маршрутів зручно повертати дані без @Res(), залишаючи формування відповіді NestJS.