Опануйте типобезпечні запити до API в TypeScript для створення надійних, підтримуваних та безпомилкових вебзастосунків. Вивчіть найкращі практики та передові техніки.
Типобезпечні запити до API за допомогою TypeScript: вичерпний посібник
У сучасній веброзробці взаємодія з API є фундаментальним завданням. TypeScript, з його потужною системою типів, пропонує значну перевагу у забезпеченні надійності та підтримуваності ваших застосунків, дозволяючи виконувати типобезпечні запити до API. Цей посібник розповість, як використовувати можливості TypeScript для створення надійних та безпомилкових взаємодій з API, охоплюючи найкращі практики, передові техніки та реальні приклади.
Чому безпека типів важлива для запитів до API
Працюючи з API, ви по суті маєте справу з даними, що надходять із зовнішнього джерела. Ці дані не завжди можуть мати очікуваний формат, що призводить до помилок під час виконання та непередбачуваної поведінки. Безпека типів забезпечує критично важливий рівень захисту, перевіряючи, що отримані дані відповідають попередньо визначеній структурі, що дозволяє виявляти потенційні проблеми на ранніх етапах процесу розробки.
- Зменшення помилок під час виконання: Перевірка типів на етапі компіляції допомагає виявити та виправити помилки, пов'язані з типами, перш ніж вони потраплять у продакшн.
- Покращена підтримка коду: Чіткі визначення типів роблять ваш код легшим для розуміння та модифікації, зменшуючи ризик виникнення помилок під час рефакторингу.
- Покращена читабельність коду: Анотації типів надають цінну документацію, що полегшує розробникам розуміння очікуваних структур даних.
- Кращий досвід розробника: Підтримка IDE для перевірки типів та автодоповнення значно покращує досвід розробника та зменшує ймовірність помилок.
Налаштування вашого проєкту TypeScript
Перш ніж занурюватися у запити до API, переконайтеся, що у вас налаштований проєкт TypeScript. Якщо ви починаєте з нуля, ви можете ініціалізувати новий проєкт за допомогою:
npm init -y
npm install typescript --save-dev
tsc --init
Це створить файл `tsconfig.json` з налаштуваннями компілятора TypeScript за замовчуванням. Ви можете налаштувати ці параметри відповідно до потреб вашого проєкту. Наприклад, ви можете увімкнути строгий режим для суворішої перевірки типів:
// tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
Визначення типів для відповідей API
Першим кроком до досягнення типобезпечних запитів до API є визначення типів TypeScript, які представляють структуру даних, які ви очікуєте отримати від API. Зазвичай це робиться за допомогою оголошень `interface` або `type`.
Використання інтерфейсів
Інтерфейси — це потужний спосіб визначення форми об'єкта. Наприклад, якщо ви отримуєте список користувачів з API, ви можете визначити такий інтерфейс:
interface User {
id: number;
name: string;
email: string;
address?: string; // Необов'язкова властивість
phone?: string; // Необов'язкова властивість
website?: string; // Необов'язкова властивість
company?: {
name: string;
catchPhrase: string;
bs: string;
};
}
Знак `?` після назви властивості вказує, що властивість є необов'язковою. Це корисно для обробки відповідей API, де певні поля можуть бути відсутніми.
Використання типів
Типи схожі на інтерфейси, але пропонують більшу гнучкість, включаючи можливість визначати об'єднання типів та перетини типів. Ви можете досягти того ж результату, що й з інтерфейсом вище, використовуючи тип:
type User = {
id: number;
name: string;
email: string;
address?: string; // Необов'язкова властивість
phone?: string; // Необов'язкова властивість
website?: string; // Необов'язкова властивість
company?: {
name: string;
catchPhrase: string;
bs: string;
};
};
Для простих структур об'єктів інтерфейси та типи часто є взаємозамінними. Однак типи стають потужнішими при роботі з більш складними сценаріями.
Виконання запитів до API за допомогою Axios
Axios — це популярний HTTP-клієнт для виконання запитів до API в JavaScript та TypeScript. Він надає чистий та інтуїтивно зрозумілий API, що полегшує роботу з різними методами HTTP, заголовками запитів та даними відповіді.
Встановлення Axios
npm install axios
Виконання типізованого запиту до API
Щоб зробити типобезпечний запит до API за допомогою Axios, ви можете використати метод `axios.get` та вказати очікуваний тип відповіді, використовуючи дженерики:
import axios from 'axios';
async function fetchUsers(): Promise {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/users');
return response.data;
} catch (error) {
console.error('Помилка отримання користувачів:', error);
throw error;
}
}
fetchUsers().then(users => {
users.forEach(user => {
console.log(user.name);
});
});
У цьому прикладі `axios.get
Обробка різних методів HTTP
Axios підтримує різні методи HTTP, включаючи `GET`, `POST`, `PUT`, `DELETE` та `PATCH`. Ви можете використовувати відповідні методи для виконання різних типів запитів до API. Наприклад, для створення нового користувача, ви можете використати метод `axios.post`:
async function createUser(user: Omit): Promise {
try {
const response = await axios.post('https://jsonplaceholder.typicode.com/users', user);
return response.data;
} catch (error) {
console.error('Помилка створення користувача:', error);
throw error;
}
}
const newUser = {
name: 'John Doe',
email: 'john.doe@example.com',
address: '123 Main St',
phone: '555-1234',
website: 'example.com',
company: {
name: 'Example Corp',
catchPhrase: 'Leading the way',
bs: 'Innovative solutions'
}
};
createUser(newUser).then(user => {
console.log('Створено користувача:', user);
});
У цьому прикладі `Omit
Використання Fetch API
Fetch API — це вбудований JavaScript API для виконання HTTP-запитів. Хоча він є більш базовим, ніж Axios, його також можна використовувати з TypeScript для досягнення типобезпечних запитів до API. Ви можете віддати йому перевагу, щоб уникнути додавання залежностей, якщо він відповідає вашим потребам.
Виконання типізованого запиту до API за допомогою Fetch
Щоб зробити типобезпечний запит до API за допомогою Fetch, ви можете використати функцію `fetch`, а потім розпарсити відповідь як JSON, вказавши очікуваний тип відповіді:
async function fetchUsers(): Promise {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data: User[] = await response.json();
return data;
} catch (error) {
console.error('Помилка отримання користувачів:', error);
throw error;
}
}
fetchUsers().then(users => {
users.forEach(user => {
console.log(user.name);
});
});
У цьому прикладі `const data: User[] = await response.json();` повідомляє TypeScript, що дані відповіді слід розглядати як масив об'єктів `User`. Це дозволяє TypeScript виконувати перевірку типів та автодоповнення.
Обробка різних методів HTTP за допомогою Fetch
Щоб робити різні типи запитів до API за допомогою Fetch, ви можете використовувати функцію `fetch` з різними опціями, такими як `method` та `body`. Наприклад, для створення нового користувача, ви можете використати такий код:
async function createUser(user: Omit): Promise {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data: User = await response.json();
return data;
} catch (error) {
console.error('Помилка створення користувача:', error);
throw error;
}
}
const newUser = {
name: 'John Doe',
email: 'john.doe@example.com',
address: '123 Main St',
phone: '555-1234',
website: 'example.com',
company: {
name: 'Example Corp',
catchPhrase: 'Leading the way',
bs: 'Innovative solutions'
}
};
createUser(newUser).then(user => {
console.log('Створено користувача:', user);
});
Обробка помилок API
Обробка помилок є критично важливим аспектом запитів до API. API можуть зазнавати збоїв з багатьох причин, включаючи проблеми з мережевим підключенням, помилки сервера та недійсні запити. Важливо коректно обробляти ці помилки, щоб запобігти збоям вашого застосунку або відображенню несподіваної поведінки.
Використання блоків try-catch
Найпоширеніший спосіб обробки помилок в асинхронному коді — це використання блоків try-catch. Це дозволяє вам перехоплювати будь-які винятки, що виникають під час запиту до API, та обробити їх належним чином.
async function fetchUsers(): Promise {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/users');
return response.data;
} catch (error) {
console.error('Помилка отримання користувачів:', error);
// Обробити помилку, наприклад, показати повідомлення про помилку користувачу
throw error; // Повторно викинути помилку, щоб дозволити коду, що викликає, також її обробити
}
}
Обробка конкретних кодів помилок
API часто повертають конкретні коди помилок, щоб вказати на тип помилки, що сталася. Ви можете використовувати ці коди помилок для більш специфічної обробки. Наприклад, ви можете захотіти відобразити інше повідомлення про помилку для помилки 404 Not Found, ніж для помилки 500 Internal Server Error.
async function fetchUser(id: number): Promise {
try {
const response = await axios.get(`https://jsonplaceholder.typicode.com/users/${id}`);
return response.data;
} catch (error: any) {
if (error.response?.status === 404) {
console.log(`Користувача з ID ${id} не знайдено.`);
return null; // Або викинути власну помилку
} else {
console.error('Помилка отримання користувача:', error);
throw error;
}
}
}
fetchUser(123).then(user => {
if (user) {
console.log('Користувач:', user);
} else {
console.log('Користувача не знайдено.');
}
});
Створення власних типів помилок
Для складніших сценаріїв обробки помилок ви можете створювати власні типи помилок для представлення різних типів помилок API. Це дозволяє вам надавати більш структуровану інформацію про помилки та ефективніше обробляти їх.
class ApiError extends Error {
constructor(public statusCode: number, message: string) {
super(message);
this.name = 'ApiError';
}
}
async function fetchUser(id: number): Promise {
try {
const response = await axios.get(`https://jsonplaceholder.typicode.com/users/${id}`);
return response.data;
} catch (error: any) {
if (error.response?.status === 404) {
throw new ApiError(404, `Користувача з ID ${id} не знайдено.`);
} else {
console.error('Помилка отримання користувача:', error);
throw new ApiError(500, 'Internal Server Error'); //Або будь-який інший відповідний код стану
}
}
}
fetchUser(123).catch(error => {
if (error instanceof ApiError) {
console.error(`Помилка API: ${error.statusCode} - ${error.message}`);
} else {
console.error('Сталася неочікувана помилка:', error);
}
});
Валідація даних
Навіть із системою типів TypeScript, критично важливо валідувати дані, які ви отримуєте від API, під час виконання. API можуть змінювати структуру своєї відповіді без попередження, і ваші типи TypeScript не завжди можуть бути ідеально синхронізовані з фактичною відповіддю API.
Використання Zod для валідації під час виконання
Zod — це популярна бібліотека TypeScript для валідації даних під час виконання. Вона дозволяє вам визначати схеми, які описують очікувану структуру ваших даних, а потім валідувати дані за цими схемами під час виконання.
Встановлення Zod
npm install zod
Валідація відповідей API за допомогою Zod
Щоб валідувати відповіді API за допомогою Zod, ви можете визначити схему Zod, яка відповідає вашому типу TypeScript, а потім використовувати метод `parse` для валідації даних.
import { z } from 'zod';
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
address: z.string().optional(),
phone: z.string().optional(),
website: z.string().optional(),
company: z.object({
name: z.string(),
catchPhrase: z.string(),
bs: z.string(),
}).optional(),
});
type User = z.infer;
async function fetchUsers(): Promise {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/users');
const data = z.array(userSchema).parse(response.data);
return data;
} catch (error) {
console.error('Помилка отримання користувачів:', error);
throw error;
}
}
У цьому прикладі `z.array(userSchema).parse(response.data)` перевіряє, що дані відповіді є масивом об'єктів, що відповідають `userSchema`. Якщо дані не відповідають схемі, Zod викине помилку, яку ви можете обробити належним чином.
Передові техніки
Використання дженериків для повторно використовуваних функцій API
Дженерики дозволяють писати повторно використовувані функції API, які можуть працювати з різними типами даних. Наприклад, ви можете створити загальну функцію `fetchData`, яка може отримувати дані з будь-якої кінцевої точки API та повертати їх з правильним типом.
async function fetchData(url: string): Promise {
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(`Помилка отримання даних з ${url}:`, error);
throw error;
}
}
// Використання
fetchData('https://jsonplaceholder.typicode.com/users').then(users => {
console.log('Користувачі:', users);
});
fetchData<{ title: string; body: string }>('https://jsonplaceholder.typicode.com/todos/1').then(todo => {
console.log('Завдання', todo)
});
Використання перехоплювачів для глобальної обробки помилок
Axios надає перехоплювачі (interceptors), які дозволяють вам перехоплювати запити та відповіді до того, як вони будуть оброблені вашим кодом. Ви можете використовувати перехоплювачі для реалізації глобальної обробки помилок, наприклад, для логування помилок або відображення повідомлень про помилки користувачеві.
axios.interceptors.response.use(
(response) => response,
(error) => {
console.error('Глобальний обробник помилок:', error);
// Показати повідомлення про помилку користувачеві
return Promise.reject(error);
}
);
Використання змінних середовища для URL-адрес API
Щоб уникнути жорсткого кодування URL-адрес API у вашому коді, ви можете використовувати змінні середовища для зберігання URL-адрес. Це полегшує конфігурацію вашого застосунку для різних середовищ, таких як розробка, тестування та продакшн.
Приклад з використанням файлу `.env` та пакета `dotenv`.
// .env
API_URL=https://api.example.com
// Встановлення dotenv
npm install dotenv
// Імпортувати та налаштувати dotenv
import * as dotenv from 'dotenv'
dotenv.config()
const apiUrl = process.env.API_URL || 'http://localhost:3000'; // надати значення за замовчуванням
async function fetchData(endpoint: string): Promise {
try {
const response = await axios.get(`${apiUrl}/${endpoint}`);
return response.data;
} catch (error) {
console.error(`Помилка отримання даних з ${apiUrl}/${endpoint}:`, error);
throw error;
}
}
Висновок
Типобезпечні запити до API є важливими для створення надійних, підтримуваних та безпомилкових вебзастосунків. TypeScript надає потужні можливості, що дозволяють визначати типи для відповідей API, валідувати дані під час виконання та коректно обробляти помилки. Дотримуючись найкращих практик та технік, викладених у цьому посібнику, ви можете значно покращити якість та надійність ваших взаємодій з API.
Використовуючи TypeScript та бібліотеки, такі як Axios та Zod, ви можете забезпечити, що ваші запити до API є типобезпечними, ваші дані валідовані, а помилки обробляються належним чином. Це призведе до створення більш надійних та підтримуваних застосунків.
Пам'ятайте, що завжди потрібно валідувати дані під час виконання, навіть із системою типів TypeScript. API можуть змінюватися, і ваші типи не завжди можуть бути ідеально синхронізовані з фактичною відповіддю API. Валідуючи дані під час виконання, ви можете виявити потенційні проблеми до того, як вони спричинять проблеми у вашому застосунку.
Вдалого кодування!