Conventions
Zander API rules
When editing the API, these rules should be strictly followed.
Naming conventions
-
GETrequests must have the suffix/getin the endpoint. For example:GET rank/getGET punishments/getGET communitycreation/getGET knowledgebase/article/get
So far, no endpoints that we have added requires needing more than one
GETrequest per endpoint group (rank/discord/server/shop etc). Thus, it makes sense to try and unify the design across these endpoints. -
GETrequests that require parameters are only injected via query. For example:GET rank/get?username=shadowwolfytGET punishments/get?limit=20GET communitycreation/get?id=1337
These parameters must be included in the documentation to tell other users how it works.
-
POSTrequests must NOT have the suffix/getin the name (surely this is obvious). -
POSTrequests that require parameters are only injected viajson. No querying, or params in the endpoint. For example:POST shop/create/item{
"shopId": 2,
"shopItem": "glass",
"shopPrice": 2,
"shopBuyQuantity": 128
}POST discord/chat{
"username": "shadowolfyt",
"server": "Survival",
"content": "This server is awesome"
}POST session/destroy{
"uuid": "0af03841-2894-434c-a4be-965b317244e8" // shadowolfyt
}
Response format
These exist to prevent API functionality from mingling with website functionality. For example, it should be illegal for the API to redirect the user. It must always return json.
-
All
GETendpoints must returnjsondata that adheres to the following format:{
"success": [true|false], // Must be a boolean
"message": "<message>", // Optional field. Can exist regardless
// of the value of success.
"data": // Result from the get request goes here. This field must
// only exist if success == true. The data type this
// field holds can be arbitrary (dict, list, bool, int,
// etc.)
}Valid:
{
"success": false,
"message": "The userId is invalid"
}{
"success": true,
"data": {
"player": "shadowwolfyt",
"diamonds": "1337"
}
}{
"success": true,
"message": "Hello, World!",
"data": [ 1, 2, 3, 4, 5 ]
} -
All
POSTendpoints must returnjsondata that adheres to the following format:{
"success": [true|false], // Must be a boolean
"message": "<message>" // Optional field. Can exist regardless
// of the value of success.
}Valid:
{
"success": false,
"message": "User already exists"
}{
"success": true
}
GET Request Response
-
GETrequests with no query, should default to returning all of that kind without any filtering. -
Any
GETrequests with queries, should only be filtering output, not including something new that wasn't there before. For example:If
GET rank/getreturned this:{
"success": true,
"data": [
{ "admin": [ "shadowwolfyt" ] },
{ "user": [ "shadowwolfyt", "Camemes" ] }
]
}Then,
GET rank/get?username=Camemescould NOT return:{
"success": true,
"data": [
{ "donator": [ "Camemes" ] },
{ "user": [ "Camemes" ] }
]
}As this would not fit the rule because "donator" did not appear in the non-filtered result of the plain
/get. -
To follow from rule 2, filtering the output using a query, must not change the return result format (TODO: unless maybe specified in the documentation?). This is to ensure consistency when applying multiple filters at the same time. This may result in empty data, and that's okay. For example:
If
GET rank/getreturned this:{
"success": true,
"data": [
{ "admin": [ "shadowwolfyt" ] },
{ "user": [ "shadowwolfyt", "Camemes" ] }
]
}Then
GET rank/get?username=Camemes&rank=adminwould return:{
"success": true,
"data": []
}noteThe data is empty because the filters reduced the result to empty, however the query still returns
"success": true. This tells the end user that an error did not occur and the filters were successfully applied. It may be desired behaviour to expect an empty result. An example of this might be the endpointGET punishments/get?username=shadowwolfyt. Where an empty result means usershadowwolfythas no punishments. Also note that the data type ofdatain the plain/getwas a JSON array, thus the data type ofdatain the filtered query is also an empty JSON array. -
Because of rule 1,
GETendpoints expecting very large output should implement the query?limit=xwherexis an integer that defines the return result limit. What the limit does for each endpoint is up to the implementation, however it should be noted in the documentation. For example:GET punishments/get?limit=3{
"success": true,
"data": [
{ "player": "shadowwolfyt", "when": "1 second ago" }, // Obviously time is not stored as a string, but you get the idea
{ "player": "Camemes", "when": "10 seconds ago" },
{ "player": "StryderEpic", "when": "25 seconds ago" }
]
}In the example above, the
GET punishments/getendpoint decided that limit=3 should only return the latest 3 punishments issued. -
GETendpoints expecting very large output should also implement the query?page=xwherexis an integer that defines the page that is returned. The data to return is defined as(page + 1) * limitwhere onlylimitentries are returned. For example:GET punishments/get{
"success": true,
"data": [
{ "player": "one", "when": "1 second ago" },
{ "player": "two", "when": "10 seconds ago" },
{ "player": "three", "when": "25 seconds ago" },
{ "player": "four", "when": "30 seconds ago" },
{ "player": "five", "when": "35 seconds ago" },
{ "player": "six", "when": "40 seconds ago" }
]
}GET punishments/get?limit=2&page=1{
"success": true,
"data": [
{ "player": "one", "when": "1 second ago" },
{ "player": "two", "when": "10 seconds ago" }
]
}GET punishments/get?limit=2&page=2{
"success": true,
"data": [
{ "player": "three", "when": "25 seconds ago" },
{ "player": "four", "when": "30 seconds ago" },
]
}GET punishments/get?limit=2&page=4{
"success": true,
"data": []
}Aron_with_an_aIn MySQL this can be done simply with the offset parameter.
// set the number of items to display per page
const limit = req.body.limit;
const page = (req.body.page) ? req.body.page : 1;
const offset = (page - 1) * limit;
// build query
const sql = "SELECT * FROM punishments LIMIT " . offset . "," . limit;That will return paginated results from the database
-
Any
GETrequest that returns a list should always return"success": trueif the resulting data is an empty list if the input queries are valid. For example:GET rank/get?username=NoPlayer{
"success": true,
"data": []
}
Documentation conventions
-
When writing documentation for
GETrequests, all unique parameters'infofields must start with the string: "Filter by", and they must also beoptional: true. For example:# ...
rank:
sidebar: Ranks
files:
- get.mdx:
route: rank/get
method: GET
privileged: false
short: Get rank assignments
description: Returns a list of all the ranks and the users assigned to each rank.
parameters:
username:
type: string
info: Filter by matching user IGN.
optional: true
# ...