Describing services

Using our taxonomy to describe rich semantic services


A service is simply a group of operations.

service PeopleService {
   operation listAllPeople():Person[]


An operation defines a function on the API.

@HttpOperation(method = 'GET', url = 'https://myservice/people')
operation listAllPeople():Person[]

Operations often have annotations that provide hints to tooling as to how to invoke them.

Taxi ships with some standard annotations, as part of it's std-lib. Although it's up to individual tooling to determine how to interpret these, the suggested usage is as follows:

@HttpOperation(method,url)Indicates that the operation should be invoked over HTTP, using the provided method and url
@HttpRequestBodyIndicates that a parameter will be found on the request body
@ServiceDiscoveryClient(serviceName)Indicates that the service's absolute url should be discovered from Service Discovery, using the provided name for lookup
@PathVariable(name)Indicates a property from the path that should be populated with a variable passed to the operation


service MovieService {
   @HttpOperation(method = "GET" , url = "https://myMovices/movies")
   operation findAllMovies() : Movie[]

   @HttpOperation(method = "GET" , url = "https://myMovices/movies/{id}")
   operationFindMovie( @PathVariable(name = "id") id : MovieId ) : Movie

// Using a service discovery client, such as Eureka
@ServiceDiscoveryClient(serviceName = "actors")
service ActorService {
   @HttpOperation(method = "GET" , url = "/actors")
   operation findAllActors() : Actor[]

Names of operation parameters are optional. This is to encourage developers to leverage a richer type system where possible:

// These two declarations are both valid, and desribe the same operation
operation convertUnits(source:Weight, targetUnit:Unit):Weight
operation convertUnits(Weight,Unit):Weight

Http Parameters

Operation Contracts & Constraints

Contracts and constraints are useful for telling tooling about what functionality an operation can provide, and what conditions must be met before invoking.

Both contracts and constraints use the same syntax.

type Money {
   currency : String
   amount : Decimal
operation convertCurrency(input: Money,
      targetCurrency: String) : Money(from input, currency = targetCurrency)

from input

A contract may indicate that a return type is derived from one of the inputs, by using the from {input} syntax:

operation convertUnits(input: Weight, target: Unit):Weight( from input )

Attribute constraints

Attribute constraints describe either a pre-condition (if on an input) or a post-condition (if on a return type) for an operation

operation convertFromPounds(input : Money(currency = 'GBP'), target: Currency)
    : Money( from input, currency = target)

As shown above, attribute constraints may either be:

  • A constant value (ie., "GBP")
  • A reference to an attribute of another parameter.
    • Nested syntax is supported (ie., foo.bar.baz)

These constraints are applicable on types too - see type constraints for an example.

This is an area of taxi that we expect to see significant development in, to improve the richness of the possible expressions
Edit on GitLab