Introduction

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 ;)

So what is this API and what is it for?

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).

General usage

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.

URL roots

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.

Anatomy of API requests/responses

  • The URL: This designates which API resource is being accessed
  • The HTTP method: GET/PUT/POST/DELETE (+ other lesser-used methods like HEAD) designate the operation being carried out on the resource. Most API resources only have a sub-set of these methods enabled.
  • The request body: this will often be empty, but if it does contain anything it will usually be for a PUT/POST request, and either contain JSON-formatted data or the contents of a file (such as a PNG image for server minimaps).
  • The response body: this request body description also applies to this, except that it pertains to the response sent back by the API.
  • The response status code: a 2XX code (most commonly 200) indicates that a request was successful, a 3XX code indicates that some form of redirection is appropriate, whilst other codes often mean that something is wrong. In general its best to look at the possible status codes for a given resource in its API reference. In general, however, you will receive a 404 if you access a URL that doesn’t map to any resource at all, a 405 if you try to use a HTTP method that is unsupported for a given resource, and a 500 if something you did caused an error in the API (pleaseeeee report any 500s you find to shadlington@thd.vg so I can fix them!).
  • The request/response headers: these specify additional meta data about the request/response, covering all manner of things from the content type to the method of authentication. The headers significant to the API will be detailed in other sections. A very common one is the Content-Type header, which you should set to application/json whenever making a request in which you include JSON-formatted data within the request body.

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:

  • statusCode The actual HTTP status code of the response (e.g. 404)
  • statusSubCode Sub-code present in some cases, where distinction matters
  • subType A readable name to go with the above sub-code
  • statusMessage Gives a human-readable message to explain the issue

Game-specific URL prefixes

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.

List type resources

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.

Authentication

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.

Caching

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.

De-slashing

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).

Timestamps

All timestamps should be in UTC. Please report any instances where you believe this is not the case.

Anything I missed?

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.