Zvládněte typově bezpečná volání API v TypeScriptu pro robustní, udržovatelné a bezchybné webové aplikace. Naučte se osvědčené postupy a pokročilé techniky.
Typově bezpečné volání API s TypeScriptem: Komplexní průvodce
V moderním vývoji webu je interakce s API zásadním úkolem. TypeScript se svým výkonným typovým systémem nabízí významnou výhodu při zajišťování spolehlivosti a udržovatelnosti vašich aplikací tím, že umožňuje typově bezpečná volání API. Tato příručka se zaměří na to, jak využít funkce TypeScriptu k budování robustních a bezchybných interakcí s API, pokrývající osvědčené postupy, pokročilé techniky a příklady z reálného světa.
Proč na typové bezpečnosti při volání API záleží
Když pracujete s API, v podstatě pracujete s daty pocházejícími z externího zdroje. Tato data nemusí být vždy ve formátu, který očekáváte, což vede k chybám za běhu a neočekávanému chování. Typová bezpečnost poskytuje zásadní vrstvu ochrany tím, že ověřuje, že data, která přijímáte, odpovídají předdefinované struktuře, a zachycuje potenciální problémy již v rané fázi vývoje.
- Snížení chyb za běhu: Typová kontrola v době kompilace pomáhá identifikovat a opravit chyby související s typy dříve, než se dostanou do produkce.
- Zlepšená udržovatelnost kódu: Jasné definice typů usnadňují pochopení a úpravu vašeho kódu, což snižuje riziko zavedení chyb během refaktorování.
- Vylepšená čitelnost kódu: Typové anotace poskytují cennou dokumentaci, což usnadňuje vývojářům pochopení očekávaných datových struktur.
- Lepší zkušenost vývojáře: Podpora IDE pro kontrolu typu a automatické dokončování výrazně zlepšuje zkušenost vývojáře a snižuje pravděpodobnost chyb.
Nastavení vašeho projektu TypeScript
Než se pustíte do volání API, ujistěte se, že máte nastavený projekt TypeScript. Pokud začínáte od nuly, můžete inicializovat nový projekt pomocí:
npm init -y
npm install typescript --save-dev
tsc --init
Tím se vytvoří soubor `tsconfig.json` s výchozími možnostmi kompilátoru TypeScript. Tyto možnosti můžete přizpůsobit tak, aby vyhovovaly potřebám vašeho projektu. Můžete například povolit přísný režim pro přísnější kontrolu typů:
// tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
Definování typů pro odpovědi z API
Prvním krokem k dosažení typově bezpečných volání API je definování typů TypeScript, které představují strukturu dat, která očekáváte obdržet z API. To se obvykle provádí pomocí deklarací `interface` nebo `type`.
Použití rozhraní
Rozhraní jsou mocný způsob, jak definovat tvar objektu. Pokud například načítáte seznam uživatelů z API, můžete definovat rozhraní jako:
interface User {
id: number;
name: string;
email: string;
address?: string; // Volitelná vlastnost
phone?: string; // Volitelná vlastnost
website?: string; // Volitelná vlastnost
company?: {
name: string;
catchPhrase: string;
bs: string;
};
}
Znak `?` za názvem vlastnosti označuje, že vlastnost je volitelná. To je užitečné pro zpracování odpovědí API, kde mohou chybět určitá pole.
Použití typů
Typy jsou podobné rozhraním, ale nabízejí větší flexibilitu, včetně možnosti definovat unijní typy a průnikové typy. Stejného výsledku jako rozhraní výše můžete dosáhnout pomocí typu:
type User = {
id: number;
name: string;
email: string;
address?: string; // Volitelná vlastnost
phone?: string; // Volitelná vlastnost
website?: string; // Volitelná vlastnost
company?: {
name: string;
catchPhrase: string;
bs: string;
};
};
Pro jednoduché objektové struktury jsou rozhraní a typy často zaměnitelné. Typy se však stávají výkonnějšími při řešení složitějších scénářů.
Provádění volání API s Axios
Axios je populární HTTP klient pro provádění požadavků API v JavaScriptu a TypeScriptu. Poskytuje čisté a intuitivní API, což usnadňuje zpracování různých metod HTTP, hlaviček požadavků a dat odpovědí.
Instalace Axios
npm install axios
Provádění typového volání API
Chcete-li provést typově bezpečné volání API s Axios, můžete použít metodu `axios.get` a určit očekávaný typ odpovědi pomocí generik:
import axios from 'axios';
async function fetchUsers(): Promise<User[]> {
try {
const response = await axios.get<User[]>('https://jsonplaceholder.typicode.com/users');
return response.data;
} catch (error) {
console.error('Chyba při načítání uživatelů:', error);
throw error;
}
}
fetchUsers().then(users => {
users.forEach(user => {
console.log(user.name);
});
});
V tomto příkladu `axios.get<User[]>('...')` říká TypeScriptu, že data odpovědi se očekávají jako pole objektů `User`. To umožňuje TypeScriptu poskytovat kontrolu typu a automatické dokončování při práci s daty odpovědí.
Zpracování různých metod HTTP
Axios podporuje různé metody HTTP, včetně `GET`, `POST`, `PUT`, `DELETE` a `PATCH`. Můžete použít odpovídající metody k provádění různých typů požadavků API. Například k vytvoření nového uživatele můžete použít metodu `axios.post`:
async function createUser(user: Omit<User, 'id'>): Promise<User> {
try {
const response = await axios.post<User>('https://jsonplaceholder.typicode.com/users', user);
return response.data;
} catch (error) {
console.error('Chyba při vytváření uživatele:', 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('Vytvořený uživatel:', user);
});
V tomto příkladu `Omit<User, 'id'>` vytváří typ, který je stejný jako `User`, ale bez vlastnosti `id`. To je užitečné, protože `id` je obvykle generováno serverem při vytváření nového uživatele.
Použití Fetch API
Fetch API je vestavěné JavaScript API pro provádění požadavků HTTP. I když je základnější než Axios, lze jej také použít s TypeScriptem k dosažení typově bezpečných volání API. Můžete jej preferovat, abyste se vyhnuli přidávání závislosti, pokud to vyhovuje vašim potřebám.
Provádění typového volání API s Fetch
Chcete-li provést typově bezpečné volání API s Fetch, můžete použít funkci `fetch` a poté analyzovat odpověď jako JSON, přičemž zadáte očekávaný typ odpovědi:
async function fetchUsers(): Promise<User[]> {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
if (!response.ok) {
throw new Error(`HTTP chyba! stav: ${response.status}`);
}
const data: User[] = await response.json();
return data;
} catch (error) {
console.error('Chyba při načítání uživatelů:', error);
throw error;
}
}
fetchUsers().then(users => {
users.forEach(user => {
console.log(user.name);
});
});
V tomto příkladu `const data: User[] = await response.json();` říká TypeScriptu, že data odpovědi by měla být považována za pole objektů `User`. To umožňuje TypeScriptu provádět kontrolu typu a automatické dokončování.
Zpracování různých metod HTTP s Fetch
Chcete-li provádět různé typy požadavků API s Fetch, můžete použít funkci `fetch` s různými možnostmi, jako jsou možnosti `method` a `body`. Například k vytvoření nového uživatele můžete použít následující kód:
async function createUser(user: Omit<User, 'id'>): Promise<User> {
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 chyba! stav: ${response.status}`);
}
const data: User = await response.json();
return data;
} catch (error) {
console.error('Chyba při vytváření uživatele:', 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('Vytvořený uživatel:', user);
});
Zpracování chyb API
Zpracování chyb je kritickým aspektem volání API. API mohou selhat z mnoha důvodů, včetně problémů se síťovým připojením, chyb serveru a neplatných požadavků. Je nezbytné tyto chyby elegantně zpracovat, aby vaše aplikace nespadla nebo se nezobrazilo neočekávané chování.
Použití bloků Try-Catch
Nejběžnějším způsobem, jak zpracovávat chyby v asynchronním kódu, je použití bloků try-catch. To vám umožňuje zachytit všechny výjimky, které jsou vyvolány během volání API, a zpracovat je odpovídajícím způsobem.
async function fetchUsers(): Promise<User[]> {
try {
const response = await axios.get<User[]>('https://jsonplaceholder.typicode.com/users');
return response.data;
} catch (error) {
console.error('Chyba při načítání uživatelů:', error);
// Zpracujte chybu, např. zobrazte chybovou zprávu uživateli
throw error; // Znovu vyvolejte chybu, aby ji mohl zpracovat i volající kód
}
}
Zpracování konkrétních chybových kódů
API často vrací konkrétní chybové kódy, které označují typ chyby, která nastala. Tyto chybové kódy můžete použít k zajištění specifičtějšího zpracování chyb. Například možná budete chtít zobrazit jinou chybovou zprávu pro chybu 404 Not Found než pro chybu 500 Internal Server Error.
async function fetchUser(id: number): Promise<User | null> {
try {
const response = await axios.get<User>(`https://jsonplaceholder.typicode.com/users/${id}`);
return response.data;
} catch (error: any) {
if (error.response?.status === 404) {
console.log(`Uživatel s ID ${id} nebyl nalezen.`);
return null; // Nebo vyvolat vlastní chybu
} else {
console.error('Chyba při načítání uživatele:', error);
throw error;
}
}
}
fetchUser(123).then(user => {
if (user) {
console.log('Uživatel:', user);
} else {
console.log('Uživatel nenalezen.');
}
});
Vytváření vlastních typů chyb
Pro složitější scénáře zpracování chyb můžete vytvářet vlastní typy chyb, které představují různé typy chyb API. To vám umožní poskytnout strukturovanější informace o chybách a efektivněji je zpracovávat.
class ApiError extends Error {
constructor(public statusCode: number, message: string) {
super(message);
this.name = 'ApiError';
}
}
async function fetchUser(id: number): Promise<User> {
try {
const response = await axios.get<User>(`https://jsonplaceholder.typicode.com/users/${id}`);
return response.data;
} catch (error: any) {
if (error.response?.status === 404) {
throw new ApiError(404, `Uživatel s ID ${id} nebyl nalezen.`);
} else {
console.error('Chyba při načítání uživatele:', error);
throw new ApiError(500, 'Interní chyba serveru'); // Nebo jakýkoli jiný vhodný stavový kód
}
}
}
fetchUser(123).catch(error => {
if (error instanceof ApiError) {
console.error(`Chyba API: ${error.statusCode} - ${error.message}`);
} else {
console.error('Došlo k neočekávané chybě:', error);
}
});
Validace dat
I s typovým systémem TypeScriptu je zásadní ověřovat data, která dostáváte z API, za běhu. API mohou změnit strukturu odpovědi bez upozornění a vaše typy TypeScriptu nemusí být vždy dokonale synchronizovány se skutečnou odpovědí API.
Použití Zodu pro validaci za běhu
Zod je oblíbená knihovna TypeScriptu pro validaci dat za běhu. Umožňuje definovat schémata, která popisují očekávanou strukturu vašich dat, a poté validovat data proti těmto schématům za běhu.
Instalace Zodu
npm install zod
Validace odpovědí API s Zodem
Chcete-li validovat odpovědi API pomocí Zodu, můžete definovat schéma Zod, které odpovídá vašemu typu TypeScript, a poté použít metodu `parse` k ověření dat.
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<typeof userSchema>;
async function fetchUsers(): Promise<User[]> {
try {
const response = await axios.get<unknown>('https://jsonplaceholder.typicode.com/users');
const data = z.array(userSchema).parse(response.data);
return data;
} catch (error) {
console.error('Chyba při načítání uživatelů:', error);
throw error;
}
}
V tomto příkladu `z.array(userSchema).parse(response.data)` ověřuje, že data odpovědi jsou pole objektů, které odpovídají `userSchema`. Pokud data neodpovídají schématu, Zod vyvolá chybu, kterou pak můžete vhodně zpracovat.
Pokročilé techniky
Použití generik pro znovupoužitelné funkce API
Generika vám umožňují psát znovupoužitelné funkce API, které dokážou zpracovat různé typy dat. Můžete například vytvořit generickou funkci `fetchData`, která dokáže načíst data z libovolného koncového bodu API a vrátit je se správným typem.
async function fetchData<T>(url: string): Promise<T> {
try {
const response = await axios.get<T>(url);
return response.data;
} catch (error) {
console.error(`Chyba při načítání dat z ${url}:`, error);
throw error;
}
}
// Použití
fetchData<User[]>('https://jsonplaceholder.typicode.com/users').then(users => {
console.log('Uživatelé:', users);
});
fetchData<{ title: string; body: string }>('https://jsonplaceholder.typicode.com/todos/1').then(todo => {
console.log('Todo', todo)
});
Použití interceptorů pro globální zpracování chyb
Axios poskytuje interceptory, které vám umožňují zachytit požadavky a odpovědi před jejich zpracováním vaším kódem. Interceptory můžete použít k implementaci globálního zpracování chyb, jako je protokolování chyb nebo zobrazení chybových zpráv uživateli.
axios.interceptors.response.use(
(response) => response,
(error) => {
console.error('Globální obsluha chyb:', error);
// Zobrazte chybovou zprávu uživateli
return Promise.reject(error);
}
);
Použití proměnných prostředí pro adresy URL API
Abyste se vyhnuli hardcodingu adres URL API ve vašem kódu, můžete použít proměnné prostředí k uložení adres URL. To usnadňuje konfiguraci vaší aplikace pro různá prostředí, jako je vývoj, staging a produkce.
Příklad použití souboru `.env` a balíčku `dotenv`.
// .env
API_URL=https://api.example.com
// Instalace dotenv
npm install dotenv
// Import a konfigurace dotenv
import * as dotenv from 'dotenv'
dotenv.config()
const apiUrl = process.env.API_URL || 'http://localhost:3000'; // provide a default value
async function fetchData<T>(endpoint: string): Promise<T> {
try {
const response = await axios.get<T>(`${apiUrl}/${endpoint}`);
return response.data;
} catch (error) {
console.error(`Chyba při načítání dat z ${apiUrl}/${endpoint}:`, error);
throw error;
}
}
Závěr
Typově bezpečná volání API jsou nezbytná pro vytváření robustních, udržovatelných a bezchybných webových aplikací. TypeScript poskytuje výkonné funkce, které vám umožňují definovat typy pro odpovědi API, validovat data za běhu a elegantně zpracovávat chyby. Dodržováním osvědčených postupů a technik popsaných v této příručce můžete výrazně zlepšit kvalitu a spolehlivost vašich interakcí s API.
Používáním TypeScriptu a knihoven jako Axios a Zod můžete zajistit, aby vaše volání API byla typově bezpečná, vaše data byla validována a vaše chyby byly elegantně zpracovány. To povede k robustnějším a udržitelnějším aplikacím.
Nezapomeňte vždy validovat data za běhu, a to i s typovým systémem TypeScriptu. API se mohou měnit a vaše typy nemusí být vždy dokonale synchronizovány se skutečnou odpovědí API. Validací dat za běhu můžete zachytit potenciální problémy dříve, než způsobí problémy ve vaší aplikaci.
Šťastné kódování!