From 477028a025b2803c443ef0a4629170beb4deb58d Mon Sep 17 00:00:00 2001 From: Jacob Lewis Date: Wed, 16 Jul 2025 10:11:07 -0500 Subject: [PATCH] Dics: Add Webhost API Documententation (#4887) * capitialization changes * ditto * Revert "ditto" This reverts commit 17cf596735888e91850954c7306ce0b80d7e453d. * Revert "capitialization changes" This reverts commit 6fb86c6568da2c08b5f8e691d4fc810e3ab09a44. * full revert and full commit * Update docs/webhost api.md Co-authored-by: qwint * Update docs/webhost api.md Co-authored-by: Aaron Wagener * Update docs/webhost api.md Co-authored-by: Aaron Wagener * Update webhost api.md * Removed in-devolopment API * Apply standard capitilization and grammar flow Co-authored-by: Scipio Wright * declarative language * Apply suggestions from code review Co-authored-by: qwint * datapackage_checksum clarification, and /datapackage clairfication * /dp/checksum clarification * Detailed responces and /generation breakdown * Update webhost api.md * Made output anonomous * Update docs/webhost api.md Co-authored-by: qwint * Swapped IDs to UUID, and added language around UUID vs SUUID * Apply suggestions from code review formatting and grammar Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Condensed paragraphs and waterfalled headders --------- Co-authored-by: qwint Co-authored-by: Aaron Wagener Co-authored-by: Scipio Wright Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --- docs/webhost api.md | 351 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 docs/webhost api.md diff --git a/docs/webhost api.md b/docs/webhost api.md new file mode 100644 index 00000000..dba57e55 --- /dev/null +++ b/docs/webhost api.md @@ -0,0 +1,351 @@ +# API Guide + +Archipelago has a rudimentary API that can be queried by endpoints. The API is a work-in-progress and should be improved over time. + +The following API requests are formatted as: `https:///api/` + +The returned data will be formated in a combination of JSON lists or dicts, with their keys or values being notated in `blocks` (if applicable) + +Current endpoints: +- Datapackage API + - [`/datapackage`](#datapackage) + - [`/datapackage/`](#datapackagestringchecksum) + - [`/datapackage_checksum`](#datapackagechecksum) +- Generation API + - [`/generate`](#generate) + - [`/status/`](#status) +- Room API + - [`/room_status/`](#roomstatus) +- User API + - [`/get_rooms`](#getrooms) + - [`/get_seeds`](#getseeds) + + +## UUID vs SUUID +Currently, the server reports back the item's `UUID` (Universally Unique Identifier). The item's `UUID` needs to be converted to a `base64 UUID` (nicknamed a `ShortUUID` and refered to as `SUUID` in the remainder of this document) that are URL safe in order to be queried via API endpoints. +- [PR 4944](https://github.com/ArchipelagoMW/Archipelago/pull/4944) is in progress to convert API returns into SUUIDs + +## Datapackage Endpoints +These endpoints are used by applications to acquire a room's datapackage, and validate that they have the correct datapackage for use. Datapackages normally include, item IDs, location IDs, and name groupings, for a given room, and are essential for mapping IDs received from Archipelago to their correct items or locations. + +### `/datapackage` + +Fetches the current datapackage from the WebHost. +You'll receive a dict named `games` that contains a named dict of every game and its data currently supported by Archipelago. +Each game will have: +- A checksum `checksum` +- A dict of item groups `item_name_groups` +- Item name to AP ID dict `item_name_to_id` +- A dict of location groups `location_name_groups` +- Location name to AP ID dict `location_name_to_id` + +Example: +``` +{ + "games": { + ... + "Clique": { + "checksum": "0271f7a80b44ba72187f92815c2bc8669cb464c7", + "item_name_groups": { + "Everything": [ + "A Cool Filler Item (No Satisfaction Guaranteed)", + "Button Activation", + "Feeling of Satisfaction" + ] + }, + "item_name_to_id": { + "A Cool Filler Item (No Satisfaction Guaranteed)": 69696967, + "Button Activation": 69696968, + "Feeling of Satisfaction": 69696969 + }, + "location_name_groups": { + "Everywhere": [ + "The Big Red Button", + "The Item on the Desk" + ] + }, + "location_name_to_id": { + "The Big Red Button": 69696969, + "The Item on the Desk": 69696968 + } + }, + ... + } +} +``` + +### `/datapackage/` + +Fetches a single datapackage by checksum. +Returns a dict of the game's data with: +- A checksum `checksum` +- A dict of item groups `item_name_groups` +- Item name to AP ID dict `item_name_to_id` +- A dict of location groups `location_name_groups` +- Location name to AP ID dict `location_name_to_id` + +Its format will be identical to the whole-datapackage endpoint (`/datapackage`), except you'll only be returned the single game's data in a dict. + +### `/datapackage_checksum` + +Fetches the checksums of the current static datapackages on the WebHost. +You'll receive a dict with `game:checksum` key-value pairs for all the current officially supported games. +Example: +``` +{ +... +"Donkey Kong Country 3":"f90acedcd958213f483a6a4c238e2a3faf92165e", +"Factorio":"a699194a9589db3ebc0d821915864b422c782f44", +... +} +``` + + +## Generation Endpoint +These endpoints are used internally for the WebHost to generate games and validate their generation. They are also used by external applications to generate games automatically. + +### `/generate` + +Submits a game to the WebHost for generation. +**This endpoint only accepts a POST HTTP request.** + +There are two ways to submit data for generation: With a file and with JSON. + +#### With a file: +Have your ZIP of yaml(s) or a single yaml, and submit a POST request to the `/generate` endpoint. +If the options are valid, you'll be returned a successful generation response. (see [Generation Response](#generation-response)) + +Example using the python requests library: +``` +file = {'file': open('Games.zip', 'rb')} +req = requests.post("https://archipelago.gg/api/generate", files=file) +``` + +#### With JSON: +Compile your weights/yaml data into a dict. Then insert that into a dict with the key `"weights"`. +Finally, submit a POST request to the `/generate` endpoint. +If the weighted options are valid, you'll be returned a successful generation response (see [Generation Response](#generation-response)) + +Example using the python requests library: +``` +data = {"Test":{"game": "Factorio","name": "Test","Factorio": {}},} +weights={"weights": data} +req = requests.post("https://archipelago.gg/api/generate", json=weights) +``` + +#### Generation Response: +##### Successful Generation: +Upon successful generation, you'll be sent a JSON dict response detailing the generation: +- The UUID of the generation `detail` +- The SUUID of the generation `encoded` +- The response text `text` +- The page that will resolve to the seed/room generation page once generation has completed `url` +- The API status page of the generation `wait_api_url` (see [Status Endpoint](#status)) + +Example: +``` +{ + "detail": "19878f16-5a58-4b76-aab7-d6bf38be9463", + "encoded": "GYePFlpYS3aqt9a_OL6UYw", + "text": "Generation of seed 19878f16-5a58-4b76-aab7-d6bf38be9463 started successfully.", + "url": "http://archipelago.gg/wait/GYePFlpYS3aqt9a_OL6UYw", + "wait_api_url": "http://archipelago.gg/api/status/GYePFlpYS3aqt9a_OL6UYw" +} +``` + +##### Failed Generation: + +Upon failed generation, you'll be returned a single key-value pair. The key will always be `text` +The value will give you a hint as to what may have gone wrong. +- Options without tags, and a 400 status code +- Options in a string, and a 400 status code +- Invalid file/weight string, `No options found. Expected file attachment or json weights.` with a 400 status code +- Too many slots for the server to process, `Max size of multiworld exceeded` with a 409 status code + +If the generation detects a issue in generation, you'll be sent a dict with two key-value pairs (`text` and `detail`) and a 400 status code. The values will be: +- Summary of issue in `text` +- Detailed issue in `detail` + +In the event of an unhandled server exception, you'll be provided a dict with a single key `text`: +- Exception, `Uncought Exception: ` with a 500 status code + +### `/status/` + +Retrieves the status of the seed's generation. +This endpoint will return a dict with a single key-vlaue pair. The key will always be `text` +The value will tell you the status of the generation: +- Generation was completed: `Generation done` with a 201 status code +- Generation request was not found: `Generation not found` with a 404 status code +- Generation of the seed failed: `Generation failed` with a 500 status code +- Generation is in progress still: `Generation running` with a 202 status code + +## Room Endpoints +Endpoints to fetch information of the active WebHost room with the supplied room_ID. + +### `/room_status/` + +Will provide a dict of room data with the following keys: +- Tracker UUID (`tracker`) +- A list of players (`players`) + - Each item containing a list with the Slot name and Game +- Last known hosted port (`last_port`) +- Last activity timestamp (`last_activity`) +- The room timeout counter (`timeout`) +- A list of downloads for files required for gameplay (`downloads`) + - Each item is a dict containings the download URL and slot (`slot`, `download`) + +Example: +``` +{ + "downloads": [ + { + "download": "/slot_file/kK5fmxd8TfisU5Yp_eg/1", + "slot": 1 + }, + { + "download": "/slot_file/kK5fmxd8TfisU5Yp_eg/2", + "slot": 2 + }, + { + "download": "/slot_file/kK5fmxd8TfisU5Yp_eg/3", + "slot": 3 + }, + { + "download": "/slot_file/kK5fmxd8TfisU5Yp_eg/4", + "slot": 4 + }, + { + "download": "/slot_file/kK5fmxd8TfisU5Yp_eg/5", + "slot": 5 + } + ], + "last_activity": "Fri, 18 Apr 2025 20:35:45 GMT", + "last_port": 52122, + "players": [ + [ + "Slot_Name_1", + "Ocarina of Time" + ], + [ + "Slot_Name_2", + "Ocarina of Time" + ], + [ + "Slot_Name_3", + "Ocarina of Time" + ], + [ + "Slot_Name_4", + "Ocarina of Time" + ], + [ + "Slot_Name_5", + "Ocarina of Time" + ] + ], + "timeout": 7200, + "tracker": "cf6989c0-4703-45d7-a317-2e5158431171" +} +``` + +## User Endpoints +User endpoints can get room and seed details from the current session tokens (cookies) + +### `/get_rooms` + +Retreives a list of all rooms currently owned by the session token. +Each list item will contain a dict with the room's details: +- Room UUID (`room_id`) +- Seed UUID (`seed_id`) +- Creation timestamp (`creation_time`) +- Last activity timestamp (`last_activity`) +- Last known AP port (`last_port`) +- Room timeout counter in seconds (`timeout`) +- Room tracker UUID (`tracker`) + +Example: +``` +[ + { + "creation_time": "Fri, 18 Apr 2025 19:46:53 GMT", + "last_activity": "Fri, 18 Apr 2025 21:16:02 GMT", + "last_port": 52122, + "room_id": "90ae5f9b-177c-4df8-ac53-9629fc3bff7a", + "seed_id": "efbd62c2-aaeb-4dda-88c3-f461c029cef6", + "timeout": 7200, + "tracker": "cf6989c0-4703-45d7-a317-2e5158431171" + }, + { + "creation_time": "Fri, 18 Apr 2025 20:36:42 GMT", + "last_activity": "Fri, 18 Apr 2025 20:36:46 GMT", + "last_port": 56884, + "room_id": "14465c05-d08e-4d28-96bd-916f994609d8", + "seed_id": "a528e34c-3b4f-42a9-9f8f-00a4fd40bacb", + "timeout": 7200, + "tracker": "4e624bd8-32b6-42e4-9178-aa407f72751c" + } +] +``` + +### `/get_seeds` + +Retreives a list of all seeds currently owned by the session token. +Each item in the list will contain a dict with the seed's details: +- Seed UUID (`seed_id`) +- Creation timestamp (`creation_time`) +- A list of player slots (`players`) + - Each item in the list will contain a list of the slot name and game + +Example: +``` +[ + { + "creation_time": "Fri, 18 Apr 2025 19:46:52 GMT", + "players": [ + [ + "Slot_Name_1", + "Ocarina of Time" + ], + [ + "Slot_Name_2", + "Ocarina of Time" + ], + [ + "Slot_Name_3", + "Ocarina of Time" + ], + [ + "Slot_Name_4", + "Ocarina of Time" + ], + [ + "Slot_Name_5", + "Ocarina of Time" + ] + ], + "seed_id": "efbd62c2-aaeb-4dda-88c3-f461c029cef6" + }, + { + "creation_time": "Fri, 18 Apr 2025 20:36:39 GMT", + "players": [ + [ + "Slot_Name_1", + "Clique" + ], + [ + "Slot_Name_2", + "Clique" + ], + [ + "Slot_Name_3", + "Clique" + ], + [ + "Slot_Name_4", + "Archipelago" + ] + ], + "seed_id": "a528e34c-3b4f-42a9-9f8f-00a4fd40bacb" + } +] +```