Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

HTTP - protokół wymiany danych

Witaj ponownie, @name! Darwin tutaj.

W poprzedniej lekcji nauczyłeś/aś się formatów danych - jak przechowywać informacje (JSON, CSV, XML, YAML). Teraz czas na HTTP - protokół, który pozwala przesyłać te dane przez internet!

Analogia Safari: Formaty danych to język, w którym zapisujesz obserwacje. HTTP to system kurierski - sposób, w jaki wysyłasz te obserwacje między stacjami badawczymi w różnych częściach Afryki! 📦🌍

Czym jest HTTP?

HTTP (HyperText Transfer Protocol) to protokół komunikacyjny - zbiór zasad, według których komputery wymieniają się danymi przez internet.

Jak to działa:

  1. Klient (np. przeglądarka, aplikacja Python) wysyła zapytanie (request)
  2. Serwer (np. strona, API) przetwarza zapytanie
  3. Serwer odsyła odpowiedź (response) z danymi lub informacją o błędzie
1[KLIENT]  ---(HTTP REQUEST)--->  [SERWER]
2   ↓                                  ↓
3   ↓                              Przetwarza
4   ↓                                  ↓
5   ↓  <---(HTTP RESPONSE)---  [SERWER]

Przykład Safari: Wysyłasz prośbę do centralnej bazy danych w Nairobi: "Podaj mi dane o lwach w Serengeti". Serwer odpowiada: "Oto 120 lwów w formie JSON"!

Metody HTTP - rodzaje zapytań

HTTP ma różne metody (czasem nazywane "czasownikami") - określają CO chcesz zrobić:

| Metoda | Przeznaczenie | Analogia Safari | |--------|---------------|-----------------| | GET | Pobierz dane | "Pokaż mi listę gatunków" 📖 | | POST | Utwórz nowy zasób | "Dodaj nową obserwację słonia" ➕ | | PUT | Zaktualizuj cały zasób | "Zastąp cały profil lwa nowymi danymi" 🔄 | | PATCH | Zaktualizuj część zasobu | "Zmień tylko populację goryla" ✏️ | | DELETE | Usuń zasób | "Usuń błędną obserwację" 🗑️ |

Najważniejsze: GET i POST - używane w 90% przypadków!

GET - pobieranie danych

1GET /api/species/lion HTTP/1.1
2Host: safari-api.com

Cechy:

  • Nie modyfikuje danych na serwerze
  • Parametry w URL (
    ?name=lion&habitat=savanna
    )
  • Można zapisać w zakładkach
  • Bezpieczna do wielokrotnego wywołania

POST - tworzenie/wysyłanie danych

1POST /api/observations HTTP/1.1
2Host: safari-api.com
3Content-Type: application/json
4
5{
6  "species": "Panthera leo",
7  "count": 12,
8  "location": "Serengeti"
9}

Cechy:

  • Wysyła dane w ciele zapytania (body), nie w URL
  • Może modyfikować dane na serwerze
  • Nie zapisuje się w historii przeglądarki
  • Może tworzyć nowe zasoby

Kody statusu HTTP - odpowiedzi serwera

Serwer zawsze odpowiada kodem statusu - liczbą mówiącą czy operacja się powiodła:

2xx - Sukces ✅

  • 200 OK - zapytanie udane, oto dane
  • 201 Created - zasób został utworzony
  • 204 No Content - sukces, ale brak danych do zwrócenia

3xx - Przekierowanie 🔀

  • 301 Moved Permanently - zasób przeniesiony na stałe
  • 302 Found - tymczasowe przekierowanie

4xx - Błąd klienta ❌

  • 400 Bad Request - błędne zapytanie (np. zły JSON)
  • 401 Unauthorized - wymagane uwierzytelnienie
  • 403 Forbidden - brak dostępu
  • 404 Not Found - zasób nie istnieje
  • 429 Too Many Requests - zbyt wiele zapytań

5xx - Błąd serwera 💥

  • 500 Internal Server Error - błąd serwera
  • 502 Bad Gateway - problem z serwerem pośredniczącym
  • 503 Service Unavailable - serwer niedostępny

Analogia Safari: Kod 200 = "Znalazłem lwa!", 404 = "Nie ma tu żadnego lwa", 500 = "Mój radiotelefon się zepsuł" 📻

Python requests - biblioteka HTTP

requests
to najpopularniejsza biblioteka Python do HTTP - prosta, elegancka, potężna!

Instalacja

1pip install requests

Podstawowe użycie - GET request

1import requests
2
3# Pobierz dane
4response = requests.get("https://api.github.com/users/octocat")
5
6# Status code
7print(response.status_code)  # 200
8
9# Dane jako JSON
10data = response.json()
11print(data["login"])  # "octocat"
12print(data["name"])   # "The Octocat"
13
14# Dane jako tekst
15print(response.text)  # Surowy JSON jako string
16
17# Nagłówki odpowiedzi
18print(response.headers["Content-Type"])  # "application/json"

Sprawdzanie sukcesu

1import requests
2
3response = requests.get("https://api.github.com/users/nonexistent")
4
5# Metoda 1: Sprawdź status code
6if response.status_code == 200:
7    print("Sukces!")
8elif response.status_code == 404:
9    print("Nie znaleziono")
10
11# Metoda 2: Użyj response.ok (True dla 2xx)
12if response.ok:
13    data = response.json()
14    print(data)
15else:
16    print(f"Błąd: {response.status_code}")
17
18# Metoda 3: Rzuć wyjątek przy błędzie
19try:
20    response.raise_for_status()  # Rzuca HTTPError dla 4xx/5xx
21    data = response.json()
22except requests.HTTPError as e:
23    print(f"HTTP Error: {e}")

Parametry URL - query parameters

GET requests często używają parametrów w URL:

1import requests
2
3# Ręcznie w URL
4response = requests.get("https://api.example.com/species?habitat=savanna&endangered=true")
5
6# Lepiej: słownik params (automatyczne kodowanie)
7params = {
8    "habitat": "savanna",
9    "endangered": "true",
10    "min_population": 100
11}
12
13response = requests.get("https://api.example.com/species", params=params)
14# URL: https://api.example.com/species?habitat=savanna&endangered=true&min_population=100
15
16print(response.url)  # Zobacz wygenerowany URL

Nagłówki (Headers)

Nagłówki to metadane zapytania - informacje o kliencie, oczekiwanym formacie, autoryzacji:

1import requests
2
3# Własne nagłówki
4headers = {
5    "User-Agent": "Safari-Data-Collector/1.0",
6    "Accept": "application/json",
7    "Authorization": "Bearer YOUR_API_KEY_HERE"
8}
9
10response = requests.get("https://api.example.com/species", headers=headers)
11
12# Sprawdź nagłówki odpowiedzi
13print(response.headers["Content-Type"])
14print(response.headers["Date"])

Popularne nagłówki:

  • User-Agent
    - identyfikacja klienta
  • Accept
    - oczekiwany format odpowiedzi
  • Content-Type
    - format wysyłanych danych
  • Authorization
    - token/klucz API

POST request - wysyłanie danych

JSON payload

1import requests
2
3# Dane do wysłania
4new_observation = {
5    "species": "Panthera leo",
6    "location": "Serengeti",
7    "count": 12,
8    "date": "2024-01-15",
9    "observer": "Darwin"
10}
11
12# POST z JSON
13response = requests.post(
14    "https://api.safari.com/observations",
15    json=new_observation  # Automatycznie: Content-Type: application/json
16)
17
18if response.status_code == 201:  # Created
19    created_data = response.json()
20    print(f"Utworzono obserwację ID: {created_data['id']}")
21else:
22    print(f"Błąd: {response.status_code}")

Form data (application/x-www-form-urlencoded)

1import requests
2
3# Dane formularza
4form_data = {
5    "species": "Loxodonta africana",
6    "count": "35"
7}
8
9response = requests.post(
10    "https://api.safari.com/quick-report",
11    data=form_data  # Content-Type: application/x-www-form-urlencoded
12)

PUT, PATCH, DELETE

1import requests
2
3# PUT - zastąp cały zasób
4updated_species = {
5    "scientific_name": "Panthera leo",
6    "population": 125,  # Zaktualizowana
7    "habitat": "sawanna"
8}
9
10response = requests.put(
11    "https://api.safari.com/species/lion",
12    json=updated_species
13)
14
15# PATCH - zmień tylko część
16partial_update = {
17    "population": 125  # Tylko populacja
18}
19
20response = requests.patch(
21    "https://api.safari.com/species/lion",
22    json=partial_update
23)
24
25# DELETE - usuń zasób
26response = requests.delete("https://api.safari.com/observations/12345")
27
28if response.status_code == 204:  # No Content
29    print("Usunięto pomyślnie")

Obsługa błędów

1import requests
2from requests.exceptions import RequestException, Timeout, ConnectionError
3
4def fetch_species_data(species_id: str):
5    """Pobierz dane gatunku z obsługą błędów"""
6    try:
7        response = requests.get(
8            f"https://api.safari.com/species/{species_id}",
9            timeout=5  # Timeout po 5 sekundach
10        )
11
12        # Sprawdź status
13        response.raise_for_status()
14
15        # Przetwórz dane
16        return response.json()
17
18    except Timeout:
19        print("⏱️ Timeout - serwer nie odpowiedział w czasie")
20        return None
21
22    except ConnectionError:
23        print("🔌 Błąd połączenia - sprawdź internet")
24        return None
25
26    except requests.HTTPError as e:
27        print(f"❌ HTTP Error {response.status_code}: {e}")
28        return None
29
30    except RequestException as e:
31        print(f"⚠️ Błąd zapytania: {e}")
32        return None
33
34# Użycie
35data = fetch_species_data("lion")
36if data:
37    print(f"Gatunek: {data['name']}")

Safari przykład - API klient do zarządzania obserwacjami

1import requests
2from typing import List, Dict, Optional
3from datetime import datetime
4
5class SafariAPIClient:
6    """Klient API do systemu obserwacji Safari"""
7
8    def __init__(self, base_url: str, api_key: str):
9        self.base_url = base_url.rstrip("/")
10        self.api_key = api_key
11        self.session = requests.Session()  # Reużywalne połączenie
12
13        # Domyślne nagłówki dla wszystkich zapytań
14        self.session.headers.update({
15            "User-Agent": "Safari-Data-Collector/2.0",
16            "Authorization": f"Bearer {self.api_key}",
17            "Accept": "application/json"
18        })
19
20    def get_species(self, species_id: str) -> Optional[Dict]:
21        """Pobierz dane gatunku"""
22        try:
23            response = self.session.get(
24                f"{self.base_url}/species/{species_id}",
25                timeout=10
26            )
27            response.raise_for_status()
28            return response.json()
29
30        except requests.RequestException as e:
31            print(f"❌ Błąd pobierania gatunku: {e}")
32            return None
33
34    def search_species(self, habitat: Optional[str] = None,
35                      endangered: Optional[bool] = None,
36                      min_population: Optional[int] = None) -> List[Dict]:
37        """Wyszukaj gatunki z filtrami"""
38        params = {}
39        if habitat:
40            params["habitat"] = habitat
41        if endangered is not None:
42            params["endangered"] = str(endangered).lower()
43        if min_population:
44            params["min_population"] = min_population
45
46        try:
47            response = self.session.get(
48                f"{self.base_url}/species",
49                params=params,
50                timeout=10
51            )
52            response.raise_for_status()
53            return response.json()
54
55        except requests.RequestException as e:
56            print(f"❌ Błąd wyszukiwania: {e}")
57            return []
58
59    def create_observation(self, species: str, location: str,
60                          count: int, notes: str = "") -> Optional[Dict]:
61        """Utwórz nową obserwację"""
62        observation_data = {
63            "species": species,
64            "location": location,
65            "count": count,
66            "date": datetime.now().isoformat(),
67            "notes": notes
68        }
69
70        try:
71            response = self.session.post(
72                f"{self.base_url}/observations",
73                json=observation_data,
74                timeout=10
75            )
76            response.raise_for_status()
77
78            if response.status_code == 201:
79                created = response.json()
80                print(f"✓ Utworzono obserwację ID: {created.get('id')}")
81                return created
82            else:
83                return response.json()
84
85        except requests.RequestException as e:
86            print(f"❌ Błąd tworzenia obserwacji: {e}")
87            return None
88
89    def update_species_population(self, species_id: str,
90                                 new_population: int) -> bool:
91        """Zaktualizuj populację gatunku (PATCH)"""
92        try:
93            response = self.session.patch(
94                f"{self.base_url}/species/{species_id}",
95                json={"population": new_population},
96                timeout=10
97            )
98            response.raise_for_status()
99            print(f"✓ Zaktualizowano populację {species_id}{new_population}")
100            return True
101
102        except requests.RequestException as e:
103            print(f"❌ Błąd aktualizacji: {e}")
104            return False
105
106    def delete_observation(self, observation_id: str) -> bool:
107        """Usuń obserwację"""
108        try:
109            response = self.session.delete(
110                f"{self.base_url}/observations/{observation_id}",
111                timeout=10
112            )
113            response.raise_for_status()
114
115            if response.status_code == 204:
116                print(f"✓ Usunięto obserwację {observation_id}")
117                return True
118
119            return False
120
121        except requests.RequestException as e:
122            print(f"❌ Błąd usuwania: {e}")
123            return False
124
125    def get_statistics(self) -> Optional[Dict]:
126        """Pobierz statystyki (z parametrami query)"""
127        params = {
128            "include_endangered": "true",
129            "group_by": "habitat"
130        }
131
132        try:
133            response = self.session.get(
134                f"{self.base_url}/statistics",
135                params=params,
136                timeout=15
137            )
138            response.raise_for_status()
139            return response.json()
140
141        except requests.RequestException as e:
142            print(f"❌ Błąd pobierania statystyk: {e}")
143            return None
144
145    def close(self):
146        """Zamknij sesję"""
147        self.session.close()
148
149
150# === DEMONSTRACJA ===
151
152print("=== SAFARI API CLIENT ===\n")
153
154# Inicjalizacja klienta
155client = SafariAPIClient(
156    base_url="https://api.safari-data.org/v1",
157    api_key="demo_key_12345"
158)
159
160# GET - pobierz gatunek
161print("1. Pobieranie danych lwa...")
162lion_data = client.get_species("lion")
163if lion_data:
164    print(f"   Gatunek: {lion_data.get('common_name')}")
165    print(f"   Populacja: {lion_data.get('population')}")
166
167# GET z parametrami - wyszukiwanie
168print("\n2. Wyszukiwanie zagrożonych gatunków w sawannie...")
169endangered = client.search_species(habitat="savanna", endangered=True)
170print(f"   Znaleziono {len(endangered)} gatunków")
171
172# POST - tworzenie obserwacji
173print("\n3. Tworzenie nowej obserwacji...")
174new_obs = client.create_observation(
175    species="Panthera leo",
176    location="Serengeti North",
177    count=8,
178    notes="Pride with 2 cubs"
179)
180
181# PATCH - aktualizacja
182print("\n4. Aktualizacja populacji...")
183client.update_species_population("lion", 125)
184
185# DELETE - usuwanie
186print("\n5. Usuwanie błędnej obserwacji...")
187client.delete_observation("obs_12345")
188
189# GET ze statystykami
190print("\n6. Pobieranie statystyk...")
191stats = client.get_statistics()
192if stats:
193    print(f"   Łączna liczba gatunków: {stats.get('total_species')}")
194
195# Zamknij sesję
196client.close()
197print("\n✓ Sesja zakończona")

Session - wydajność dla wielu zapytań

Jeśli robisz wiele zapytań do tego samego API, użyj

Session
- reużywa połączenie TCP:

1import requests
2
3# BEZ Session - każde zapytanie = nowe połączenie
4for i in range(100):
5    response = requests.get("https://api.example.com/data")
6
7# Z Session - jedno połączenie, szybsze!
8session = requests.Session()
9session.headers.update({"Authorization": "Bearer token123"})
10
11for i in range(100):
12    response = session.get("https://api.example.com/data")
13
14session.close()

Timeouty - nie czekaj w nieskończoność

Zawsze używaj timeout, aby zapytanie nie wisiało w nieskończoność:

1import requests
2
3# Timeout 5 sekund
4response = requests.get("https://slow-api.com/data", timeout=5)
5
6# Różne timeouty: (connect_timeout, read_timeout)
7response = requests.get("https://api.com/data", timeout=(3, 10))
8# 3s na połączenie, 10s na odczyt danych

Podsumowanie

W tej lekcji nauczyłeś/aś się:

  • ✅ Czym jest HTTP i jak działa (klient → serwer → odpowiedź)
  • ✅ Metody HTTP: GET, POST, PUT, PATCH, DELETE
  • ✅ Kody statusu: 200 OK, 404 Not Found, 500 Server Error
  • ✅ Biblioteka
    requests
    :
    requests.get()
    ,
    requests.post()
  • ✅ Parametry URL (
    params=
    ), nagłówki (
    headers=
    )
  • ✅ Wysyłanie JSON (
    json=
    ) i form data (
    data=
    )
  • ✅ Obsługa błędów:
    response.raise_for_status()
    , try/except
  • ✅ Session dla wydajności
  • ✅ Timeouty dla bezpieczeństwa

Checkpoint

Przed przejściem dalej:

  • [ ] Rozumiesz różnicę między GET a POST
  • [ ] Potrafisz wysłać zapytanie GET z parametrami
  • [ ] Potrafisz wysłać POST z JSON
  • [ ] Wiesz jak obsłużyć błędy HTTP
  • [ ] Rozumiesz kody statusu (2xx, 4xx, 5xx)

Analogia Safari: HTTP to system kurierski między stacjami badawczymi. GET = "wyślij mi dane", POST = "zapisz te nowe obserwacje", kody statusu = potwierdzenia dostawy! 📦✉️

W następnej lekcji Darwin pokaże Ci REST API - standardy architektury API, które pozwalają budować profesjonalne systemy wymiany danych! 🏗️🌐

Ir a CodeWorlds