-
Notifications
You must be signed in to change notification settings - Fork 0
Specification
Motion: RESTful JSON interface for message services
###Abstract Motion defines a method of communication between a source of messages and services that either provide additional detail about a message or perform actions on a message.
###Copyright Notice Copyright (c) 2015 Netmail, Inc.
###1. Introduction The goal of Motion is to describe a mechanism by which any source of messages, (ie an MTA, Archive system, chat server, email client, etc) can learn more about a message and can act on a message based on what was learned. This is achieved by use of motion services.
###2. Conventions and Terminology The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [RFC2119].
The terms "JSON", "JSON text", "JSON value", "member", "element", "object", "array", "number", "string", "boolean", "true", "false", and "null" in this document are to be interpreted as defined in RFC 4627 [RFC4627].
###3. Overview
Motion provides a mechanism of communication between a message source (a Motion Consumer) and services that can act on messages to provide additional information about a message or perform an action on a message.
All communication is done via HTTP 1.1.
###4. Manifest
A Motion service is defined by a manifest that tells a consumer of the service how to talk to it, and what exactly the service provides. The manifest must follow the schema defined in section 7.1.
####4.1 Example Manifest
{
"name": "translate",
"description": "Translates a message from one language to another",
"requires": [ "subject", "body", "htmlBody" ],
"requests": [ ],
"modifies": [ "subject", "body", "htmlBody" ],
"endpoint": "http://translate.example.com/translate/"
}
####4.2 requires
A service MUST provide a list of fields that it requires in order to process a message. Each item in the list should be either the name of a top level field, or an array of names.
An example of a "requires" list for a service that requires the message body and a name and email address for each recipient:
"requires": [
"body",
[ "to", "name" ],
[ "to", "address" ]
]
####4.3 requests
A service MAY provide a list of fields that it can use but does not require. The format is identical to the "requires" list.
####4.4 modifies
A service MUST provide a list of fields that it may modify. The format is identical to the "requires" list.
Any fields in the "modifies" list MAY be included in a message response. An example of a "modifies" list for a service that returns a modified message body:
"modifies": [ "body", "htmlBody" ]
####4.5 endpoint
A service MUST provide a URL, or an array of URLs that can be used to create a configured instance of a service.
####4.6 accepts
// TODO Describe syntax for specifying a JSON schema that the service
// accepts and how to reference a JSON schema that is not defined by
// the specification.
###5. Configuration
A configured instance MUST be created before a Motion Service may be used to process messages. Each configured instance of a service represents a specific set of options that define the behavior of that service.
A service SHOULD support the creation of any number of configured instances, and is responsible for storing the configuration that is associated with a particular configured instance.
###5.1. Creation of a configured instance
Creating a configured instance is done by POSTing a document to the "endpoint" specified in the service's manifest. The document should match the schema defined in section 7.2. The document MUST include a list of fields that the consumer is willing to provide to the service for each message that it wishes to process.
If the request is accepted the service SHOULD then send a 201 response and MUST include a "Location" header that specifies the URI that represents the newly created configured instance of that service.
###5.2. Creation of a configured instance example
C:POST /translate/ HTTP/1.1
C:Content-Type: application/json
C:
C:{
C: "provides": [
C: "body", "htmlBody"
C: ]
C:}
C:
S:HTTP/1.1 201 Created
S:Location: /translate/options/a1e9
###5.3. Managing a configured instance
A configured instance may be used for message processing as soon as it has been created, but in most cases the service will wish to provide the ability to change options for the configured instance first.
A service SHOULD return an HTML page in response to a GET request that displays and allows configuration of the configured instance. The mechanisms for how the configuration is displayed, saved and stored is the responsibility of the service and should not be exposed to the consumer.
###6. Message processing
A consumer may POST a JSON document to the URI of a configured instance of a service to request that the service processes that message. If the service is able to process the message successfully then it MUST send a 200 response, with a body containing any fields that it wishes to modify.
If the message can not be processed then the service should send an appropriate HTTP response. If a 301 or 302 response is received then the consumer MUST NOT change the method when sending the request to the new location.
A consumer of Motion services MUST NOT send any fields that the service did not request in the "requires" or "requests" fields of it's manifest.
###6.1 Message processing example
C:POST /translate/options/a1e9 HTTP/1.1
C:Content-Type: application/json
C:
C:{
C: "subject": "Bonjour!",
c: "body": "j'oblie tout",
C: "htmlBody": "<html><body>j'oblie tout</body></html>"
C:}
C:
S:HTTP/1.1 200 Ok
S:Content-Type: application/json
S:
S:{
S: "subject": "Hello",
S: "body": "I forgot everything",
S: "htmlBody": "<html><body>I forgot everything</body></html>"
S:}
###7. Schema
####7.1. #/manifest
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of the service"
},
"description": {
"type": "string",
"description": "Quick description of the service"
},
"requests": {
"type": "array",
"description": "Message properties the service uses as input",
"items": {
"type": "string"
}
},
"requires": {
"type": "array",
"description": "Message properties the service NEEDS as input",
"items": {
"type": "string"
}
},
"modifies": {
"type": "array",
"description": "Message properties the service may modify",
"items": {
"type": "string"
}
},
"endpoint": {
"type": "string",
"format": "uri",
"description": "URI of the service; message data is POSTed here"
}
},
"required": [
"name",
"description",
"examines",
"modifies",
"endpoint"
]
}
####7.2. Configuration registration
####7.2. Message
####7.2.1. #/message
The default accepted type for a Motion service is "#/message". This type attempts to include all commonly required fields for most types of messages. No fields are required, so a subset of this type may be used to match the data provided by the message source.
// TODO This is currently incomplete. Add missing fields
// TODO Document each field
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"from": {
"$ref": "#/message/address"
},
"to":{
"type": [ "array", "null" ],
"items": {
"$ref": "#/message/address"
}
},
"subject": { "type": "string" },
"date": { "type": "string", "format": "date-time" },
"body": { "type": [ "string", "null" ] },
"htmlBody": { "type": [ "string", "null" ] },
"attachments": {
"type": [ "array", "null" ],
"items": "#/message/attachment"
}
}
}
#####7.2.1.1. #/message/address
A #/message/address object is used to represent a sender or recipient of a message.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": object",
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"id": {
"type": "string"
}
}
}
#####7.2.1.2. #/message/attachment
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": object",
"properties": {
"id": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"type": {
"type": "string"
},
"name": {
"type": "string"
},
"size": {
"type": "integer"
},
"width": {
"type": "integer"
},
"height": {
"type": "integer"
},
"attachments": {
"type": [ "array", "null" ],
"items": "#/message/attachment"
}
}
}
####7.2.2. #/email
Services that wish to support email specific fields such as headers or the source should accept "#/email" rather than "#/message".
// TODO This is currently incomplete. Add missing fields
// TODO Document each field
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"allOf": [
{ "$ref": "#/message" },
{
"properties": {
"header": {
"type": [ "array", "null" ],
"items": { "$ref": "#/email/header" }
},
"source": {
"$ref": "#/email/attachment"
},
"attachments": {
"type": [ "object", "null" ],
"$ref": "#/email/attachment"
}
}
}
]
}
#####7.2.2.1. #/email/header
#####7.2.2.2. #/email/attachment
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"allOf": [
{ "$ref": "#/message/attachment" },
{
"properties": {
"header": {
"type": [ "array", "null" ],
"items": { "$ref": "#/email/header" }
},
"offset": {
"type": "integer"
}
}
}
]
}
####7.2.3. #/email submission