-
Notifications
You must be signed in to change notification settings - Fork 86
Analyzing the jsonapi request and response format
#Analyzing the JSONAPI request and response format This is for people interested in how the JSONAPI API request and response format works. If you are interested in a guide on how to use the API please look at the guides section on the Home page of the wiki.
##Requests All requests for JSONAPI fall into one of four categories. These categories are:
- A standard API request
- A multiple API request
- A stream API request
- An invalid request
###Standard API request
A standard API request is one where a request is made for data, and the data is immediately returned. Examples of standard API methods are getPlayerLimit
and getServerVersion
.
A standard API request looks like this:
/api/call?method={methodName}&args={jsonEncodedArrayOfArgs}&key={key}&tag={identifier}
Every thing in curly braces in that URL is something you will need to change for each different API request. Let's analyze each one:
-
{methodName}
is the the name of the API method you wish to call. There is a list of the default ones built into JSONAPI are available at this page. Some examples values aregetPlayerLimit
,getPlayer
ordynmap.getPort
. -
{jsonEncodedArrayOfArgs}
is a JSON encoded array of arguments for a particular method. Every argument listed on the method API docs is required. It is recommended to pass an empty array when there are no arguments. However, not utilizing theargs
GET variable is also acceptable. Do not forget to escape the JSON encoded result in accordance with RFC 3986. In PHP therawurlencode
function satisfies this. In JavaScript the escape() function seems to satisfy this. Example:["hello","world"]
will convert to%5B%22hello%22%2C%22world%22%5D
. -
{key}
is a valid key for this method (see below for more information on keys). -
{identifier}
and itstag
argument are optional. The tag is a string and will be included in the response and can be used to identify a response. It comes in very handy if you have multiple handlers registered for only one socket connection.
Here are some examples of valid URLs for the user alecgorge
with the password MySecret
and salt pepper123
:
/api/call?method=reloadServer&args=%5B%5D&key=6821b5b40aa8e91487f95831cc0c0ea1eb1aafe2901447f7d9b9d76a495dcf92
/api/call?method=getBukkitVersion&key=1d4034ddbda9189ae2175ab929012ba8a7bba7c7121497a1a0eb122c572f8de8
/api/call?method=getPlayer&args=%5B%22silvinci%22%5D&key=341f36fce351707911d4baaa0f245f09222aaa5b7d907f3f43781d6dafdb6c94
/api/call?method=broadcastWithName&args=%5B%22Hello%22%2C%22silvinci%22%%5D&key=4f77adf03116c4ca4e19c93a39595b0e8c04bd1df718fd8e366f08c2cd1edeee
You can use standard API requests in both a HTTP request and an open socket connection. See How to use the standard API over HTTP and How to use the standard API over a socket connection for more information.
###Multiple API request
Exactly the same as a standard API request, but method
is a JSON-encoded array of method names and args
is a JSON-encoded array of arrays. Don't forget to properly escape both. Also, make sure all requests go to /api/call-multiple
not /api/call
.
/api/call-multiple?method={jsonEncodedArrayOfMethodNames}&args={jsonEncodedArrayOfArgs}&key={key}
Here is an example:
+-------- Methods --------+---According arguments ---+----------------- Function ---------------+
| getPlayer | ["silvinci"] | Get information about player silvinci |
| givePlayerItemWithData | ["silvinci", 35, 64, 14] | Give player silvinci a stack of red wool |
| opPlayer | ["silvinci"] | Make player silvinci OP |
| getPlayerCount | [] | Get the number of online players |
+-------------------------+--------------------------+------------------------------------------+
JSON encoded arrrays:
["getPlayer","givePlayerItemWithData","opPlayer","getPlayerCount"]
[ ["silvinci"],["silvinci",35,64,14],["silvinci"],[]] // due to a technical limitation of GitHub, there is a space needed between [ and the following [. It doesnt belong there.
Escaped:
%5B%22getPlayer%22%2C%22givePlayerItemWithData%22%2C%22opPlayer%22%2C%22getPlayerCount%22%5D
%5B%5B%22silvinci%22%5D%2C%5B%22silvinci%22%2C35%2C64%2C14%5D%2C%5B%22silvinci%22%5D%2C%5B%5D%5D
Putting it all together for the user alecgorge
with the password MySecret
and salt pepper123
:
/api/call-multiple?method=%5B%22getPlayer%22%2C%22givePlayerItemWithData%22%2C%22opPlayer%22%2C%22getPlayerCount%22%5D&args=%5B%5B%22silvinci%22%5D%2C%5B%22silvinci%22%2C35%2C64%2C14%5D%2C%5B%22silvinci%22%5D%2C%5B%5D%5D&key=760457f2d3bbbe2ae6e8c3766119464e99e454057d799b8097948f9217c1eab6
###Stream API request A stream API request is one where a request is made to "subscribe" to a particular data source, and as new data is found on the server, another response line is sent back to the client.
A stream API request looks like this:
/api/subscribe?source={sourceName}&key={key}&show_previous={showPrevious}
Every thing in curly braces in that URL is something you will need to change for each different API request. Let's analyze each one:
-
{sourceName}
is the the name the data source you want to subscribe to. The only options right now arechat
,console
andconnections
. -
{key}
is a valid key for this method (see below for more information on keys). -
{showPrevious}
(optional, default istrue
) is eithertrue
orfalse
. The last 50 messages will be sent immediately if this istrue
.
You can use stream API requests in both a HTTP request and an open socket connection. See How to use the stream API over HTTP and How to use the stream API over a socket connection for more information.
###An invalid request An invalid request does not fulfill any of the other request types.
##Key format
All requests need to be authenticated with a key for security reasons. The key is a sha256 sum of a string in this format: username + methodNameOrSourceName + password + salt
-
username
needs to be a valid username that is in the server'sconfig.yml
in theplugins/JSONAPI/
folder. -
methodNameOrSourceName
is the name of the method that you are trying to call. If you are using the multiple-call API, then this should just be the JSON-encoded array of methods. It can also be the name of the data source you are trying to subscribe to in the stream API. This should be exactly the same as the unescapedmethod
orsource
GET
variable. -
password
is the corresponding password tousername
. -
salt
is the salt set in the server'sconfig.yml
in theplugins/JSONAPI
folder.
This format means that there is a different key for each different API method. When you have multiple username and password combinations, that means that there can be more than one valid key.
Here are some examples of valid keys for the user alecgorge
with the password MySecret
and salt pepper123
:
getBukkitVersion -> alecgorgegetBukkitVersionMySecretpepper123 -> b97162cc3ec6d230d196b7f5950dc2dcb2877947ddbc2db7268f8e0ebf797a1e
saveMap -> alecgorgesaveMapMySecretpepper123 -> 37db859d3d23d3affcabdc72ec66d34cda8dea58ee0e0dc7bce8fa9af4ac2db2
reloadServer -> alecgorgereloadServerMySecretpepper123 -> 858eef1c1591a2a5c3f156b92cb60948d65c1ed5867a4cc0100d57897f8fb572
["getPlayer","givePlayerItemWithData","opPlayer","getPlayerCount"] -> alecgorge["getPlayer","givePlayerItemWithData","opPlayer","getPlayerCount"]MySecretpepper123 -> 760457f2d3bbbe2ae6e8c3766119464e99e454057d799b8097948f9217c1eab6
connections -> alecgorgeconnectionsMySecretpepper123 -> 93d730c15edd4a66ff12a9b9ebbfb1842d301a06db25000cfa28ff5fb7b80009
Here are some examples of key generation in different languages:
$key = hash('sha256', $username . $methodNameOrSourceName . $password . $salt);
// this assumes you have a method called `sha256` that creates the SHA256 hash from a `String`
String key = sha256(username + methodNameOrSourceName + password + salt);
var crypto = require("crypto");
function getKey(username, methodNameOrSourceName, password, salt) {
var shasum = crypto.createHash("sha256");
shasum.update(username + methodNameOrSourceName + password + salt);
return shasum.digest("hex");
}
var key = getKey(username, methodNameOrSourceName, password, salt);