JavaRush /Курси /Модуль 4: FastAPI /Повна реалізація API з інтеграцією зовнішнього сервісу

Повна реалізація API з інтеграцією зовнішнього сервісу

Модуль 4: FastAPI
Рівень 16 , Лекція 9
Відкрита

У цій лекції ми зберемо всі раніше вивчені концепції і реалізуємо повноцінний API на FastAPI з інтеграцією зовнішнього сервісу. Ми організуємо проєкт, створимо ендпоінти, підключимось до зовнішнього API, обробимо отримані дані та додамо валідацію, а також напишемо прості тести. Щоб зробити проєкт цікавішим, будемо працювати з OpenWeatherMap API для надання даних про погоду.

Реалізуємо невеликий API-додаток, який дозволяє клієнтам:

  1. Запитувати поточну інформацію про погоду по місту.
  2. Валідація даних (наприклад, переконаємось, що місто дійсно вказане).
  3. Обробляти помилки у випадку проблем із зовнішнім API (наприклад, неправильний API-ключ або мережеві помилки).

Такі навички знадобляться при створенні реальних проєктів, де потрібно взаємодіяти з іншими сервісами: інтеграція з платіжними системами, соцмережами, аналітичними інструментами тощо. Ця вміння також часто перевіряється на співбесідах.


Створення структури проєкту

Спочатку організуємо каталог проєкту. Найбільш базова структура виглядатиме так:


weather_app/
├── app/
│   ├── main.py
│   ├── api/
│   │   ├── __init__.py
│   │   ├── weather.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── schemas.py
│   ├── services/
│       ├── __init__.py
│       ├── weather_service.py
│   ├── settings.py
├── requirements.txt
  • app/main.py — основний файл для запуску додатка.
  • app/api/weather.py — тут описуватимемо маршрути.
  • app/models/schemas.py — зберігаємо Pydantic-схеми.
  • app/services/weather_service.py — реалізуємо логіку інтеграції з зовнішнім API.
  • app/settings.py — налаштування проєкту, наприклад API-ключі.

Встановлення залежностей

Почнемо з встановлення бібліотек. Нам знадобляться FastAPI, httpx і Pydantic:

pip install fastapi uvicorn httpx

Оновіть requirements.txt:

fastapi
httpx
uvicorn

Налаштування основного файлу додатка

Створимо мінімальний файл main.py:


from fastapi import FastAPI
from app.api.weather import router as weather_router

app = FastAPI(
    title="Weather API",
    description="A simple API to fetch weather information from OpenWeatherMap",
    version="1.0.0"
)

app.include_router(weather_router, prefix="/weather")

Тут ми створюємо екземпляр FastAPI і підключаємо маршрути з модуля weather.


Реалізація ендпоінта для отримання погоди

Додамо файл app/api/weather.py:


from fastapi import APIRouter, HTTPException, Query
from app.models.schemas import WeatherResponse
from app.services.weather_service import get_weather_data

router = APIRouter()

@router.get("/", response_model=WeatherResponse)
async def get_weather(city: str = Query(..., description="City name to fetch weather data")):
    """
    Fetch weather data for a given city.
    """
    weather_data = await get_weather_data(city)
    if not weather_data:
        raise HTTPException(status_code=404, detail="Weather data not found")
    return weather_data
  1. Маршрут: Створюємо маршрут GET /weather/, який приймає параметр city.
  2. Опис: Використовуємо Query для опису параметра міста.
  3. Відповідь: Повертаємо JSON у вигляді, описаному в схемі WeatherResponse.

Опис Pydantic-схеми

Тепер створимо файл app/models/schemas.py, де опишемо схему відповіді:


from pydantic import BaseModel

class WeatherResponse(BaseModel):
    city: str
    temperature: float
    description: str

Цей клас задає структуру повернених даних: місто, температура і опис погоди.


Написання сервісу для роботи з зовнішнім API

Додамо файл app/services/weather_service.py:


import httpx
from app.settings import OPENWEATHERMAP_API_KEY

BASE_URL = "http://api.openweathermap.org/data/2.5/weather"

async def get_weather_data(city: str):
    """
    Fetch weather data from OpenWeatherMap API.
    """
    params = {
        "q": city,
        "appid": OPENWEATHERMAP_API_KEY,
        "units": "metric"  # Get temperature in Celsius
    }

    async with httpx.AsyncClient() as client:
        response = await client.get(BASE_URL, params=params)
        if response.status_code != 200:
            return None
        data = response.json()
        return {
            "city": data["name"],
            "temperature": data["main"]["temp"],
            "description": data["weather"][0]["description"]
        }
  1. Функція відправляє асинхронний GET-запит до OpenWeatherMap API.
  2. Парсить відповідь і витягує потрібні дані: назву міста, температуру і опис.

Налаштування API-ключа

Створимо файл app/settings.py:


import os

OPENWEATHERMAP_API_KEY = os.getenv("OPENWEATHERMAP_API_KEY", "your_api_key_here")

Не забудьте замінити your_api_key_here на ваш реальний API-ключ. Або встановіть змінну оточення OPENWEATHERMAP_API_KEY.


Обробка помилок

Якщо в сервісу OpenWeatherMap виникне помилка (наприклад, неправильний API-ключ або неіснуюче місто), ми повертаємо None. У маршруті це перетворюється на HTTP-помилку 404 через HTTPException.

Можна покращити обробку помилок:


        if response.status_code == 404:
            return {"error": "City not found"}
        elif response.status_code == 401:
            return {"error": "Invalid API key"}
        response.raise_for_status()

Тестування ендпоінта

Простий клієнт для перевірки:
створіть файл test_weather.py:


import pytest
from fastapi.testclient import TestClient
from app.main import app

client = TestClient(app)

@pytest.mark.parametrize("city", ["London", "Paris", "Tokyo"])
def test_get_weather(city):
    response = client.get(f"/weather/?city={city}")
    assert response.status_code == 200
    assert "temperature" in response.json()
  1. Тести перевіряють кілька міст.
  2. Переконайтесь, що відповідь містить поле temperature.

Запуск додатка

Запустіть сервер за допомогою команди:

uvicorn app.main:app --reload

Перейдіть за адресою http://127.0.0.1:8000/docs, щоб протестувати ендпоінт через Swagger UI.

3
Опитування
Обробка помилок при роботі з зовнішніми сервісами, рівень 16, лекція 9
Недоступний
Обробка помилок при роботі з зовнішніми сервісами
Обробка помилок при роботі з зовнішніми сервісами
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ