Skip to content

TeKrop/overgraphql-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

41 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ•ΈοΈ OverGraphQL API

Python Build Status Coverage Issues License: MIT

OverGraphQL API exposes Overwatch 2 heroes, roles, gamemodes, maps and player statistics through a single GraphQL endpoint. It's a pure facade over OverFast API: it never talks to Blizzard directly and doesn't parse anything itself β€” it reshapes OverFast REST data into one relational graph, so you can fetch exactly the data you need in a single query. Built with Strawberry GraphQL and httpx.

Table of contents

πŸ”Ž How it works

flowchart LR
    Client["GraphQL client"] -->|"POST /graphql"| OverGraphQL["OverGraphQL API"]
    OverGraphQL -->|REST| OverFast["OverFast API"]
    OverFast -->|scraping| Blizzard["Blizzard pages"]
Loading

Two kinds of data, two strategies:

  • Semi-static data (heroes, roles, gamemodes, maps) is cached in-process for 24 hours. Concurrent fetches of the same resource are coalesced, and upstream calls are paced below OverFast's rate limit, so even a cold-cache heroes query (one detail call per hero) stays friendly to the upstream.
  • Player data is always fetched from OverFast, which owns freshness through its own Stale-While-Revalidate cache. One player at a time, no batching.
flowchart TD
    R["Field resolver"] --> C{"In cache?"}
    C -->|hit| OK["Return"]
    C -->|miss| L["Coalescing lock<br/>(one fetch per key)"]
    L --> P["Paced GET<br/>(&lt; OverFast rate limit,<br/>retry once on 429)"]
    P --> D["Parse to domain model"]
    D --> S["Cache (24h TTL)"] --> OK
    R2["Player field resolver"] --> P2["Paced GET"] --> D2["Parse to domain model"] --> OK2["Return<br/>(freshness owned by OverFast SWR)"]
Loading

The schema is fully documented: every type, field and argument carries a description, browsable in the GraphiQL explorer served at /graphql (the GraphQL equivalent of OverFast's Redoc/Swagger).

🐍 Architecture

Hexagonal-lite, dependencies flow inward only:

flowchart LR
    subgraph GraphQL layer
        Q["Query / types<br/>(strawberry)"]
    end
    subgraph Domain
        M["Models<br/>(plain dataclasses)"]
        PT["OverFastPort<br/>(Protocol)"]
    end
    subgraph Adapters
        A["OverFastClient<br/>(httpx + TTL cache)"]
    end
    Q --> PT
    Q --> M
    A -. implements .-> PT
    A --> M
Loading
  • Domain β€” plain frozen dataclasses and a single typing.Protocol port; no framework imports. Most domain models are registered directly as strawberry types (zero mapping code).
  • Adapters β€” OverFastClient implements the port: HTTP, caching, coalescing, pacing, parsing.
  • GraphQL layer β€” resolvers only see the port, injected through the request context; tests swap in an in-memory fake.

Hero, map and gamemode keys are plain strings on purpose: new Blizzard content flows through without a schema update. Only closed sets (roles, platforms, player gamemodes) are enums.

πŸš€ Example queries

The single endpoint is POST /graphql. Opening it in a browser serves GraphiQL, with autocompletion and the full schema documentation.

Static data is one relational graph β€” here heroes with their role, and maps with their gamemodes, in one query:

query StaticData {
  heroes(key: "ana") {
    name
    description
    role {
      name
      description
    }
    abilities {
      name
      description
    }
  }
  maps {
    name
    location
    gamemodes {
      name
    }
  }
}

Every list query (roles, gamemodes, maps, heroes) accepts an optional key filter; an unknown key returns an empty list.

Player profile and statistics β€” select only what you need, each stats field triggers its own upstream fetch:

query PlayerProfileAndStats {
  player(playerId: "TeKrop-2217") {
    avatar
    namecard
    title
    username
    lastUpdatedAt
    statsSummary {
      general {
        kda
        timePlayed
        winrate
        gamesPlayed
        total {
          healing
          damage
          assists
        }
      }
    }
  }
}

Career statistics with labels, per platform and gamemode:

query CareerStats {
  player(playerId: "TeKrop-2217") {
    careerStats(platform: PC, gamemode: COMPETITIVE) {
      hero
      categories {
        label
        stats {
          label
          value
        }
      }
    }
  }
}

An unknown player returns player: null.

πŸ‹ Run for production

Ensure you have docker and docker compose installed, then:

docker compose up -d --build

The API listens on http://localhost:8080/graphql. No mandatory configuration: by default it targets the live OverFast API instance. Create a .env file to override any setting.

πŸ’½ Run as developer

Requirements: docker, docker compose and just.

just build    # build Docker images (required first)
just start    # run the app with autoreload on localhost:8000
just test     # run tests with coverage
just lint     # ruff linter
just format   # ruff formatter
just check    # ty type checker
just lock     # update uv.lock

βš™οΈ Settings

All settings are environment variables (or a .env file), loaded by pydantic-settings:

Variable Default Description
OVERFAST_API_URL https://overfast-api.tekrop.fr Base URL of the OverFast API instance used as upstream
STATIC_DATA_TTL 86400 TTL (seconds) of the in-process cache for semi-static data
UPSTREAM_REQUESTS_PER_SECOND 20 Pacing of upstream requests, must stay below OverFast's per-IP rate limit
MAX_QUERY_DEPTH 10 Maximum allowed GraphQL query depth
MAX_QUERY_ALIASES 15 Maximum aliases per query
MAX_QUERY_TOKENS 1000 Maximum tokens per query document
LOG_LEVEL INFO Minimum level of application logs

πŸ›‘οΈ Guardrails

Queries are validated before execution: depth, alias count and document size are limited (see settings above). GraphiQL and introspection are enabled on purpose β€” this is a public API, they are the documentation.

πŸ™ Credits

All data comes from OverFast API, which itself scrapes Blizzard's official Overwatch pages. Overwatch is a trademark of Blizzard Entertainment, Inc. This project is not affiliated with Blizzard Entertainment.

πŸ“ License

Copyright Β© 2026 Valentin PORCHET.

This project is MIT licensed.

About

πŸ•ΈοΈ OverGraphQL API exposes Overwatch 2 heroes, roles, gamemodes, maps and player statistics through a single GraphQL endpoint.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Contributors