Skip to content
logoBack to home screen

REST API - DDSA Service Evaluation

You can execute DDSA Service Requests via the /api/v1 endpoint.

Overview

Supported MethodDescription
GETUsed for simple DDSA service requests. All properties are encoded in the URL parameters or as custom (so starting with gm-) headers. The properties must be of type String, int, float, long, double, boolean, Date, decimal, enum or a list or set of the mentioned types.
POSTUsed for more complex DDSA service requests. All types are supported. The service request can either be provided as form data or encoded in the body of the request, with the mimeType provided in the Content-Type header.
PATCHUsed in the same manner as POST.

Every service request call is unmarshalled into the following entities:

  • the actual call
  • the endpoint, which contains multiple properties that drive the behavior of the endpoint, independently of the actual service requests you want execute.

The properties of the ServiceRequest may be prefixed with service and properties of the Endpoint entity may be prefixed with endpoint.

If no prefix is provided, we'll try to find the property in the service request first, then in the endpoint. If the property doesn't exist anywhere, we'll send a 400: Bad request error with an error message.

For more information, see REST Parameters and Headers.

Service Domain

A service domain serves a similar purpose as a namespace, in the sense that it groups certain elements according to some arbitrary criteria. In our context, the elements are service requests and the criterion has to do with the where the service is evaluated.

The idea is that you can have the same request handled in different ways in different domains. Another reason is that you want to keep unrelated things separated, so only requests that logically belong together can be found in the same service domain.

An instance of the ServiceDomain type you create manually must have a service model assigned. After all, service domains group service requests and those come from service models. Depending on the implementation and logic of the service processors used in service requests of a service model, service requests grouped in one service domain can optionally have their results persisted. Moreover, a service model can depend on one or more other service models that represent specific business models for a wide range of concrete operational needs.

A standard access is also a service domain, as it groups the entire functionality of what you can do with the entities of its assigned metamodel within the access. Note that your access does not have to have a service model to be considered a service domain. Out-of-the-box, you can use CRUD operations on the entities assigned to the metamodel of an access as CRUD operations are automatically exposed as REST API when deploy an access that has a metamodel assigned.

The serviceDomain part of the URL is necessary for every API call, as it specifies where the service is located, which is usually an access. You can, however, have a service domain which is not an access.

You can create a new service domain in Control Center by looking up ServiceDomain using the Quick Access bar and creating a new instance.

Service domain is a parameter which must be specified in the path of every service request REST call. If you don't specify it, you will send your call to the default domain.

Overriding Service Domain

You can override the service domain by passing a serviceDomain parameter in the URL of the call or by providing a domainId in the body of the call. This is useful when you want to run a service request from one domain on another one. The best example for this is the GMQL REST call.

The GMQL REST call is a part of the default serviceDomain:default service domain. If you want to run a GMQL query on another domain (access), you must override the service domain by adding serviceDomain=yourServiceDomain to the URL or by adding domainId="yourServiceAccess" to the body, for example, calling host:port/tribefire-services/api/v1/gmql?statement=from%20com.braintribe.model.generic.GenericEntity&domainId=myCustomAccess will send the GMQL query from com.braintribe.model.generic.GenericEntity to the access with the external ID myCustomAccess.

Simple Name Resolution

If your service request has a simple name that is unique within a given service domain, then instead of using the /api/v1/serviceDomain/foo.bar.ExampleServiceRequest notation you can just use /api/v1/serviceDomain/ExampleServiceRequest. If the simple name is not unique and you try to use the /api/v1/serviceDomain/ExampleServiceRequest notation, you will get an exception.

Authentication

Send a POST call to /api/v1/authenticate for authentication. Make sure to provide your credentials in the body of the request:

ItemDescription
Method and LinkPOST host:port/tribefire-services/api/v1/authenticate
Body{ "user": "cortex", "password": "cortex" }
HeadersContent-Type: application/json

You have to include the session ID in every REST call. You can include it in the following:

  • URL parameter: sessionId=yourSessionId
  • header parameter: gm-session-id

You cannot include the session ID in the body of the request!

If you are not logged in (there is no valid session) and you paste a GET call in your browser, you will be redirected to a login screen. After logging in, you will see the result of your GET call.

The redirect does not happen for the /api/v1/authenticate call.

Endpoint Configuration

You can configure the behavior of the REST endpoint by assigning desired values to available parameters:

Write Empty Properties

ParameterDescription
URL Parameterwrite-empty-properties=<...>
Header Parametergm-write-empty-properties=<...>
TypeBoolean
Default Valuefalse
DescriptionWhen this flag is set to true, the marshaller returns all properties that are set to null or are empty (for maps, sets and lists)

Stabilize Order

ParameterDescription
URL Parameterstabilize-order=<...>
Header Parametergm-stabilize-order=<...>
TypeBoolean
Default Valuefalse
DescriptionWhen this flag is set to true, the marshaller ensures that properties in different instances of the same entity are always in the same order. This is especially useful when you return empty properties using the writeEmptyProperties parameter.

Prettiness

ParameterDescription
URL Parameterprettiness=<...>
Header Parametergm-prettiness=<...>
Typenone, low, mid or high
Default Valuemid
DescriptionThis property represents the level of prettiness used when writing the assembly back to the body of the response.
Each implementation of the marshaller may use this value slightly differently, but as a rule of thumb, none contains no new lines or indentation information and should only be used to minimise the size of the body and high provides the best possible indentation for humans to read.

Projection

ParameterDescription
URL Parameterprojection=<...>
Header Parametergm-projection=<...>
TypeString
Default Valuenull
DescriptionWhen the response to a call is a GenericEntity (i.e. in most of the cases), this value represents the path of properties to be returned from the response.

In this example, the following REST call: /api/v1/serviceDomain/foo.bar.ExampleServiceRequest returns the following answer (encoded as JSON) without projection:

{
  "_type": "foo.bar.ExampleServiceResponse",
  "exampleProperty": {
    "_type": "foo.bar.ExampleEntity",
    "anotherProperty": {
      "_type": "foo.bar.AnotherEntity",
      "stringValue": "Welcome to tribefire documentation!"
    }
  },
  "intValue": 42,
  "someList": [0, 1, 5]
}

The following are different values returned for various projections:

  • projection=intValue
42
  • projection=exampleProperty
{
   "_type": "foo.bar.ExampleEntity",
   "anotherProperty": {
      "_type": "foo.bar.AnotherEntity",
      "stringValue": "Welcome to tribefire documentation!"
   }
}
  • projection=exampleProperty.anotherProperty.stringValue
"Welcome to tribefire documentation!"

The following projections are not supported:

  • projection=_type: the projection should be a list of property names separated by . and _type is not a property, but an internal value added by tribefire used when unmarshalling a JSON
  • projection=someList.0: it is not possible to reference values inside of collections

Depth

ParameterDescription
URL Parameterdepth=<...>
Header Parametergm-depth=<...>
Typeshallow - returns only the first level
reachable - returns the whole assembly
number >= 0 - returns the provided level, starting at 0
Default Value3
DescriptionFor complex assemblies, this property specifies how deep the returned assembly should be traversed before being returned. This property is a simplified TraversingCriterion.

The depth parameter is applied after the projection parameter.

In this example, the following REST call: /api/v1/serviceDomain/foo.bar.ExampleServiceRequest returns the following answer (encoded as JSON, with writeEmptyProperties=true) without the projection parameter set:

{
  "_type": "foo.bar.ExampleServiceResponse",
  "a": {
    "_type": "foo.bar.EntityA",
    "b": {
      "_type": "foo.bar.EntityB",
      "c": {
        "_type": "foo.bar.EntityC",
        "d": {
          "_type": "foo.bar.EntityD",
          "e": "We need to go deeper."
        }
      }
    }
  }
}

The following are different values returned for various depths:

  • depth=shallow: only returns the first level
  • depth=0: only returns the first level
{
  "_type": "foo.bar.ExampleServiceResponse",
  "a": null
}
  • depth=2: returns the 3 first levels (zero-indexing)
{
  "_type": "foo.bar.ExampleServiceResponse",
  "a": {
    "_type": "foo.bar.EntityA",
    "b": {
      "_type": "foo.bar.EntityB",
      "c": null
    }
  }
}
  • depth=reachable: returns the entire assembly
  • depth=327: any number bigger than the maximum depth returns the entire assembly
{
  "_type": "foo.bar.ExampleServiceResponse",
  "a": {
    "_type": "foo.bar.EntityA",
    "b": {
      "_type": "foo.bar.EntityB",
      "c": {
        "_type": "foo.bar.EntityC",
        "d": {
          "_type": "foo.bar.EntityD",
          "e": "We need to go deeper."
        }
      }
    }
  }
  • depth=1&projection=a.b: starting from foo.bar.EntityB, returns 2 levels (starting at 0...)
{
  "_type": "foo.bar.EntityB",
  "c": {
    "_type": "foo.bar.EntityC",
    "d": null
  }
}

Entity Recurrence Depth

ParameterDescription
URL Parameterentity-recurrence-depth=<...>
Header Parametergm-entity-recurrence-depth=<...>
Typenumber >= -1 - returns the provided level, starting at 0
Default Value0
DescriptionFor complex entities which have recurrent entities (entities that appear more than once in the returned JSON), this property specifies how deep the returned recurrent entity should be traversed before being returned. This property is used to avoid _id and _ref in the returned JSON.

The entity-recurrence-depth parameter is applied after the depth parameter.

In this example, the following REST call: /api/v1/serviceDomain/foo.bar.ExampleServiceRequest without the projection parameter set returns the following answer (encoded as JSON, with write-empty-properties=true) :

{
  "_type": "foo.bar.ExampleServiceResponse", "_id": "0",
  "a": {
    "_type": "foo.bar.EntityA", "_id": "1",
    "b": {
      "_type": "foo.bar.EntityB", "_id": "2",
      "name": "name_of_entity_B",
      "c": {
        "_type": "foo.bar.EntityC", "_id": "3",
        "d": {
          "_ref": "2"
        }
      }
    }
  }
}

Note there are different values returned for various settings of entity-recurrence-depth:

  • entity-recurrence-depth=0: returns marshalled JSON with _id and _ref
{
  "_type": "foo.bar.ExampleServiceResponse", "_id": "0",
  "a": {
    "_type": "foo.bar.EntityA", "_id": "1",
    "b": {
      "_type": "foo.bar.EntityB", "_id": "2",
      "name": "name_of_entity_B",
      "c": {
        "_type": "foo.bar.EntityC", "_id": "3",
        "d": {
          "_ref": "2"
        }
      }
    }
  }
}
  • entity-recurrence-depth=1: only returns first level (scalar values) for the recurrent entity
{
  "_type": "foo.bar.ExampleServiceResponse",
  "a": {
    "_type": "foo.bar.EntityA", "_id": "1",
    "b": {
      "_type": "foo.bar.EntityB", "_id": "2",
      "name": "name_of_entity_B",
      "c": {
        "_type": "foo.bar.EntityC", "_id": "3",
        "d": {
          "_type": "foo.bar.EntityB",
          "name": "name_of_entity_B"
        }
      }
    }
  }
}
  • entity-recurrence-depth=-1: returns the entire recurrent entity (an entity that appears more than once in the returned JSON), if cyclic dependency is detected it will only return scalar values for that entity.

Write Absence Information

ParameterDescription
URL Parameterwrite-absence-information=<...>
Header Parametergm-write-absence-information=<...>
TypeBoolean
Default Valuefalse
DescriptionWhen this Boolean flag is set to true, the marshaller writes information for all absent properties.

Type Explicitness

ParameterDescription
URL Parametertype-explicitness=<...>
Header Parametergm-type-explicitness=<...>
Typeauto, always, entities or polymorphic
Default Valueauto
DescriptionThis property is used to decide whether _type is present in marshalled JSON.

This property is only available in JSON marshaller.

auto - _type is always returned for entity types and properties that are not known simple types (String, integer, etc).
always - _type is always returned for every element
entities - _type is always returned for entity types and properties that are not known simple types (String, integer, etc).
polymorphic - _type is returned for every element if the actual type cannot be established from the context

Identity Management Mode

ParameterDescription
URL Parameteridentity-management-mode=<...>
Header Parametergm-identity-management-mode=<...>
Typeoff, auto, _id or id
Default Valueauto
DescriptionRepresents how duplicates of objects should be unmarshalled.

auto - Depending on the parsed assembly, the marshaller automatically detects the identification information and uses it for identity management.
off - No identity management.
_id - The internally generated _id information is used, if available.
id - The id property is used, if available.

Download Resource

ParameterDescription
URL Parameterdownload-resource=<...>
Header Parametergm-download-resource=<...>
TypeBoolean
Default Valuefalse
DescriptionWhen set to true, the result of the request is not the JSON representation of the Resource but the binary data itself.

Save Locally

ParameterDescription
URL Parametersave-locally=<...>
Header Parametergm-save-locally=<...>
TypeBoolean
Default Valuefalse
DescriptionWhen set to true, the Resource being handled by the request is not displayed in the browser (if the Resource is of type understood by the browser) but is downloaded (the contentDisposition header changes from inline to attachment). For more information about this header, see developer.mozilla.org.

Response Filename

ParameterDescription
URL Parameterresponse-filename=<...>
Header Parametergm-response-filename=<...>
TypeString
Default Valuen/a
DescriptionRepresents the filename of the file downloaded (changes the value of the filename property of the contentDisposition header). For more information about this header, see developer.mozilla.org.

Response Content Type

ParameterDescription
URL Parameterresponse-content-type=<...>
Header Parametergm-response-content=type=<...>
TypeMIME Type String
Default Valuen/a
DescriptionSets the MIME type of the content.

GET

The GET service request call URL is formed according to the following pattern: /api/v1/serviceDomain/type.signature.of.ServiceRequest

You can use the URL and the header parameters to populate the ServiceRequest and the Endpoint entities.

The GET method does not support passing in a body, therefore all the properties of the ServiceRequest as well as Endpoint entities must be fully set from the URL and header parameters. You can work with all property types, but some of them will require using an alias first - see Complex Request Properties.

Examples:

Method: GET

URL: http://localhost:8080/tribefire-services/api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser?sessionId=session-id Headers:

  • Accept: application/json
  • Content-Type: application/json

Response:

{
  "_type": "com.braintribe.model.user.User",
  "id": "some-id",
  "firstName": "cortex",
  "lastName": "cortex"
}

Here are several examples of the same call which returns the current user session from a sessionId but written in different forms:

  • All parameters in URL, without prefix

    URL: /api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser?sessionId=xxx&prettiness=high
    Headers:

    • Accept: application/json
  • All parameters in URL, with prefix

    URL: /api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser?service.sessionId=xxx&endpoint.prettiness=high
    Headers:

    • Accept: application/json
  • All parameters in headers, without prefix

    URL: /api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser Headers:

  • Accept: application/json

  • gm-session-id: xxx

  • gm-prettiness: high

  • All parameters in headers, with prefix:

    URL: /api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser
    Headers:

    • Accept: application/json
    • gm-service.session-id: xxx
    • gm-endpoint.prettiness: high
  • Parameters mixed between headers and URL parameters, without prefix:

URL: /api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser?sessionId=xxx
Headers:

  • Accept: application/json
  • gm-prettiness: high

Complex Request Properties

Above you learned about how to set simple request properties. However, if you want set values on complex property types in your request (such as entities, maps, collections of entities, properties of the object type), you will need to use an alias.

Let's imagine a GET request to find movies:

FindMoviesRequest which returns a response of Type List<Movie>.

Our request has the following properties (indention indicates properties set on other properties (sub-properties); the type of a property follows behind its name):

- name (String)
- director (Entity Director)
 - name (String)
 - country (String)
 - awardsWon (Entity AwardsWon)
   - institution (Entity Institution)
     - name (String)
   - name (String)
- category (List<CategoryEnum>) (CategoryEnum's constants: Horror, Romance, Thriller, Comedy)
- additional (Map<String,String>)
  [Example:
    key: wonOscar
    value: true]

Example 1 - Simple Entities

As first example, let's try to find all movies of Austrian directors.

Let director property have the alias d. This is expressed using the following syntax: director=@d, which we will use to set the sub-properties of the director request property. In our example it's the country:

@d.country=Austria

Note that you couldn't just say director.country=Austria, because that would mean that director is expected to be an alias which must have been introduced by you first - as demonstrated in the previous paragraph.

On the right side of the equal sign, the same rules apply as if it would be a "normal" request property. In this example: Because the Director's country property is of type String, the property can be set directly, as demonstrated.

The final URL then looks as follows:

findMovies?director=@d&d.country=Austria

Example 2 - Deeply Nested Entities

Now, we will try to set the name of the award won by the director to oscar. In this situation, name is a property of awardsWon, and awardsWon is a property of director:

- director (Entity Director)
 - name (String)
 - country (String)
 - awardsWon (Entity AwardsWon)
   - institution (Entity Institution)
     - name (String)
   - name (String)

First, we need to set an alias for director:

director=@d

Then, we need another alias for awardsWon:

@d.awardsWon=@a

Only now can we reach name:

a.name=oscar

Combining the above into a single request, we get:

findMovies?director=@d&d.awardsWon=@a&a.name=oscar

Example 3 - Collections

Let's try to set the movie category to romance and horror (who doesn't enjoy some sparkling vampires every now and then).

Now, we can assign enum values in our request:

category=horror&category=romance

Combining the above into a single request, we get:

findMovies?category=horror&category=romance

Example 4 - Maps

The property additional has the type map. We use an alias a to add another entry to the map. Note that the alias does not refer to the map but to a map entry: additional=@a.

We can set the key and value of the entry as follows:

a.key=wonOscar&a.value=true

The final request would then be:

findMovies?additional=@a&a.key=wonOscar&a.value=true

Example 5 - Sub-types of Entities

Thanks to the alias feature, you can assign values having a different type than the original property, provided it's a sub-type.

Consider a person property having the com.braintribe.Person type. Let's assume we want to assign a value of a different type, for example com.braintribe.ExtendedPerson.

First, we need to assign a type signature to the alias:

@p=com.braintribe.ExtendedPerson

Without the above, you could only assign values of the original type of the person property (com.braintribe.Person)

Now, we can assign the alias to the property having the supertype com.braintribe.Person.

person=@p

Note that order is important here. If we did the above operation first, we would already assign the type of Person (com.braintribe.Person) to the alias @p, which is not our goal.

Finally, we can assign the property itself:

p.extendedName=Thomas

As a result, the request looks as follows:

requestName?@p=com.braintribe.ExtendedPerson&person=@p&p.extendedName=Thomas

Example 6 - Object-type Properties

If necessary, it's possible to assign values to properties of the object type in your GET request. The below examples show the basic principles on how to do it:

Simple assignment

To assign a value (an integer in this case), use the below syntax:

objectProperty=11

The whole request would then be requestName?objectProperty=11.

Naturally, you can assign other types as well:

Data typeSyntax
integerobjectProperty=11
stringobjectProperty='11' (in quotes due to type ambiguity)
longobjectProperty=11L
doubleobjectProperty=11.234D
floatobjectProperty=11.234F
stringobjectProperty=Grzegorz (no type ambiguity hence no quotes)
booleanobjectProperty=true
enumobjectProperty=com.braintribe.ManyValuesEnum.VALUE_007
Advanced example - assigning an entity:

Let's assume we want to assign a value to the name property of the com.braintribe.Person entity, which, in turn, will be assigned to a property of the type object.

First, we need to assign an alias to the com.braintribe.Person entity.

@p=com.braintribe.Person

Now, we can assign the entity to the object property using the alias:

objectProperty=@p

Finally, we can assign the name property itself:

p.name=Joe

As a result, the request looks as follows:

requestName?@p=com.braintribe.Person&objectProperty=@p&p.name=Joe

POST, PATCH, and PUT

There are two ways of sending POST, PATCH, and PUT service request calls:

As Form Data

Tribefire supports special handling for requests that have the multipart/form-data or application/x-www-form-urlencoded format which are typically sent from native HTML browser forms. The multipart/form-data format is also the only way to send binary data (i.e. files) together with the REST request. This solution makes it easy to create HTML pages that can trigger a given service request.

Examples

  • Simple request: authentication
<form action="/tribefire-services/api/v1/authenticate">
  User: 
  <input type="text" name="user">
  Password:
  <input type="password" name="password">
  <input type="submit" value="Submit">
</form>

This will perform an authentication call and return the userId as a String and open it in the same tab in the browser.

  • Complex request: updating the image of a user

Imagine a request UpdateAvatarRequest that calls the UpdateAvatarProcessor which updates the avatar image of a user. The request has two properties:

  • userName of type String
  • image of type Resource
<form action="/tribefire-services/api/v1/updateAvatar">
  User: 
  <input type="text" name="userName">
  Image:
  <input type="file" name="image">
  <input type="submit" value="Submit">
</form>

On server side this will result in an UpdateAvatarRequest where the userName is set to the value of the input field and the resource at the image property contains the binary data of the file uploaded via the form element with the same name.

Note that you can still send endpoint parameters via the form action URL:

<form action="/tribefire-services/api/v1/updateAvatar?prettyness=high&depth=1">
  User: 
  <input type="text" name="userName">
  Image:
  <input type="file" name="image">
  <input type="submit" value="Submit">
</form>

As Simple Body

You can also choose to submit your service request in the body of the REST call. The ServiceRequest is then unmarshalled from the body, in the mimeType specified in the Content-Type header.

Since only the Endpoint entity is specified in the URL/header parameter, there is no need for a prefix here, however you can use the endpoint. prefix for clarity if you want.

Since the type of the ServiceRequest may be contained in the body, it is not necessary to pass it in the URL. However, the following URLs are still valid:

  • /api/v1/serviceDomain/type.signature.of.ServiceRequest: If there is also a type signature in the body, it is used instead of the type signature from the URL
  • /api/v1/serviceDomain/: If there is no type signature in the body, a 400: Bad requestis thrown.

Examples:

Method: POST

URL: http://localhost:8080/tribefire-services/api/v1/cortex/com.braintribe.model.securityservice.GetCurrentUser Headers:

  • Accept: application/json
  • Content-Type: application/json
  • gm-session-id: someId

Body:

{
  "domainId": "cortex" 
}

Response:

{
  "_type": "com.braintribe.model.user.User",
  "id": "some-id",
  "firstName": "cortex",
  "lastName": "cortex"
}

Here are several examples of the same call which returns the current user session from a sessionId but written in different forms:

  • ServiceRequest type in URL, endpoint parameters in URL

URL: /api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser?prettiness=high&sessionId=someId
Headers:

  • Accept: application/json
  • Content-Type: application/json

Body:

{
  
}
  • ServiceRequest type in URL, endpoint parameters in headers

URL: /api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser?sessionId=someId
Headers:

  • Accept: application/json
  • Content-Type: application/json
  • gm-prettiness: high

Body:

{
  
}
  • ServiceRequest type in body, endpoint parameters in URL

URL: /api/v1/serviceDomain?prettiness=high&sessionId=someId
Headers:

  • Accept: application/json
  • Content-Type: application/json

Body:

{
  "_type": "com.braintribe.model.securityservice.GetCurrentUser"
}
  • ServiceRequest type in body, endpoint parameters in headers

URL: /api/v1/serviceDomain/com.braintribe.model.securityservice.GetCurrentUser
Headers:

  • Accept: application/json
  • Content-Type: application/json
  • gm-prettiness: high
  • gm-session-id: someId

Body:

{
  "_type": "com.braintribe.model.securityservice.GetCurrentUser"

}

Mapping Customization

By default, any foo.bar.ServiceRequest in tribefire may be invoked via REST with the method GET or POST and URL /api/v1/serviceDomain/foo.bar.ServiceRequest.

However, it is possible to configure custom mappings for any request via the singleton com.braintribe.model.ddra.DdraConfiguration entity in the cortex access.

For every parameter, you can define its default value. For example, entityRecurrenceDepth is the parameter supported on the REST endpoint and with defaultEntityRecurrenceDepth you can define the default (as the name suggests) for that parameter.

Much like the facade design pattern, customizing your mapping allows you to decouple the REST endpoint where a functionality is exposed from the service request that carries out the functionality. Consider the /gmql request for example. The functionality is exposed under the /tribefire-services/api/v1/gmql endpoint, but the actual service request is com.braintribe.model.accessapi.GmqlRequest. This way, if the request ever changes, the exposed endpoint will remain the same.

DdraConfiguration has a set of com.braintribe.model.ddra.DdraMapping that influence the behavior of a single mapping. DdraMapping has the following properties:

  • method

    This property defines which HTTP method the service request is accessible with.

    Type | com.braintribe.model.ddra.DdraUrlMethod Enumeration Possible Values | GET, POST, PUT, DELETE, GET_POST (exposed as both GET and POST) Default Value | GET_POST Mandatory | no

  • path

    This property defines under which URL the service request is accessible.

    Type | String Possible Values | any, but must start with / Mandatory | yes

    Supported features:

    • you can map different service requests under the same URL and different method (you can use this to simulate CRUD APIs to a certain extend)
    • paths with multiple / are supported

    Not supported functionality:

    • dynamic or conditional paths are not supported, for example /my-entity/<id> where ID would be filled in from the URL
    • paths with variable length are not supported, for example /my-path/* where any path starting with /my-path would match
    Path ValueAccessible Under
    path=/my-requesttribefire-host/tribefire-services/api/v1/serviceDomain/my-request
    path=/my-services/service1tribefire-host/tribefire-services/api/v1/serviceDomain/my-services/service1
    path=/my-services/service2tribefire-host/tribefire-services/api/v1/serviceDomain/my-services/service2
    method=GET path=/my-crud-apiGET:tribefire-host/tribefire-services/api/v1/serviceDomain/my-crud-api
    method=POST path=/my-crud-apiPOST:tribefire-host/tribefire-services/api/v1/serviceDomain/my-crud-api
    method=PUT path=/my-crud-apiPUT:tribefire-host/tribefire-services/api/v1/serviceDomain/my-crud-api
    method=DELETE path=/my-crud-apiDELETE:tribefire-host/tribefire-services/api/v1/serviceDomain/my-crud-api
  • requestType

    This value contains the GmEntityType of the request that should be created and executed.

    ParameterDescription
    TypeGmEntityType, must correspond to a subtype of ServiceRequest
    MandatoryNo
  • transformRequest

    This value contains an instance of ServiceRequest (as opposed to a type in requestType) that should be evaluated for this path. Note that this instance is not filled from the URL parameters, headers or the body, it is executed as is.

    If the transformRequest is an instance of com.braintribe.model.service.api.HasServiceRequest and requestType is defined, then an instance of type requestType is created from the parameters or body and assigned to the serviceRequest property.

    The idea here is to be able apply preprocessing or postprocessing to multiple REST endpoints and to decouple it from the endpoint implementation.

    ParameterDescription
    TypeServiceRequest
    Mandatoryno
  • defaultProjection

    This value contains the default projection to use for this REST call.

    ParameterDescription
    TypeString
    Mandatoryno

For more information on projection, see Projection.

  • defaultDepth

    A simplified TraversingCriterion. For complex assemblies, it dictates how deep the returned assembly should be.

    ParameterDescription
    Typecom.braintribe.model.processing.ddra.endpoints.model.DdraEndpointDepthKind Enumeration
    Possible Valuesshallow, reachable, custom (number >= 0).
    Default Value0
    Mandatoryno
  • defaultEntityRecurrenceDepth

    A integer value. For complex recurrence of entities, it dictates how deep returned recurrence assembly should be. In case of 0 it will use _id and _ref in result. If -1 is used it will traverse recurrence tree indefinitely.

    ParameterDescription
    TypeInteger
    Possible Valuesnumber >= -1
    Default Value0
    Mandatoryno
  • defaultMimeType Identifies default content format used for operations against content transmitted.

    ParameterDescription
    TypeString
    Possible Valuesapplication/xml, application/json, application/gm, text/xml, text/x-json, gm/xml, gm/bin, gm/json, gm/jseh, gm/jse, gm/man, gm/deprecated-json
    Default Valueapplication/json
    Mandatoryno
  • defaultPrettiness

    Represents the level of prettiness to be used when writing the assembly back to the body of the response.

    ParameterDescription
    Typecom.braintribe.codec.marshaller.api.OutputPrettiness Enumeration
    Possible Valuesnone, low, mid, high
    Default Valuemid
    Mandatoryno
  • defaultServiceDomain Identifies service domain to be used by default for service requests.

    ParameterDescription
    TypeString
    Possible Valuesany
    Mandatoryno
  • defaultStabilizeOrder

    When this Boolean flag is set to true, the marshaller ensures that properties in different instances of the same entity are always in the same order. Especially useful when writeEmptyProperties=true.

    ParameterDescription
    TypeBoolean
    Possible Valuestrue, false
    Default Valuefalse
    Mandatoryno
  • defaultTypeExplicitness

    Represents how type of objects should be marshalled.

    ParameterDescription
    Typecom.braintribe.codec.marshaller.api.TypeExplicitness Enumeration
    Possible Valuesauto - The marshaller decides which of the other options it will choose.
    always - The types are made explicit to allow to preserve the correct type under all circumstances which means not to rely on any contextual information to auto convert it from another type.
    entities - The types are made explicit for entities in all cases and the other values can get simpler types if appropriate and the context of the value can give the information to reestablish the correct type with an auto conversion.
    polymorphic - he types are made explicit if the actual type cannot be reestablished from the context of the value which is the case that value is a concretization of the type given by the context.
    Default Valueauto
    Mandatoryno
  • defaultWriteAbsenceInformation

    When this Boolean flag is set to true, the marshaller writes information for all absent properties.

    ParameterDescription
    TypeBoolean
    Possible Valuestrue, false
    Default Valuefalse
  • defaultWriteEmptyProperties

    When this Boolean flag is set to true, the marshaller writes all properties that are set to null or are empty (for maps, sets and lists).

    ParameterDescription
    TypeBoolean
    Possible Valuestrue, false
    Default Valuefalse
  • requestPrototyping

    You can use this property as an alternative to a serialized-request. Instead of setting the serialized-request field manually (e.g. copy-pasting JSON directly into the request in Swagger), you can create a request prototype instead, and then map it to your request via DdraMapping. Note that this could be very useful to set default properties for the request. If found, the prototype will be used instead of the serialized-request.

    When prompted, use one of the below prototyping requests:

    • QueryPrototyping - queries for the prototype in an access. This prototype is then used when you execute your request. You need to identify the target prototype:

      ParameterDescription
      accessIdaccess_name where the prototype is located (you can find it in the URL after opening the access after ?accessId=, for example access.demo in ?accessId=access.demo#default).
      prototypeGlobalIdGlobalId of the target prototype.
    • ResourcePrototyping - uses the attached resource as a prototype. In this case, you only need to attach the JSON file:

      ParameterDescription
      prototypeResourceAttach your prototype here (a JSON file).
    • StaticPrototyping - similar to QueryPrototyping, but the prototype must be found in the Cortex model.

      ParameterDescription
      prototypeAssign the prototype from Cortex here.

Configuration in Control Center

The com.braintribe.model.ddra.DdraConfiguration may be queried and updated in Control Centre. You can find it using the Quick Access box.

The mappings are effective as soon as the changes are committed, therefore it is possible to update the configuration without restarting tribefire.

Configuration via Java

Since the configuration for the API is an entity in the cortex access, it is possible to edit it the exact same way as for entities in other accesses.

In this example, we are programmatically mapping the simple authenticate call to /api/v1/serviceDomain/login?user=xxx&password=xxx. Consult the EditDdraConfigurationExample class below:

import com.braintribe.model.ddra.DdraConfiguration;
import com.braintribe.model.ddra.DdraMapping;
import com.braintribe.model.meta.GmEntityType;
import com.braintribe.model.processing.session.GmSessionFactories;
import com.braintribe.model.processing.session.GmSessionFactoryBuilderException;
import com.braintribe.model.processing.session.api.persistence.PersistenceGmSession;
import com.braintribe.model.processing.session.api.persistence.PersistenceGmSessionFactory;

public class EditDdraConfigurationExample {

	public static void main(String[] args) throws GmSessionFactoryBuilderException {

		// get the session factory for a local instance of Tribefire
		PersistenceGmSessionFactory sessionFactory = GmSessionFactories.remote("http://localhost:8080/tribefire-services").authentication("cortex", "cortex").done();

		// open a session to the cortex access
		PersistenceGmSession session = sessionFactory.newSession("cortex");

		// get the GmEntityType for the simple authentication service request
		GmEntityType simpleAuth = session.query().entity(GmEntityType.T, "type:com.braintribe.model.securityservice.OpenUserSessionWithUserAndPassword").find();

		// create a DdraMapping
		DdraMapping mapping = session.create(DdraMapping.T);
		// no need to set this, as this is the default value
		// mapping.setMethod(DdraUrlMethod.GET_POST);
		mapping.setPath("/login");
		mapping.setRequestType(simpleAuth);

		// by default, the OpenUserSessionWithUserAndPassword returns an OpenUserSessionResponse
		// this entity contains a UserSession entity (under the property userSession), which itself contains a sessionId, let's just return the sessionId here
		mapping.setDefaultProjection("userSession.sessionId");

		// get the DdraConfiguration instance
		DdraConfiguration ddraConfiguration = session.query().entity(DdraConfiguration.T, "singleton").find();

		// add the mapping
		ddraConfiguration.getMappings().add(mapping);

		// commit
		session.commit();
	}

}

If you create a similar class and configure the DdraMapping object as specified above, you can authenticate in tribefire with a GET or POST call to /api/v1/serviceDomain/login.

Embedded Properties

It's worth knowing that if the request has any embedded properties, they are also shown in Swagger. For details on how embedding works, see Embedded metadata.

If you want embedded properties to show up only in Swagger, add the ddra use-case selector to embedded metadata.

Requesting Nested Properties

/api/v1 endpoints support accessing nested REST properties via an alias, meaning that you can execute requests even on complex property structures. Aliases can be assigned to entities, maps, lists, and even properties of the Object type. Consider the below data that we want to query with a GET request to find a movie:

FindMoviesRequest -> List<Movie>

- name
- director
 - name
 - country
 - awardsWon
   - institution
     - name
   - name
- category List<Enum> (Horror, Romance, Thriller, Comedy)
- additional
  (Map)
  Example:
    key: wonOscar
    value: true

Normally it wouldn't be possible to refer to nested data, such as director properties, and their properties. This problem was solved by adding the possibility to assign an alias to a property.

Let director have the alias d. This is expressed using the following syntax: director=@d, resulting in the possiblility to refer to properties of director:

@d.country=Austria

Note that you couldn't just say director.country=Austria, because then director is expected to be an alias.

Similarly, let the property additional of the type map have the alias a. This is expressed as additional=@a, resulting in the possibility to refer to keys and values:

a.key=wonOscar&a.value=true

An advanced GET query using an alias could then look as follows:

findMovies?director=@d&d.country=Austria&category=Horror&category=Romance&additional=@a&a.key=wonOscar&a.value=true

A real-life use-case for this feature could be sending a POST request disguised as GET, when using a third-party tool that only supports GET. In that case, we can decide to offer a request that semantically should be a POST (i.e. it creates new entries in the database) as a GET request in tribefire. This is not the recommended solution but sometimes it could be necessary to use it. For example, we could add an extra GET mapping for model/create because we need to create a model via a simple third-party tool that does not support POST.

Try it Out

If you want to experiment with the API for yourself, use our integrated Swagger UI.

For more information, see Using Swagger UI.