Gets data from https://tibia.fandom.com and exposes this data using a RESTful JSON API.
Navigate to https://tibiawiki.dev to view the Swagger API of this project.
Requires JDK 25. Clone this git project to your local computer and compile it using: ./gradlew build from your favourite command line
terminal. Then execute: ./gradlew bootRun and open your browser on http://localhost:8080
You can now access the REST resources using your browser or any REST client such as Postman or curl from your command line. E.g. navigating to http://localhost:8080/api/corpses should give you a list of corpses.
Process health (no Fandom/wiki calls): GET /actuator/health,
/actuator/health/liveness, /actuator/health/readiness, and /actuator/info.
Cloud Run probe settings, SHA image tags, rollback, and knobs are documented in
docker/README.md.
The default Spring profile talks to TibiaWiki on Fandom. That hop is treated as unreliable:
wiki.api-urlandwiki.user-agentare configurable (no hardcoded client constants)- Each wiki call has a timeout (
wiki.call-timeout, default 20s) and is retried with full jitter - Category member lists and single-page wikitext are cached in-process (
wiki.cache.ttl, default 60s) ?expand=trueis served from that cache and rejected with HTTP 413 if the category is larger thanwiki.expand.max-pages(default 5000)- Wiki I/O uses a fixed thread pool (
wiki.io.threads, default 2) sized for Cloud Run 1Gi / ~1 vCPU; a full queue (wiki.io.queue-capacity, default 32) is rejected with HTTP 503 - Concurrent bulk expands are limited per instance (
wiki.expand.max-concurrent, default 2) so one replica cannot stampede Fandom or OOM - The jwiki
Wikiclient is created on first use, so a Fandom outage does not fail process start - Set
wiki.warm-on-startup=trueon Cloud Run min-instances to buildWikiat boot instead of on the first request
The fixtures profile does not construct this client and never calls Fandom.
A Bun-based black-box harness in regression/ snapshots HTTP JSON
and compares later responses to those goldens. It is not part of the Gradle test task.
GitHub Actions (.github/workflows/api-regression.yml) boots the API with
--spring.profiles.active=fixtures — an in-process wiki repository that reads
regression/fixtures/ — then runs bun run smoke:docs and bun run test
against http://localhost:8080. That job never calls Fandom or tibiawiki.dev.
./regression/scripts/boot-fixtures.sh # repo root, other terminal
cd regression && bun run smoke:docs && bun run testUse bun run capture against the fixture-backed server to refresh goldens.
See regression/README.md.
Gradle, ITs, and fixture smoke:docs do not run the production container
entrypoint. GitHub Actions (.github/workflows/docker-boot.yml) and the
Cloud Build PR/prod paths build docker/Dockerfile (same context as deploy)
then ./scripts/docker-boot-smoke.sh: docker inspect must show exec-form
java with no $/$$/sh -c, and GET /actuator/health/readiness must
be 200/UP for PORT=8080 and PORT=19080.
Cloud Run PORT is bound in Spring (server.port=${PORT:8080}), not by a
shell ENTRYPOINT. See docker/README.md and
AGENTS.md.
docker build -t tibiawikiapi -f ./docker/Dockerfile .
./scripts/docker-boot-smoke.sh tibiawikiapi
# or: BUILD=1 ./scripts/docker-boot-smoke.shPublic Cloud Run leaves WIKI_WRITE_ENABLED unset (false). Unauthenticated
clients cannot mutate TibiaWiki through tibiawiki.dev. ModifyAny stays in
the codebase for a future bot.
To enable PUT locally or for a bot:
export WIKI_WRITE_ENABLED=true
export WIKI_WRITE_TOKEN=optional-shared-secret # optional; if set, required on PUTWhen a token is configured, send Authorization: Bearer <token> or
X-WIKI-Write-Token. Missing or wrong tokens return HTTP 401. When writes
are disabled, PUT returns HTTP 403.
CORS allows GET (plus HEAD/OPTIONS) from https://tibiawiki.dev and local
bootRun origins. Credentials are not enabled. Override origins with
WIKI_CORS_ALLOWED_ORIGINS (* for any GET origin).
Public GET/HEAD /api/** can be soft-throttled with an in-process token bucket
keyed by client IP (IPv4 full address, IPv6 /64). Defaults: burst 20, refill
0.5/s (~30/min). Rejected calls return HTTP 429 with Retry-After,
X-RateLimit-* headers, and JSON {"error":"rate_limited",...}.
Off by default in the app; enabled on Cloud Run by
scripts/cloud-run-release.sh (RATE_LIMIT_ENABLED=true, overridable). Manual
toggle on the live service:
gcloud run services update tibiawikiapi \
--region europe-west1 --project tibiawikiapi-246008 \
--update-env-vars=RATE_LIMIT_ENABLED=trueTune with RATE_LIMIT_CAPACITY, RATE_LIMIT_REFILL_PER_SECOND,
RATE_LIMIT_EXPAND_CAPACITY, and RATE_LIMIT_EXPAND_REFILL_PER_SECOND.
Rollback: set RATE_LIMIT_ENABLED=false. Actuator, springdoc, and Swagger UI
are not limited. Counters are per instance (see docker/README.md).
The client IP is the rightmost X-Forwarded-For entry, which Cloud Run's front
end appends. Entries a client sends itself (and a client Forwarded header) are
ignored, so they cannot select a fresh bucket. Behind more trusted proxies, set
RATE_LIMIT_FORWARDED_FOR_TRUSTED_HOPS (default 1; 0 uses the socket address).
Requests with no client address (Cloud Run reports 0.0.0.0 for Google-internal
traffic) share one bucket scaled by RATE_LIMIT_UNATTRIBUTED_MULTIPLIER (default 5).
Deploys cap Cloud Run at MAX_INSTANCES (default 3), which bounds the per-instance
multiplier.
For all resources the query parameter ?expand=true can be appended to get a full list of JSON objects
at the collection resource level. For example, instead of https://tibiawiki.dev/api/achievements the url
https://tibiawiki.dev/api/achievements?expand=true can be used. Categories larger than
wiki.expand.max-pages return HTTP 413 instead of bulk-fetching Fandom.
The following resources are available:
| Entity | List | Example |
|---|---|---|
| Achievement | achievements | Goo Goo Dancer |
| Books | books | Dungeon Survival Guide (Book) |
| Buildings | buildings | Theater Avenue 8b |
| Charms | charms | Adrenaline Burst |
| CipSoft Members | cipsoftmembers | Knightmare |
| Corpses | corpses | Dead Rat |
| Creatures | creatures | Dragon |
| Effects | effects | Blue Electricity Effect |
| Familiars | familiars | Grovebeast |
| Fansites | fansites | TibiaWiki |
| Hunting Places | hunting places | Hero Cave |
| Imbuements | imbuements | Powerful Strike |
| Items1 | items | Carlin Sword |
| Keys | keys | Key 4055 |
| Locations | locations | Thais |
| Loot Statistics | loot | Ferumbras |
| Missiles | missiles | Throwing Cake Missile |
| Mounts | mounts | Donkey |
| NPCs | npcs | Sam |
| Objects1 | objects | Blueberry Bush |
| Outfits | outfits | Pirate Outfits |
| Quests | quests | The Paradox Tower Quest |
| Spells | spells | Light Healing |
| Streets | streets | Sugar Street |
| Updates | updates | Summer Update 2020 |
| Worlds | worlds | Antica |
1 as of 2021 the categories Items and Objects were merged on the wiki. To be backwards compatible with systems relying on an accurate list of Items, this API now returns a list of 'Pickupable Items' from the Items endpoint, but which have the Object templateType.
Hunting Places follow Infobox Hunt: recommended level, skill, and defence are knight, paladin, and mage only.
TibiaWiki has not added Monk columns yet, so this API does not invent them. Spell voc values that include Monks
are parsed into typed vocations (the original voc wiki string is unchanged).