-
Notifications
You must be signed in to change notification settings - Fork 0
RIM 0.3.0
The Resource Interaction Model (RIM) language allows you to quickly and easily create REST APIs for use by humans and machines.
HelloWorld.rim
rim HelloWorld { // Define the HTTP methods your intend to use and a nice name if you prefer [alias] [HTTP method] events SEE GET end // Define a set of commands available to your resources. // Generally a small set of commands will be reused for a number of resources. commands GETEntities Noop optional_configuration_props end // Define a resource that is nothing more than a link to some messages initial resource root item ROOT view { Noop } path "/" SEE -> messages end // Define a resource that will show a collection of messages resource messages collection Message view { GETEntities } end }
The RIM language uses resources and transitions to define RESTful services; this manner of defining a service is very similar to a state machine or directional graph. Resources are identified by name and all resources must be addressable from at least one other resource. To create a RESTful service, as defined by Roy Fielding, resources must conform to four Uniform Interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state. The RIM language ensures these constraints can be met at runtime by enforcing the resource naming, transition, metadata, and action semantics.
The RIM language uses the resource
nomenclature to define a container for an entity or multiple entities. e.g. the example resource below represents a collection
of Message entities.
resource messages collection Message view { GETHelloMessage } end
A resource
MUST be given a unique name, it MUST provide a view
command
or workflow, and it MUST represent either an item
or a collection
of an entity.
To be considered valid, a RIM definition MUST define exactly one initial resource; all other resources MUST have at least one transition from another resource.
A command
or workflow that will be executed when a safe transition to a state is issued.
resource messages collection Message view { GETHelloMessage } end
A list of command
or workflow, separated by ;
, that will be executed when an unsafe transition to a state is made.
resource messages collection Message view { GETHelloMessage } actions { GETHelloMessage; UpdateMessage } end
A list of relations that will be used in any links to this state.
resource messages collection Message view { GETHelloMessage } relations { "mylinkrelation" } end
A resource
can define one of two types of resource; they are either an item
or a collection
item
An individual.
collection
A collection of individuals.
An initial resource
is a special resource state that identifies a logical entry point to the interaction model. It MAY be used by a runtime container to understand the starting point(s) of the resource graph, a runtime container MAY only bind resources to paths when they exist in the graph from this initial
starting point.
initial resource Root item ServiceDocument view { GETServiceDocument } end
A set of resource interaction models MUST define one initial
resource
.
An exception resource
is a special resource state used to catch interaction errors for resources which do not have an onerror
handler.
exception resource AirlineException item AirlineError view { GETException } end
Transitions are mostly commonly represented as links through a given media type. They are the main way we provide state or context to our application interactions and they define how a User-Agent can interact with our service.
->
transition
Single transition.
initial resource root item ROOT actions { Noop } path "/" GET -> messages end resource messages collection Message view { GETHelloMessage } end
*->
transition
For each item transition.
-->
transition
An auto transition.
A transition from one resource
to another may be loosely defined, dynamic or transient in nature. In such cases it is necessary to define the transition linkage parameters. e.g. the flights resource in the following example uses the flightID field from the Flight entity to transition to the flight resource, where flight requires an id path parameter.
resource flights collection Flight view { GETEntities } path "/Flight" GET *-> flight id=flightID end resource flight item Flight view { GETEntity } path "/Flight({id})" end
A transition from one resource
to another may be conditional on the existence or non-existence of another resource. For example, a successful update may transition to the item
whereas an unsuccessful update may remove the resource and require a transition to the collection
. In such cases it is possible to define conditional link expressions using the OK()
and NOT_FOUND()
functions. It is possible to use these transition conditions on all types of transitions.
events GET GET UPDATE PUT end commands GetEntities properties GetEntity properties PutEntity properties end initial resource A collection ENTITY view { GetEntities } GET *-> B end resource B item ENTITY view { GetEntity } UPDATE -> B_pseudo end resource B_pseudo item ENTITY actions { PutEntity } GET --> A (NOT_FOUND(B)) GET --> B (OK(B)) end
Define/describe the semantics of a transition to a resource.
A runtime container is expected to understand at least the primitive HTTP events GET
, PUT
, POST
, DELETE
, HEAD
, and OPTIONS
. These events can be given an alias to aide understanding in a domain where HTTP is not the normal conversational way of describing an interaction.
events SEE GET REMOVE DELETE end
The onerror
keyword declares an error handler which enables resources to delegate the error handling to other resources.
resource flights collection Flight view { GETEntities } path "/Flight" GET *-> flight id=flightID onerror --> flightError end resource flightError item FlightError view { GETFlightError } end
The result of executing the view action on the error resource will be returned as the response of the current request. It may be desirable to return a link to an error details resource in case the current request should return something else such as e.g. a summary of errors.
resource flights ... onerror --> flightErrorSummary end resource flightErrorSummary item FlightErrorSummary view { GETFlightErrorSummary } GET -> flightErrors end resource flightErrors item FlightError view { GETFlightErrors } end
The additional complexity involved in this step is that a user will have to access flightErrors with a separate request. It is therefore the responsibility of the GETFlightErrorSummary command to store the errors details and GETFlightErrors to retrieve it from intermediate storage. This storage area could be the resource manager, an in-memory database or a cache.
Define a command for use in an action, view, or workflow.
The Resource Interaction Model (RIM) language provides a scoping and reuse facility to help you organise your interaction model. Once you have identified events
, commands
or resource
s that you want to isolate or reuse you can simply wrap them in a domain
and then use
your model in a number of other source files.
domain TestDomain { use Common.Global.* use ONE.* rim ONE { commands NoopGET end initial resource A collection ENTITY view { NoopGET } GET -> TestDomain.TWO.B end } rim TWO { commands NoopGET end initial resource B collection ENTITY view { NoopGET } GET -> ONE.A GET -> A end } }
The RIM language uses the domain
nomenclature to define a container for one or more rim
objects. e.g. the example domain TestDomain above defines a domain
with one resource interaction model (rim
).
A domain
MUST be given a unique name, it MUST define at least one rim
.
The RIM language uses the rim
nomenclature to define a container for one or more resource
objects. e.g. the example rim
TestDomain.TWO above defines one resource
called B.
A rim
MUST be given a unique name, it MUST define at least one events
, commands
, or resource
.
The RIM grammar in EBNF notation can be found here RIMDsl.xtext. This grammar when used with XText can provide an Eclipse based editor for the RIM language.