Когда мы проектируем систему, взаимодействующую с несколькими API, важно учитывать:
- Безопасность:
- Использование OAuth2 для аутентификации и обновления токенов.
- Ограничение прав доступа с помощью ролей и сервисных аккаунтов.
- Структура проекта:
- Разделение на модули для работы с разными API.
- Конфигурация для хранения ключей API, токенов и конфиденциальных данных.
- Асинхронность:
- Использование
httpxдля выполнения асинхронных запросов. - Оптимизация обработки данных для повышения производительности.
- Использование
Вот как будет выглядеть наша система:
- Google Sheets: хранение и обновление данных таблиц.
- Google Drive: загрузка и управление файлами.
- Google Maps: получение геоданных о пользователях и местоположении объектов.
Разделим логику на три модуля:
sheets_service.py: для работы с Google Sheets API.drive_service.py: для взаимодействия с Google Drive API.maps_service.py: для работы с Google Maps API.
Настройка проекта
Для начала убедитесь, что у вас установлены необходимые библиотеки. Это можно сделать с помощью pip:
pip install fastapi uvicorn google-api-python-client google-auth httpx
Конфигурация проекта
Создадим файл .env, где будем хранить конфиденциальные данные:
GOOGLE_API_CLIENT_ID=<ваш client_id>
GOOGLE_API_CLIENT_SECRET=<ваш client_secret>
GOOGLE_SHEETS_ID=<ID вашей таблицы>
GOOGLE_DRIVE_FOLDER_ID=<ID папки на Google Диске>
GOOGLE_MAPS_API_KEY=<ваш API-ключ для Google Maps>
Добавим обработку .env в код с помощью python-dotenv:
pip install python-dotenv
Теперь создадим файл config.py:
from dotenv import load_dotenv
import os
load_dotenv()
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_API_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_API_CLIENT_SECRET")
GOOGLE_SHEETS_ID = os.getenv("GOOGLE_SHEETS_ID")
GOOGLE_DRIVE_FOLDER_ID = os.getenv("GOOGLE_DRIVE_FOLDER_ID")
GOOGLE_MAPS_API_KEY = os.getenv("GOOGLE_MAPS_API_KEY")
Реализация модулей
Создайте файл sheets_service.py:
from googleapiclient.discovery import build
from google.oauth2.service_account import Credentials
from config import GOOGLE_SHEETS_ID
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
credentials = Credentials.from_service_account_file("service_account.json", scopes=SCOPES)
service = build('sheets', 'v4', credentials=credentials)
def read_data(range_name):
sheet = service.spreadsheets()
result = sheet.values().get(spreadsheetId=GOOGLE_SHEETS_ID, range=range_name).execute()
return result.get('values', [])
def write_data(range_name, values):
sheet = service.spreadsheets()
body = {
'values': values
}
result = sheet.values().update(spreadsheetId=GOOGLE_SHEETS_ID, range=range_name,
valueInputOption="RAW", body=body).execute()
return result
Работа с Google Drive API
Создайте файл drive_service.py:
from googleapiclient.http import MediaFileUpload
from googleapiclient.discovery import build
from google.oauth2.service_account import Credentials
from config import GOOGLE_DRIVE_FOLDER_ID
SCOPES = ['https://www.googleapis.com/auth/drive']
credentials = Credentials.from_service_account_file("service_account.json", scopes=SCOPES)
service = build('drive', 'v3', credentials=credentials)
def upload_file(file_name, mime_type):
file_metadata = {
'name': file_name,
'parents': [GOOGLE_DRIVE_FOLDER_ID]
}
media = MediaFileUpload(file_name, mimetype=mime_type)
file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
return file.get('id')
Работа с Google Maps API
Создайте файл maps_service.py:
import httpx
from config import GOOGLE_MAPS_API_KEY
async def get_coordinates(address):
url = f"https://maps.googleapis.com/maps/api/geocode/json"
params = {"address": address, "key": GOOGLE_MAPS_API_KEY}
async with httpx.AsyncClient() as client:
response = await client.get(url, params=params)
response.raise_for_status()
data = response.json()
return data['results'][0]['geometry']['location']
Интеграция в FastAPI
Теперь создадим файл main.py:
from fastapi import FastAPI, HTTPException
from sheets_service import read_data, write_data
from drive_service import upload_file
from maps_service import get_coordinates
app = FastAPI()
@app.get("/sheets/{range_name}")
async def get_sheet_data(range_name: str):
try:
data = read_data(range_name)
return {"data": data}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/sheets/{range_name}")
async def add_sheet_data(range_name: str, values: list):
try:
result = write_data(range_name, values)
return {"updated_cells": result.get("updatedCells")}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/drive/upload")
async def upload(file_name: str, mime_type: str):
try:
file_id = upload_file(file_name, mime_type)
return {"file_id": file_id}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/maps/")
async def get_location(address: str):
try:
coords = await get_coordinates(address)
return {"coordinates": coords}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
Тестирование приложения
Теперь вы можете запустить приложение, используя Uvicorn:
uvicorn main:app --reload
Примеры запросов:
- Получение данных из таблицы Google Sheets:
GET /sheets/Sheet1!A1:D10 - Загрузка файла на Google Drive:
POST /drive/upload?file_name=example.pdf&mime_type=application/pdf - Получение координат по адресу:
GET /maps/?address=New+York
Этот проект — отличный способ показать свои навыки на собеседовании или действительно использовать интеграцию с Google API в реальных приложениях. От автоматизации документации до управления картами и геоданными — возможности безграничны! Не забудьте учитывать лимиты запросов, обрабатывать ошибки и следить за обновлением токенов для использования OAuth2.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ