The RBR (RedBaRell) Language is a syntax used to describe web services.
It’s organized into:
RBR is organized into definitions containing variables or operations, and global definitions.
The general syntax is:
global name "value"; type binary python:Binary; meta ( title "this", version 1.0, description "That" ); path somepath ( method GET, url /, use python:somecode, );
Every section or global ends with a semi-colon, and every definitin is separated by a comma.
There’s a special unique meta section that’s used to define a few metadata:
meta ( title "this", version 1.0, description "That" );
In sections, for some variables, you can define multiple elements:
path Foo ( variable1 ( field1 value1, operation, field2 value2 ) );
Here’s a full example of a valid RBR file that defines an API to shorten URLs:
meta ( description """An URL Shortener""", version 1.0 ); path shorten ( description "Shortens an URL", method POST, url /shorten, request-body ( description "Contains the URL to shorten" ), response-body ( description "The shortened URL" ), response-headers ( set Content-Type "text/plain" ), response-status ( describe 200 "Success", describe 400 "I don't like the URL provided" ), use python:shortme.shorten.shorten );
RBR recognizes these types:
Paths are described using the Routes syntax (see XXX), and always start with /.
XXX more on paths.
Every location is suffixed with a type. Right now RBR recognizes:
Every path definition can contain these variables:
The meta section can contain:
|||(1, 2, 3, 4, 5, 6, 7) Single value|
|||(1, 2, 3, 4, 5, 6) Multiple values in a subsection. Subsections can contain a description, some variables and some operations.|
|||(1, 2, 3) Mandatory|
Every section can contain extra custom fields, as long as they are suffixed by x- so they don’t conflict with a future version of the RBR DSL. Examples: x-author, x-request-max-size, etc. The reference implementation is not interpreting those fields, but they are loaded in the AST.
Each section can contain one or several operations. Operations can be used to:
You can check a request or response header or body, using one of these expressions:
The first form can be used to validate a body. For example, to check that the request body is json and return 400 if not, you can write:
request-body ( unless type is json return 400 )
The second form is to be used for headers:
request-headers ( unless X-Back-Off is int return 400 )
RBR provides a very few pre-defined types for these operations:
But you can define your own types. See Defining custom types.
The last form can be used to call some custom function. Basic authentication example:
request-headers ( unless Authorization validates with python:auth return 401 )
Will return a 401 unless auth() returns True.
You can alter the value of a header or body using alter with code, where code() is a callable that will get the value to alter, and return the result.
For example, if you want to return a compressed version of a response that contains a CSS stylesheet, you can write:
response-body ( alter with python:somemodule.compress_css )
Where compress_css() is a function that returns a compressed version of the body.
You can directly set a header, using set header value. For instance, if you want to set the Content-Type of a response to “text/css”:
response-headers ( set content-type "text/css" )
describe code text will let you describe every status code for the response.
response-status ( describe 200 "Success", describe 400 "The request is probably malformed", describe 401 "Authentication failure" )
As explained earlier, every section and subsection in the DSL file can contain a description. Descriptions are useful to document the web services:
path capitalize ( description "A web service with several post/pre processing", ... request-body ( description "Send a string in json and the server returns it Capitalized.", ), response-body ( description "The string, Capitalized !", ) );
RBR provides a very few pre-defined types for check operations:
To define a new type, you can use a type name value definition, where name is the name of the type and value a code location.
The code location is instanciated, then invoked everytime a type needs to be chacked. It receives the value and must return True or False.
type blob python:Blob;
class Blob: def __call__(self, value): return value.startswith('blob:')
The meta section allows you to define a title, a description and a version for your application.
meta ( title "RedBarrel Application", version 1.1, description """ This is a RedBarrel App ! """ );
Requests to a given url can be proxied to another server.
path shorten ( description "Shortens an URL", method POST, url /shorten, request-body ( description "Contains the URL to shorten" ), response-body ( description "The shortened URL" ), response-headers ( set Content-Type "text/plain" ), response-status ( describe 200 "Success", describe 400 "I don't like the URL provided" ), use proxy:http://localhost:5000 );
The request and response can be checked as usual, and the request is eventually proxied to http://localhost:5000 then the response returned.
This is useful if you want to use another server to build the response for a given service.