Architecture¶
This page describes the internal design of gopro-api — how the layers fit together, how data flows from an HTTP request to a typed Python object, and where to look when you want to extend the library.
High-level overview¶
flowchart TD
U(["User / Script / CLI"])
U --> GC["GoProClient\n(sync wrapper)"]
U --> AGC["AsyncGoProClient\n(async wrapper)"]
GC -->|delegates to| GA["GoProAPI\n(requests-based)"]
AGC -->|delegates to| AGA["AsyncGoProAPI\n(aiohttp-based)"]
GA -->|HTTP| API(["api.gopro.com"])
AGA -->|HTTP| API
Package layout¶
| Path | Role |
|---|---|
gopro_api/api/gopro.py |
GoProAPI — synchronous HTTP client (requests) |
gopro_api/api/async_gopro.py |
AsyncGoProAPI — asynchronous HTTP client (aiohttp) |
gopro_api/api/models.py |
Pydantic request/response models |
gopro_api/api/__init__.py |
Re-exports GoProAPI, AsyncGoProAPI |
gopro_api/client.py |
GoProClient / AsyncGoProClient — high-level wrappers |
gopro_api/config.py |
pydantic-settings Settings (GP_ACCESS_TOKEN) |
gopro_api/exceptions.py |
Custom exception hierarchy |
gopro_api/utils.py |
Shared helpers (resolution scoring, etc.) |
gopro_api/cli/ |
Typer application — search, info, pull, auth commands |
Layers¶
1. HTTP clients (gopro_api.api)¶
GoProAPI and AsyncGoProAPI are thin wrappers around HTTP calls. They:
- Inject the
gp_access_tokencookie on every request. - Validate and deserialise responses into Pydantic models.
- Raise typed exceptions (
gopro_api.exceptions) on non-2xx responses.
Both are context-managers that handle session lifecycle:
with GoProAPI() as api: # opens a requests.Session
result = api.search(...)
async with AsyncGoProAPI() as api: # opens an aiohttp.ClientSession
result = await api.search(...)
2. High-level clients (gopro_api.client)¶
GoProClient and AsyncGoProClient add convenience on top of the raw API:
- Pagination —
--all-pagesiteration oversearchresults. - Asset selection — picking the best video variation by resolution.
- File download — streaming CDN downloads to disk.
3. Pydantic models (gopro_api.api.models)¶
All request parameters and API responses are typed with Pydantic v2 models:
- Requests —
GoProMediaSearchParams,CapturedRange. - Responses —
GoProMediaSearchResponse,GoProMediaDownloadResponse,GoProAuthStatus, and their_embedded/_pageschildren (with field aliases for the GoPro API's underscore-prefixed keys).
List fields in request models are serialised to comma-separated strings automatically when calling model_dump().
4. Configuration (gopro_api.config)¶
A single Settings class (pydantic-settings) reads GP_ACCESS_TOKEN from:
- Environment variables.
- A
.envfile in the current working directory.
Clients accept an explicit access_token parameter that overrides Settings.
get_token_info() reports whether a token is configured and whether it came from the environment or a .env file.
5. CLI (gopro_api.cli)¶
The CLI is built with Typer and Rich:
gopro_api/cli/app.py— Typer application and shared options.gopro_api/cli/search.py—searchcommand +SearchPrinter.gopro_api/cli/info.py—infocommand +InfoPrinter.gopro_api/cli/pull.py—pullcommand +PullPrinter.gopro_api/cli/auth.py—authcommand +AuthPrinter.gopro_api/cli/_common.py— shared helpers.
Each command delegates to GoProClient/AsyncGoProClient and passes the result to a dedicated *Printer class for Rich-formatted output.
Data flow — gopro-api search¶
sequenceDiagram
actor User
participant CLI
participant GoProClient
participant GoProAPI
participant GoproCom as api.gopro.com
User->>CLI: gopro-api search --start … --end …
CLI->>GoProClient: search() / search_all()
GoProClient->>GoProAPI: search(GoProMediaSearchParams)
GoProAPI->>GoproCom: GET /media/search?captured_after=…&per_page=…
GoproCom-->>GoProAPI: JSON response
GoProAPI-->>GoProClient: GoProMediaSearchResponse (Pydantic)
GoProClient-->>CLI: response
CLI->>User: Rich table or raw JSON (stdout)
Data flow — gopro-api auth¶
sequenceDiagram
actor User
participant CLI
participant AsyncGoProClient
participant AsyncGoProAPI
participant GoproCom as api.gopro.com
User->>CLI: gopro-api auth
CLI->>AsyncGoProClient: check_auth()
AsyncGoProClient->>AsyncGoProAPI: check_auth()
AsyncGoProAPI->>GoproCom: GET /media/search?per_page=1
GoproCom-->>AsyncGoProAPI: HTTP 200 or 401
AsyncGoProAPI-->>AsyncGoProClient: GoProAuthStatus
AsyncGoProClient-->>CLI: GoProAuthStatus
CLI->>User: Rich panel or JSON (stdout)
Error handling¶
classDiagram
Exception <|-- GoProAPIError
GoProAPIError <|-- GoProAuthError
GoProAPIError <|-- GoProNotFoundError
class GoProAPIError {
Base class for all library errors
}
class GoProAuthError {
HTTP 401 — token expired or missing
}
class GoProNotFoundError {
HTTP 404 — media ID does not exist
}
| Exception | Raised when |
|---|---|
GoProAPIError |
Base class for all library errors. |
GoProAuthError |
The API returns 401 Unauthorized (token expired or missing). |
GoProNotFoundError |
The API returns 404 (media ID does not exist). |
See gopro_api/exceptions.py and API Reference → Exceptions for the full hierarchy.
Extending the library¶
New API endpoint — add a method to GoProAPI / AsyncGoProAPI (and the corresponding Pydantic models), then expose it in GoProClient / AsyncGoProClient.
New CLI command — create a new file under gopro_api/cli/, define a Typer command, register it in app.py, and add a *Printer class for output formatting.