Concept:
Web UI REST API
Headline
Documentation for the REST API for Web UIs.
Examples
The following Clients implement this API:
The following Servers implement this API:Overview
This API describes a Client-server architecture. All actions are initiated by the Client via sending a POST XMLHttpRequest containing the relevant data formatted in JSON. The Server then processes this requests and sends a response, also in JSON.
First a connection is established and the Client receives the Server configuration and the data model. Afterwards, the client can perform actions on the data model and the server can respond to those with messages and various commands.
Connecting
Initial Contact
This is the first thing the client shall sends to the server to retrieve information about its capabilites and which URLs it should be using for each request. This must always be POSTed against the root URL of the server ("/").
The client's message schema looks like this:
{
"title" : "config request",
"type" : "object",
"required" : ["type"],
"properties" : {
"type" : {"pattern" : "^config$"}
}
}
That is, the clients message is just:
{"type" : "config"}
The server shall respond with a big object describing its configuration:
{
"title" : "config response",
"type" : "object",
"required" : ["method", "types", "actions"],
"properties" : {
"method" : {
"type" : "object",
"required" : ["name", "tree url"],
"properties" : {
"name" : {
"pattern" : "^ajax$",
"description" : "right now there's only one method: ajax"
},
"tree url" : {
"type" : "string",
"description" : "the URL where the model can be retrieved"
},
"action urls" : {
"type" : "object",
"description" : "mappings from actions to their URLs",
"patternProperties" : {
".*" : {"type" : "string"}
}
}
}
},
"types" : {
"type" : "object",
"description" : "types of the model, like company or employee",
"patternProperties" : {
".*" : {
"type" : "object",
"properties" : {
"icon" : {
"type" : "string",
"description" : "URL to an icon for this type"
},
"printf" : {
"type" : "object",
"description" : "display text format for nodes of this type",
"required" : ["format"],
"properties" : {
"format" : {
"type" : "string",
"description" : "a printf-style format string"
},
"args" : {
"type" : "array",
"items" : {"type" : "string"},
"description" : "format argument keys from the node's fields"
}
}
},
"children" : {
"type" : "array",
"items" : {"type" : "string"},
"uniqueItems" : true,
"description" : "keys of types that are valid children"
},
"actions" : {
"type" : "array",
"items" : {"type" : "string"},
"description" : "list of actions for this type, empty string can be used as separator"
}
}
}
}
},
"actions" : {
"type" : "object",
"description" : "mappings of action keys to the way they are displayed",
"patternProperties" : {
".*" : {
"oneOf" : [
{
"type" : "string"
},
{
"type" : "object",
"required" : ["text"],
"properties" : {
"text" : {"type" : "string"},
"icon" : {"type" : "string"}
}
}
]
}
}
}
}
}
Since the structural information above can be a bit overwhelming, it is probably easier to refer to these examples. They are in YAML, but are structurally equivalent to JSON:
Retrieving the Model
After receiving a valid server configuration, the client shall send a request to the tree url it was given to retrieve the model. The request looks like this:
{
"title" : "tree request",
"type" : "object",
"required" : ["type"],
"properties" : {
"type" : {"pattern" : "^tree$"}
}
}
So again, it's just a type in an object:
{"type" : "tree"}
The server shall then respond with its current object model, whose schema looks like this:
{
"title" : "tree response",
"type" : "array",
"items" : {"$ref" : "#/node"},
"node" : {
"type" : "object",
"description" : "recursive tree of nodes",
"required" : ["type", "text"],
"properties" : {
"type" : {
"type" : "string",
"description" : "type of the node, must reference a type given in the configuration"
},
"text" : {
"type" : "string",
"description" : "title, name, e.a. of a node"
},
"children" : {
"type" : "array",
"items" : {"$ref" : "#/node"},
"description" : "array of child nodes below a node"
}
}
}
}
Note that each node has a unique ID and child nodes of all types are in one array, there's no separation for departments, employees or managers. If your server-side model differs from this, you will need to convert it to this format.
An example response looks like this:
[
{
"type" : "root",
"id" : "1C4B98C6-2E48-11E4-8B8F-829F24AF2D0B",
"text" : "Companies",
"children" : [
{
"type" : "company",
"text" : "ACME Corporation",
"id" : "1C4B96B4-2E48-11E4-8B8F-829F24AF2D0B",
"children" : [
{
"type" : "department",
"id" : "1C4B42CC-2E48-11E4-8B8F-829F24AF2D0B",
"text" : "Research",
"children" : [
{
"type" : "employee",
"text" : "Ralf",
"address" : "Koblenz",
"id" : "1C4AB564-2E48-11E4-8B8F-829F24AF2D0B",
"salary" : "1234"
}
]
}
]
}
]
}
]
Client Actions
Once the model has been received, the client can perform actions on it. The server shall respond to each action it has described in its configuration with a response (see next section). What the server decides to respond with is not defined by this protocol, it is up to the implementation to do something sensible and tell the client about it.
Regular Actions
A regular action is performed on a single node. The client shall only perform actions that are valid as per the configuration it received and they shall be POSTed against the appropriate URLs, also as per configuration received.
The schema for an action looks like this:
{
"title" : "regular action",
"type" : "object",
"required" : ["type", "id"],
"properties" : {
"type" : {
"type" : "string",
"description" : "the type of action being performed"
},
"id" : {
"type" : "string",
"description" : "the ID of the node the action is being performed on"
}
}
}
A sample action, which would be sent to the server's /total URL:
{
"type" : "total",
"id" : "1C4B96B4-2E48-11E4-8B8F-829F24AF2D0B"
}
Restructure Action
This action is for invoking Feature:Restructuring. The action is performed on two nodes: the source node that is being moved and the target node it is to become a child of.
The client shall only invoke this action if the configuration defines an action called "restructure", and POST it against the appropriate URL if it is given. It shall also not attempt to restructure incompatible types, as per the server's types' children configuration.
The schema for a restructure action looks like this:
{
"title" : "restructure action",
"type" : "object",
"required" : ["type", "id", "target"],
"properties" : {
"type" : {
"pattern" : "^restructure$"
},
"id" : {
"type" : "string",
"description" : "the ID of the node to be moved"
},
"target" : {
"type" : "string",
"description" : "the ID of the node that should become the parent of the moving node"
},
"pos" : {
"type" : "integer",
"description" : "the position in target's children the moving node should end up with"
}
}
}
An example:
{
"type" : "total",
"id" : "1C4B96B4-2E48-11E4-8B8F-829F24AF2D0B",
"target" : "123E4567-E89B-12D3-A456-426655440000",
"pos" : 0
}
Server Responses
There are two things the server can send with a response: messages and commands. The server can send any number of these in its response to any action. What kind of response an action elicits is up to the implementation.
When the client submits a form the server should also send a response to the form. See #Form below for details.
The schema for a response looks like this:
{
"title" : "response",
"type" : "object",
"properties" : {
"commands" : {
"oneOf" : [
{
"$ref" : "#/definitions/command"
},
{
"type" : "array",
"items" : {"$ref" : "#/definitions/command"}
}
]
},
"messages" : {
"oneOf" : [
{
"$ref" : "#/definitions/message"
},
{
"type" : "array",
"items" : {"$ref" : "#/definitions/message"}
}
]
},
"form" : {
"type" : "object",
"properties" : {
"valid" : {
"description" : "anything truthy or falsey"
},
"errors" : {
"type" : "object",
"description" : "mapping from field name to error message",
"patternProperties" : {
".*" : {"type" : "string"}
}
}
}
}
},
"definitions" : {
"command" : {
"type" : "object",
"description" : "see individual command types for structure information"
},
"message" : {
"oneOf" : [
{
"type" : "string",
"description" : "just a message with no particular type"
},
{
"type" : "object",
"description" : "a message with a type, such as 'error'",
"required" : ["text"],
"properties" : {
"text" : {"type" : "string"},
"type" : {"type" : "string"}
}
}
]
}
}
}
Commands
There are various different types of commands that tell the client to do certain things. They will all be explained in the following.
add
The client shall add the given node to the parent node. The parent node must exist.
Schema:
{
"title" : "add command",
"type" : "object",
"required" : ["type", "node"],
"properties" : {
"type" : {"pattern" : "^add$"},
"parent" : {
"type" : "string",
"description" : "ID of the parent node"
},
"node" : {
"description" : "same as nodes in initial model response"
}
}
}
Example command:
{
"type" : "add",
"parent" : "1C4B42CC-2E48-11E4-8B8F-829F24AF2D0B",
"node" : {
"type" : "employee",
"id" : "1C4AB2B2-2E48-11E4-8B8F-829F24AF2D0B",
"text" : "Erik",
"address" : "Utrecht",
"salary" : "12345"
}
}
edit
The client shall find the node with the same ID and then set all fields of the local node that exist in the command node to the value of the command node's field.
Schema:
{
"title" : "edit command",
"type" : "object",
"required" : ["type", "node"],
"properties" : {
"type" : {"pattern" : "^edit$"},
"node" : {
"description" : "same as nodes in initial model response, except all fields but id are optional"
}
}
}
As an example, take a local Node that looks like this:
{
"type" : "employee",
"text" : "Ralf",
"address" : "Koblenz",
"id" : "1C4AB564-2E48-11E4-8B8F-829F24AF2D0B",
"salary" : "1234"
}
And the command looks like this:
{
"type" : "edit",
"node" : {
"id" : "1C4AB564-2E48-11E4-8B8F-829F24AF2D0B",
"text" : "Ralph",
"salary" : "123"
}
}
Then only the fields "text" and "salary" shall be changed, the fields not mentioned stay the same. The result is:
{
"type" : "employee",
"text" : "Ralph",
"address" : "Koblenz",
"id" : "1C4AB564-2E48-11E4-8B8F-829F24AF2D0B",
"salary" : "123"
}
move
The client shall move the given source node under the given target node, either at the position that is given or at the end of the children list if none is given.
Schema:
{
"title" : "move command",
"type" : "object",
"required" : ["type", "source", "target"],
"properties" : {
"type" : {"pattern" : "^move$"},
"source" : {
"type" : "string",
"description" : "ID of the node to be moved"
},
"target" : {
"type" : "string",
"description" : "ID of the node that should become the parent"
},
"pos" : {
"type" : "integer",
"description" : "the position in target's children the moving node should end up with"
}
}
}
Example command:
{
"type" : "move",
"source" : "1C4AB564-2E48-11E4-8B8F-829F24AF2D0B",
"target" : "123E4567-E89B-12D3-A456-426655440000",
"pos" : 0
}
delete
The client shall remove the given node and all of its children from the local model.
Schema:
{
"title" : "delete command",
"type" : "object",
"required" : ["type", "id"],
"properties" : {
"type" : {"pattern" : "^delete$"},
"id" : {
"type" : "string",
"description" : "ID of the node to be deleted"
}
}
}
Example command:
{
"type" : "delete",
"id" : "1C4AB564-2E48-11E4-8B8F-829F24AF2D0B"
}
form
See #Forms below.
Messages
Messages are just informational text for the client, which should just present them to the user.
Forms
The server may send a form command to the client, which should show it to the user to be filled out.
The schema explains what the form command looks like and it should be clear how the client could display it:
{
"title" : "forms command",
"type" : "object",
"required" : ["type", "submit", "fields"],
"properties" : {
"type" : {"pattern" : "^form$"},
"title" : {
"type" : "string",
"description" : "optional title for the form"
},
"submit" : {
"type" : "string",
"description" : "URL to POST this form to"
},
"fields" : {
"type" : "array",
"description" : "fields of the form",
"items" : {
"type" : "object",
"required" : ["name"],
"properties" : {
"name" : {"type" : "string"},
"label" : {"type" : "string"},
"value" : {"type" : "string"}
}
}
}
}
}
Example command:
{
"type" : "form",
"title" : "Edit Employee",
"submit" : "/save/edit/employee/1C4AB564-2E48-11E4-8B8F-829F24AF2D0B",
"fields" : [
{
"name" : "text",
"label" : "Name",
"value" : "Ralf"
},
{
"name" : "address",
"label" : "Address",
"value" : "Koblenz"
},
{
"name" : "salary",
"label" : "Salary",
"value" : "1234"
},
]
}
The client shall POST the results of this form like a regular web form. The server should then respond with a form response (see #Server Responses) that tells the client if the submitted form was valid. If it's valid, the form should be closed. Otherwise there should be a mapping of errors that should be presented to the user.
Sample response:
{
"form" : {
"valid" : 0,
"errors" : {
"name" : "This can't be empty.",
"salary" : "This can't be negative."
}
}
}
There are no revisions for this page.
User contributions
User edits
Syntax for editing wiki
For you are available next options:will make text bold.
will make text italic.
will make text underlined.
will make text striked.
will allow you to paste code headline into the page.
will allow you to link into the page.
will allow you to paste code with syntax highlight into the page. You will need to define used programming language.
will allow you to paste image into the page.
is list with bullets.
is list with numbers.
will allow your to insert slideshare presentation into the page. You need to copy link to presentation and insert it as parameter in this tag.
will allow your to insert youtube video into the page. You need to copy link to youtube page with video and insert it as parameter in this tag.
will allow your to insert code snippets from @worker.
Syntax for editing wiki
For you are available next options:will make text bold.
will make text italic.
will make text underlined.
will make text striked.
will allow you to paste code headline into the page.
will allow you to link into the page.
will allow you to paste code with syntax highlight into the page. You will need to define used programming language.
will allow you to paste image into the page.
is list with bullets.
is list with numbers.
will allow your to insert slideshare presentation into the page. You need to copy link to presentation and insert it as parameter in this tag.
will allow your to insert youtube video into the page. You need to copy link to youtube page with video and insert it as parameter in this tag.
will allow your to insert code snippets from @worker.