Антон Ларичев
Как на frontend, так и на backend нам приходится работать с внешним API. Особенную боль доставляют внешние API, которые не привязаны к вашему релизному циклу и могут меняться как бог на душу положит. Поэтому хорошо иметь способ из валидировать без лапши кода.
Для примера, допустим мы стучимся в сервис, который выдаёт нам информацию о нашем подписчике - его email и подписан он или нет. Нам нужно для дальнейшей работы обеспечить наличие этих двух полей. Идём в тупую!
const getData = async () => {
const { data } = await axios.get('https://my-api/1');
if(!data.email) {
throw new Error('Нет адреса почты');
}
if (!data.isSubscribed) {
throw new Error('Нет информации о подписке');
}
return data;
}
В целом выглядит не очень страшно... пока у нас 2 поля. А представьте 10 или 20? А если будут вложенные структуры 🤯? К тому же мы тут ещё не проверили, что почта имеет корректный формат. Как бы хотелось иметь более декларативный способ обработки ошибок! И он есть: class-validator
.
Если вы работали с NestJS, то наверняка с ним неявно сталкивались при написании pipes. Давайте его тут используем.
Шаг 1: опишем наш приходящий класс:
class ExternalData {
constructor(data: ExternalData) {
Object.assign(this, data);
}
email: string;
isSubscribed: boolean;
}
Шаг 2: Теперь давайте докинем ему декораторов, которые будут описывать нужные данные:
import { IsBoolean, IsEmail, IsString } from 'class-validator';
class ExternalData {
constructor(data: ExternalData) {
Object.assign(this, data);
}
@IsString({ message: 'Нет адреса почты' })
@IsEmail({}, { message: 'Неверный формат адреса почты'})
email: string;
@IsBoolean({ message: 'Нет информации о подписке'})
isSubscribed: boolean;
}
В каждом из них мы можем прописать дополнительные опции, в том числе своё сообщение об ошибке, если оно необходимо. Мы фактически описали все наши данные по их формату и типу за 3 строчки код (класс бы нам всё равно нужен был в виде интерфейса для получения данных).
Конструктор класса нам будет необходим для быстрого создания инстанса с пришедшими данными.
Шаг 3: Magic!
import { validate } from 'class-validator';
const getData = async () => {
const { data } = await axios.get('https://my-api/1');
validate(new ExternalData(data)).then(errors => {
if (errors.length > 0) {
// Пришедшие данные не верны
} else {
// Всё верно!
}
});
}
В результате нам достаточно просто вызвать validate
для инстанса класса и в errors
мы получим список ошибок с текстом и указанием где именно оно произошло. Всё! Наш класс прошёл валидацию, и мы можем спокойно с ним работать. Если нет - отправляем ошибки интерации в лог или внешнюю систему, чтобы оповестить разработчиков, что злые разработчики стороннего API опять строят нам козни!
Комментарии
0