MyRobotLab API Service Endpoints
MRL offers several service endpoints with the WebGUI service.
You may send command or recieve data through these endpoints.
All service endpoints begin the same way.
{scheme}://{host}:{port}/api/{apiKey}
e.g. http://localhost:8888/api/service/
The litteral api is required.
At this point an api type needs to be specified.
http(s)://host:port/api/{apiKey}
Currently only 2 api types are supported they can be services or messages
Service API
This api is can call any method on any service and return the data returned by the method encoded in json. It blocks and does not susped the connection.
CALLING METHODS
http(s)://host:port/api/service/{name}/{method}/{param0}/{param1}/...
example:
GET http://localhost:8888/api/service/runtime/getUptime
returns:
"0 days 0 hours 9 minutes 43 seconds"
FINDING METHODS
All of the public methods of any service can quickly be displayed in detail by using the following url.
GET http://localhost:8888/api/service/{name}/ <- You'll notice the trailing slash.
Above is the beginning of the list of methods we have access to. The first one is availableProcessors. The method takes no parameters, and returns an integer.
The method would be called like this:
GET http://localhost:8888/api/runtime/availableProcessors
If the method has "simple" parameters, they are just added with slashes.
runtime.createAndStart takes 2 parameters
So the GET url would look like this.
And servo01 has been created and started.
What is returned is all the data within the servo.
DISPLAYING SERVICE DATA
To get any service's data a url with the service name is used "without" the trailing slash
More complex method parameters require the Messages API
Messages API
The messages api is utilized by the WebGUI client. The connection is upgraded to websockets. Long Polling is used as a fall back if websockets are not supported. Once the connection is established messages are passed back and forth in an asynchronous manner. The messages are encoded in JSON.
ws(s)://host:port/api/messages
POST ws://localhost:8888/api/messages{"name":"runtime","historyList":[],"method":"getUptime","data":[]}
Explanation:
- http(s) ws(s):// - uri scheme
- host:port - the host & port where MyRobotLab WebGUI service is running
- apiKey - messages or service - the messages api will suspend the connection through a websocket or long polling - this will allow asynchronous message exchange. json will not suspend the connection and the return data will not be wrapped in a message
- {service} - the named service
- {method} - is the method to be invoked
Example:
The very root of the API returns the current running service. In this case there are 2 services running "runtime" & "webgui". The current platform is returned too. From this information we can construct a few more URLs to give us more details about the running services.
Synchronous vs Asynchronous
TODO
- this is a API document - create anothe for "messaging" - do not mix the two
- how to reflect help & examples
- explanation of Synchronous vs Asynchonous
- Objective is to be "intuitive", friendly & consistent
- Actual examples with code
Rules and Observations
- Any URL with this notation can be changed into a Message, and any Message into a URL
- HTTP & the internet is functional not OO - REST is a good design to follow
- Using all HTTP verbs is not nearly as easy or ubiquitous as using the universal GET
- POST & GET in MRL API work identically - both can send an array of parameters. GET sends the parrameters with / being the divider. POST sends them in an encoded array for example in JSON it would be ["param0","param1","param2"]
Conventions
- http://localhost:3333/api - gives you a list of service names which can be used in the next URI
- http://localhost:3333/api/{service name} - gives you the current state of the services
- http://localhost:3333/api/{service name}/help - gives the reflected simple signature of methods of the service - *** I WISH IT GAVE PARAM NAMES *** - regrettably these get compiled out - TODO is to use index into the Javadoc - where Javadoc is a "help" resource in the repo
- http://localhost:3333/api/{service name}/help/javadoc - help in Javadoc format
- http://localhost:3333/api/{service name}/ = http://localhost:3333/api/{service name}/help
Runtime - the nameless service
RULE : - no name == Runtime !!!!
internal queues
Methods
Because MRL is a distributed, these methods will behave the same regardes if there is one MRL instance running or a network of them.
name | group | self | local | remote | blocking | async |
---|---|---|---|---|---|---|
addListener | pub/sub | X | X | X | ||
removeListener | pub/sub | X | X | X | ||
removeAllListeners | pub/sub | X | X | X | ||
invoke | invoke | X | X | X | ||
send | invoke | X | X | |||
sendBlocking | invoke | X | X | |||
subscribe | pub/sub | X | X | |||
unsubscribe | pub/sub | X | X | |||
in | queue | X | X | X | ||
out | queue | X | X | X |
Invoke
Invoke is synchronous, and it simply calls a method and waits for the returned data if there is any. If any other service has subscribed to the method being called, they will be sent the data too. This is a common way to broadcast data on a topic.
For example, if a service invoked the method publishState like this
invoke("publishState")
all services which subscribed to that topic get the Service sent to them
invoke("{service name}/{method}/{param0}/{param1}/...")
invoke("{method}/{param0}/{param1}/...")
invoke({method},{param0},{param1},...)
subscibe("{service name}/{method}", "onMethod")
subscibe("{service name}/{method}")
examples - Goal would be to make the smallest communication library possible (which should be very very small) which does the basic subscribe & invoke
Messages
Messages is a message endpoint and allows the asynchronous exchange of messages through a suspended websocket connection. Typically this would be handled through a Javascript framework in the browser.
The MRL Message structure can be described in JavaScript as this :
function Message(name, method, params) { this.msgID = new Date().getTime(); this.timeStamp = this.msgID; this.name = name; this.sender = webguiName; this.sendingMethod = method; this.historyList = new Array(); this.method = method; this.data = params; }
e.g.
POST http://localhost:7777/api/messages
{"msgID":1431792202686,"timeStamp":1431792202686,"name":"runtime","sender":"webgui","sendingMethod":"","historyList":[],"method":"start","data":["arduino","Arduino"]}
will do the same as the API 1 example ie - create and start an Arduino service named "arduino". It will not get a return message since it is asynchronous. However, any service method can be subscribed too in MRL - so if the Runtime.start method was prevously subscribed to, an Arduino encoded in json message would come back.
internal representations
mrl://remote01/tcp://127.0.0.1:6767
mrl://webgui01/http://127.0.0.1:6767
// reconcile !!!
MRLComm protocol
The MRLComm is a very lightweight protocol which is used to communicate to and from an Arduino microcontroller. The same protocol could probably be used on other microcontrollers, but this has not been implemented (or only partially so for the Propeller).
We shall have a textual api to MRLComm but currently binary is only supported. There is binary to Text conversion which can be done with the protocol.
Binary Protocol
MRLComm binary protocol is
MAGIC_NUMBER|NUM_BYTES|FUNCTION|DATA0|DATA1|....|DATA(N)
If a message does not start with the MAGIC_NUMBER it is thrown away.
WebGUI
- Definitions - router, work space panel, service panel, service controller