So, this is the KAG Web API. Or maybe it’d be better to start calling it the THD API, as you’ll be seeing other games using it soon enough... But enough vague teasers for now ;)
It is a RESTful Web API that uses JSON as the primary means of conveying information between HTTP requests. I’m not going to elaborate a great deal on what REST is, but if you want to know more then there’s plenty of info out there just a quick Google away. Some of the most important elements as far as this API is concerned are that everything uses a consistent HTTP interface (using the various HTTP methods, e.g. GET, PUT, POST, DELETE), most resources are cacheable by the clients (details later in this intro) and the interactions between the API & clients are stateless (client context is not stored between requests).
Developers can use this API to request information about and/or manage entities represented within the API, (such as games, players or servers) provided that they have sufficient permissions to allow them to do so. For example, we (the THD devs) use the API to authenticate players logging into King Arthur’s Gold using the player resources, as well as using the server resources in order to maintain a server lobby for the game (which have also been used by community developers to make their own server list websites).
The absolute simplest answer for ‘how do you use the API?’ is ‘by making HTTP requests’. In fact, in many cases you can make a simple GET request to one of the API resources with the same browser you’re using the view this documentation e.g. https://api.kag2d.com/v1/game/thd/kag will return basic information about the game King Arthur’s Gold.
However, there is quite a bit more to the API’s usage, which I will detail below.
This is the documentation for the current, actively developed version of the API, V1. The root address for all URLs used by the API is therefore https://api.kag2d.com/v1/, e.g. https://api.kag2d.com/v1/player/Shadlington/info.
Also available are https://api-dev.kag2d.com/v1 and https://api-test.kag2d.com/v1 for the dev and test instances of the API, respectively.
One final thing I’d like to point out is that for this API it is often the case that non-200 response codes indicate that some form of error or warning, and in these cases the response body will be JSON-formatted and contain the following elements:
It is generally the case that every resource exposed by this API has only one URL mapped to it, with only one exception: game-specific entities and their resources. For game-specific entities (in contrast to universal entities such as players and devgroups) like servers and mods, we prefix their URLs with the path to the resource for the game they are tied to (e.g. https://api.kag2d.com/v1/game/thd/kag/servers). However, because games have two possible URL structures mapping to them (see Games for details), all game-specific resources also have two URL structures mapping to them, made up by attaching their specific resource path (/servers in the previous example) to each of the two possible game URL prefixes (/game/thd/kag and /game/1 for KAG).
For example, with the example above (https://api.kag2d.com/v1/game/thd/kag/servers), https://api.kag2d.com/v1/game/1/servers also maps to the same resource.
Some resources provide a standardised list format for entities of a particular type, e.g. https://api.kag2d.com/v1/devgroups lists devgroups. These list are always represented as a JSON array of JSON objects, where each object follows the same format as one of the other resources for the given entity (the docs for the specific list will specify which resource they are the same as).
There are always 3 optional query variables that can be specified for these lists: start, limit and filters. Start and limit are simple - they’re used to retrieve blocks of results in chunks.
Limit specifies how many results to retrieve and start specifies at which result to start retrieving them. The default (i.e. when you don’t include start or limit variables) is start=0 and limit=20, which will fetch the first 20 results. If you set limit to -1 then all results will be retrieved.
Filters are more complicated. The filters variable is encoded as flattened JSON - specifically as an array ‘[]’ of objects ‘{}’, with each object consisting of 2-3 key-value pairs: field, value and (optionally) op.
Field specifies what field is to be filtered. Value is the value to filter the field on. Op specifies what operator to use to filter it (from eq, ne, le, lt, ge and gt - with eq as the default used when op is omitted).
Example: [{“field”: “build”, “op”: “eq”, “value”: 590}, {“field”: “currentPlayers”, “op”: “ge”, “value”: 5}] could be used on the servers list resource to filter the list to servers where build=590 and currentPlayers>=5.
All filters in the list are AND’d together (there is no OR).
Each resource may have special custom filters that bend these rules slightly, but they will be explained in the docs for that resource.
You can filter on most of the fields you can see when you GET a server status, but for the exact list of which fields are available for filtering you should consult the filterinfo resource for the given list, accessed at the URL made by adding ‘/filterinfo’ to the end of the list resource’s own URL. This is most useful for game-specific resources, where it will soon (though it currently does not) show the list of filter available for the specified game, with each game potentially having a different set of available filters.
Note that where these list resources are game-specific, you can essentially treat the game prefix as an additional, mandatory filter criteria that limits the list to those entities linked to the specified game.
In all cases where the API requires authentication we use basic HTTP authentication, where the username is a KAG player account username (presumably your own one) and the password is the password for said account. It is usually the case that you have to be the player directly associated with the resource to be authorised, with the exception of those resources that are linked to devgroups instead of individuals (see Devgroups for details), where it the rules get more complicated (and you should refer to the specific resource documentation), but generally you have to at least be a member of the group.
Two kinds of caching are/can be used with this API. The first is server-side caching (which you have no control over). Many resources will be cached by the server after they generate, for a length of time that is specific to the resource in question. This can occasionally lead to some resources being out of date - particularly when it comes to list type resources, which do not have their caches invalidated by PUTs to the individual resources they are listing.
The second type of caching is client-side caching. This is implemented through conditional HTTP GET requests - which revolves around using If-Modified-Since + Last-Modified and If-None-Match + ETag headers in your GET requests.
Basically, most resources will provide Last-Modified and ETag headers in successful GET responses. If, in a subsequent GET request to the same resource, you set the If-Modified-Since header to the value of previous response’s Last-Modified header, then if the resource has not been modified since the last time you made a request (i.e. the Last-Modified header of the resource hasn’t changed) then the response will have an empty body (and thus should return faster) and a status code of 304. If it has changed you’ll get a 200 as usual with the updated resource contents in the body.
Similarly, if you set the If-None-Match header to the value of previous response’s ETag header, then you will get an empty 304 response if the resource is unchanged since the request when you obtained the ETag (the ETag should, in theory, be different whenever a resourced is changed in a meaningful way, as it is usually made by hashing the resource body). If-Modified-Since and If-None-Match can either be used individually or together in the same request.
So to implement client-side caching you can store the GET responses in a cache along with their Last-Modified/Etag headers and only update them when requests made with the appropriate headers come back with a 200 rather than a 304.
A notable use of the ETag headers exists in Mods, where package ETags are set to match the devHash present in the package registration.json file, so the devHash can be used in the If-None-Match header to check whether your local copy of the mod package is outdated or not.
Kind of a minor point, but worth being aware of: all trailing-slashed paths will 301 redirect to their de-slashed equivalent (e.g. https://api.kag2d.com/v1/player/Shadlington/info/ will redirect to https://api.kag2d.com/v1/player/Shadlington/info).
All timestamps should be in UTC. Please report any instances where you believe this is not the case.
If there’s anything you feel is missing from anywhere in these docs (or just plain wrong!), please let me (Shadlington) know, either by PM’ing me over at https://forum.thd.vg/, or via my email shadlington@thd.vg.