@DefaultAnnotation({})

Package jmri.server.json

The JMRI JSON Services provide access to JMRI via JSON data objects via a RESTful interface over HTTP or via JSON messages via a socket interface over TCP or WebSockets.

Schema

The JMRI JSON protocol has two sets of schema, one for messages from clients to a JMRI server, and one for messages from a JMRI server to clients. The core schema for socket interfaces are the client schema and server schema. These schema define the structure of JSON messages in this protocol. Messages generally contain type, data, and method properties.

The data object types supported in a running JMRI instance for both RESTful and socket interfaces can be listed at http://my-jmri-server:12080/json/version/type and individual schema for each data object type at http://my-jmri-server:12080/json/version/schema/type

Methods

The JMRI JSON services accept four methods, all of which directly correspond to HTTP 1.1 methods. The socket services accept one non-HTTP 1.1 method "list" to allow the listing of objects (in the HTTP service, this is an HTTP GET). In the socket implementations, the method is specified using the "method" name in the message object with one of the following values:
"get"
Get the requested object. Absent a "method" name, this is the default method. Note to developers: this should be an idempotent method.
"post"
Modify the requested object.
"put"
Create the requested object. Note to developers: this should be an idempotent method if the requested object already exists (i.e., this request should not modify an existing object if a new object cannot be created).
"delete"
Delete the requested object. Note to developers: This should be an idempotent method if the requested object does not exist.
"list"
Used in the socket interfaces to get a list of the given type. The equivalent form in the RESTful interface is a GET request to /json/<version>/<type>.

Messages

Fundamentally, the JSON server passes messages as JSON Objects between a JMRI server and one or more clients. In the TCP Socket and WebSocket interfaces, a message from the client generally has three properties (full details are in the schema):

type
The type of object in the data property.
method
The RESTful method to be used, defaults to get if not present.
data
The JSON representation of a JMRI object; see the schema for the properties of this object, since the properties vary by type.
id
A message identity as a positive integer that will be returned unmodified to the client in any messages that are direct responses to the message containing an id. Defaults to zero if not present.

A message from the server is either a single JSON Object {"type":"type","data":{...}} except as noted below or a JSON Array of objects. In the RESTful interface, messages from the client in POST and PUT requests may contain a JSON object that corresponds to the data object in the socket interfaces.

Exceptions

Exceptions to the above form for the socket interfaces are:

Get Requests
When using a get method, specifying the method is optional.
List Requests
List requests are in the form: {"type":"type","method":"list","data":{...}} (recommended) or {"type":"list","list":"type"} or {"list":"type"} in the socket interfaces and will either cause an error to be thrown if type is not listable, or cause an array of items to be sent to the client. The data object is not required; some list requests can have additional parameters in the data object; however some services ignore that with lists.
List Responses
List responses are in the form: [message,message], an array of object message types with type and data properties. There is no guarantee that an array contains all objects of a single type, or that an array contains all of the objects of a single type, since it is, by design, possible for multiple services, including third-party services to respond to a single request, and the JSON server neither makes nor enforces any guarantees concerning how those services respond. Multiple responses are joined together when using JSON via the RESTful interface, and may or may not be joined together when using JSON in other interfaces.
Heartbeats
Heartbeat messages are sent by the client to assure the JMRI server that a socket connection is still up. A heartbeat from the client is in the form {"type":"ping"} and is answered with a {"type":"pong"} from the JMRI server.
Closing Sockets
When a socket is being closed in a non-erroneous way, the system initiating the close (either a client or server) sends a message {"type":"goodbye"} and closes its connection. The receiving system should not respond and close its connection.
Malformed JSON
When receiving a message with malformed JSON, the JMRI server will not attempt to include an id if present in the malformed message.

Note The name property of a data object must be the system name, not the user name, of the requested object (usually a NamedBean), except when creating an object using a put method and the Manager for that class of NamedBean supports creating a NamedBean using an automatically generated system name. It is generally safer to always use system names.

Versions

The running JMRI instance may support multiple major versions of the JSON protocol. A single JMRI instance will only support one major.minor.patch version of the JSON protocol (i.e. a JMRI instance may support JSON versions 5.3.1 and 6.0.2, but should not be expected to support JSON version 5.3.1 and 5.4.0). A JMRI instance that supports multiple versions of the JSON protocol will provide a JSON list of name/value pairs in response to the HTTP query http://localhost:12080/json/version. No Socket equivalent of this URL exists, since the first message (a hello message) in the socket stream specifies the version to be used. The names are the supported versions in major.minor.patch format and the values are the HTTP path component ("v" + major (i.e "v5" for version 5.3.1)) for using that version. (Web)Socket JSON clients should specify the required JSON version in the hello message or in the WebSocket URL. If a requested version is not specified, the JSON protocol 5.x.y will be used. If a JMRI instance does not support JSON protocol 5, an error will be returned if the client does not specify the JSON version to use.

Note until support for using protocol version 5 is dropped, requesting an unsupported version will result in an error with code 404 or 400. Once support for protocol version 5 is dropped all requests for an unsupported version will result in an error with code 400.

Version History

Changes to the major number represent a backwards incompatible change in the protocol, while changes to the minor number represent an addition to the protocol, and changes to patch number represent a bug fix within the protocol. The JSON protocol version is available to clients in the hello message. Within test releases between to two production releases, breaking changes only reset the major number once (for example, breaking changes in JMRI 4.15.4 to JSON protocol version 4.1 followed by breaking changes to 5.0.0 in 4.15.6 will result in JMRI release 4.16 including JSON protocol version 5.0.0, not 6.0.0, since 4.15.4 and 4.15.6 are both between JMRI production releases 4.14 and 4.16).

Starting with 5.0.0, the JSON protocol version follows semantic version rules, prior to that the version is just a major.minor version.

5.4.0 (JMRI 4.19.5)
  • Allows the feedback mode and feedback sensors to be manipulated for turnouts.
5.3.0 (JMRI 4.19.2)
  • Adds /json/version RESTful API endpoint to list JSON versions supported by the running JMRI instance. This endpoint is not versioned like other endpoints.
  • Adds the version type the socket APIs to allow a client to query the protocol version currently in use on the socket over which the request was made.
  • Adds the version property to hello objects to allow a client to specify a preferred version and the server to notify the client of the version in use.
  • Allows RESTful API endpoints for version 5 to explicitly request a protocol version using /json/v#/type/... or implicitly expect the use of version 5 using /json/type/.... Versions 6 and newer will always require explicitly requiring the version in RESTful API endpoints.
5.2.0 (JMRI 4.17.7)
  • memory and block now return idTag and reporter values as json objects
  • for networkService, add userName and change name to mDNS type
  • Add configProfile.isNextProfile
  • several schema fixes
  • reporter.report now supports Reportable data
  • fix systemConnection, configProfile, panel to return single item for name
5.1.0 (JMRI 4.17.4)
  • Fixes setting the car type for operations rolling stock
  • Adds the settable property "carSubType" to include car type information that is not shown on manifests or switch lists
5.0.0 (JMRI 4.15.4 with further changes in 4.15.6)
  • Adds the ability for a client to specify a message ID that will be included in messages returned in direct response to the identified message
  • Adds a framework for allowing a client to delete objects and handle conflicts (mostly object is in use elsewhere types) when deleting objects
  • Adds schemas that define valid JSON message for all types except consists; #5002 is being used to track progress on allowing schema validation at all times.

Introduces backwards-incompatible changes of:

  • Respecting the requirement that a JSON message object from the client include a method name to not be treated as a "get" introduced in version 4.1.
  • Removes code that creates listeners for objects not requested by the client
  • JSON Operations objects use name instead of id to match behavior of other JSON objects.
  • JSON Throttle objects use name instead of throttle to match behavior of other JSON objects.
  • Deprecates, but does not remove, support for plural tokens for listing types, using the singular token syntax introduced in version 3.0.
4.1 (JMRI 4.11.4)
The RESTful method associated with a JSON message from the client absent a method name with a value of "get", "post", "put", or "delete" is assumed to be "get".
4.0 (JMRI 4.3.4)
Prior to version 4.0, the JSON servers had a single definition for all tokens used in JSON communications. As of version 4.0, the JSON servers use a modular protocol, fixing as constants only the tokens used for the basic protocol structure as well as some tokens used by multiple modules.
3.0 (JMRI 3.11.2)
Types no longer need be plural to list. This means that RESTful URLs can be /json/type/name for a single object and /json/type for a list of objects, and /json/types is no longer needed to list (i.e. /json/turnout/IT1 gets turnout IT1, and /json/turnout gets the list of turnouts).
2.0 (JMRI 3.9.3)
No reason for version change listed in commit history.
1.1 (JMRI 3.7.1)
No reason for version change listed in commit history.
1.0 (JMRI 3.4)
Initial release of JMRI JSON Protocol.

Notes

The JMRI JSON services are defined using JsonServiceFactory objects which may be loaded as third-party plug-ins to JMRI (see Plug-in mechanisms). Because of this the JSON server can make no guarantees concerning how the JSON services handling a specific type of object behave; specifically the following are not guaranteed:

  • An array response to a list request contains all items of the requested type.
  • An array response does not contain duplicate items of the same type with different data.
  • The message sent from a JMRI server is in response to the last message received when using sockets.
  • Requests for an object will cause a listener to be created for that object such that the client is automatically updated when the object or object state changes.
  • Requests for a list will cause a listener to be created that automatically updates the client when objects of a type are added or removed within JMRI.
  • A single service will be the only responder to a specific message.
Since:
4.3.4
See Also:
JsonServlet, JsonServer, JsonServiceFactory