Skip to content

Latest commit

 

History

History
289 lines (198 loc) · 6.64 KB

2.5.md

File metadata and controls

289 lines (198 loc) · 6.64 KB

Praca z API / Working with APIs


Why it matters / Dlaczego to ważne

Most modern apps integrate with external services through APIs.

Większość nowoczesnych aplikacji integruje się z zewnętrznymi serwisami przez API.

Documentation:

Requests: HTTP for Humans

Video:

Corey Schafer — Requests Library (0:00–30:00)


Installing requests / Instalacja requests

uv add requests

GET requests / Żądania GET

GET requests fetch data from a server.

Żądania GET pobierają dane z serwera.

Let's use a currency exchange rate API - useful for real apps like expense trackers or shopping carts.

Użyjmy API kursów walut - przydatne w prawdziwych aplikacjach jak trackery wydatków czy koszyki zakupowe.

Create api_demo.py:

Utwórz api_demo.py:

import requests

# Get latest exchange rates / Pobierz najnowsze kursy walut
response = requests.get("https://api.frankfurter.dev/latest?from=USD")

print(f"Status: {response.status_code}")

if response.status_code == 200:
    data = response.json()
    print(f"Base currency: {data['base']}")
    print(f"Date: {data['date']}")
    print(f"USD to EUR: {data['rates']['EUR']:.4f}")
    print(f"USD to PLN: {data['rates']['PLN']:.4f}")

Run:

Uruchom:

uv run python api_demo.py

Status codes / Kody statusu

Code Meaning Znaczenie
200 OK Sukces
404 Not Found Nie znaleziono
500 Server Error Błąd serwera

URL parameters / Parametry URL

import requests

# Convert 100 USD to specific currencies / Konwertuj 100 USD na konkretne waluty
params = {
    "from": "USD",
    "to": "EUR,PLN,GBP",
    "amount": 100
}

response = requests.get("https://api.frankfurter.dev/latest", params=params)

if response.status_code == 200:
    data = response.json()
    print(f"Converting {data['amount']} {data['base']}:")

    for currency, rate in data['rates'].items():
        print(f"  {currency}: {rate:.2f}")

POST requests / Żądania POST

POST sends data to create resources.

POST wysyła dane aby utworzyć zasoby.

import requests

new_post = {
    "title": "My Post",
    "body": "Content here",
    "userId": 1
}

response = requests.post(
    "https://jsonplaceholder.typicode.com/posts",
    json=new_post
)

if response.status_code == 201:
    created = response.json()
    print(f"Created post ID: {created['id']}")

Error handling / Obsługa błędów

Always handle network errors.

Zawsze obsługuj błędy sieciowe.

import requests
import logging

logger = logging.getLogger(__name__)

def get_exchange_rate(from_currency: str, to_currency: str) -> float | None:
    try:
        url = f"https://api.frankfurter.dev/latest?from={from_currency}&to={to_currency}"
        response = requests.get(url, timeout=5)
        response.raise_for_status()

        data = response.json()
        return data['rates'][to_currency]

    except requests.exceptions.HTTPError:
        logger.error(f"HTTP error {response.status_code}")
        return None
    except requests.exceptions.ConnectionError:
        logger.error("Could not connect to exchange rate API")
        return None
    except requests.exceptions.Timeout:
        logger.warning("Request timeout")
        return None
    except KeyError:
        logger.error(f"Invalid currency: {from_currency} or {to_currency}")
        return None
    except Exception:
        logger.exception("Unexpected error getting exchange rate")
        return None

rate = get_exchange_rate("USD", "EUR")
if rate:
    print(f"1 USD = {rate:.4f} EUR")

Real-world example: currency converter / Przykład z życia: konwerter walut

This is how I wrap APIs in my projects.

Tak opakowuję API w moich projektach.

import requests
import logging
from datetime import date

logger = logging.getLogger(__name__)

class CurrencyConverter:
    BASE_URL = "https://api.frankfurter.dev"

    def __init__(self, timeout: int = 5):
        self.timeout = timeout

    def convert(self, amount: float, from_currency: str, to_currency: str) -> float | None:
        """Convert amount from one currency to another"""
        try:
            response = requests.get(
                f"{self.BASE_URL}/latest",
                params={"from": from_currency, "to": to_currency, "amount": amount},
                timeout=self.timeout
            )
            response.raise_for_status()
            data = response.json()
            return data['rates'][to_currency]
        except Exception:
            logger.exception(f"Failed to convert {from_currency} to {to_currency}")
            return None

    def get_historical_rate(self, currency_from: str, currency_to: str,
                           date_str: str) -> float | None:
        """Get historical exchange rate for specific date"""
        try:
            response = requests.get(
                f"{self.BASE_URL}/{date_str}",
                params={"from": currency_from, "to": currency_to},
                timeout=self.timeout
            )
            response.raise_for_status()
            data = response.json()
            return data['rates'][currency_to]
        except Exception:
            logger.exception(f"Failed to get historical rate for {date_str}")
            return None

# Usage / Użycie
logging.basicConfig(level=logging.INFO)
converter = CurrencyConverter()

# Convert 100 USD to EUR / Konwertuj 100 USD na EUR
result = converter.convert(100, "USD", "EUR")
if result:
    print(f"100 USD = {result:.2f} EUR")

# Get rate from last year / Pobierz kurs z zeszłego roku
rate = converter.get_historical_rate("USD", "PLN", "2023-01-01")
if rate:
    print(f"USD/PLN on 2023-01-01: {rate:.4f}")

Timeouts / Limity czasu

Always set timeouts to avoid hanging.

Zawsze ustawiaj limity czasu aby uniknąć zawieszenia.

# Good - with timeout / Dobrze - z limitem
response = requests.get(url, timeout=5)

# Bad - can hang forever / Źle - może zawiesić się na zawsze
# response = requests.get(url)

Podsumowanie / Summary

After this section you can:

Po tej sekcji potrafisz:

  • make GET requests to fetch data

    wykonywać żądania GET aby pobierać dane

  • send POST requests to create resources

    wysyłać żądania POST aby tworzyć zasoby

  • pass URL parameters

    przekazywać parametry URL

  • handle HTTP errors and network issues

    obsługiwać błędy HTTP i problemy sieciowe

  • set timeouts properly

    ustawiać limity czasu poprawnie

  • build API wrapper classes

    budować klasy wrapper dla API


Next: 2.6 — Linters i formatery