Publishing schemas from Spring Boot applications

Available since 0.37.0

The Spring Boot Schema Publisher starter automatically publishes Taxi schemas from your Spring Boot applications to Orbital on startup.

This is useful for microservices architectures where individual services own their own schema definitions and need to automatically register them with a central Orbital instance.

Adding the dependency

Add the starter dependency to your Spring Boot application’s pom.xml:

<dependency>
    <groupId>com.orbitalhq</groupId>
    <artifactId>schema-publisher-spring-boot-starter</artifactId>
    <version>${orbital.version}</version>
</dependency>

You also need to declare the Orbital repository:

<repositories>
  <repository>
    <id>orbital-releases</id>
    <url>https://repo.orbitalhq.com/release</url>
  </repository>
  
  <!-- snapshot is only required if you're using snapshots -->
  <repository>
    <id>orbital-snapshots</id>
    <url>https://repo.orbitalhq.com/snapshot</url>
    <snapshots>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>

Or for Gradle (build.gradle):

implementation 'com.orbitalhq:schema-publisher-spring-boot-starter:${orbitalVersion}'

Once added, the starter will automatically:

  • Discover Taxi schemas in your application at startup
  • Publish them to the configured Orbital server

Configuration

The project uses reasonable defaults, so generally the only properties that requires configuration are:

  • The base URL of your server
  • The publisherId (which defaults to ${spring.application.name})

Defaults can be overridden by configuring the publisher in your application.yml:

orbital:
  schema:
    publisher:
      enabled: true                          # Enable/disable publishing (default: true)
      base-url: https://my-service-prod/     # Sets the base URL, where Orbital should try to call this application
      publisher-id: my-service               # Publisher ID (default: ${spring.application.name})
      orbital-url: http://localhost:9022             # Orbital server URL (default: http://localhost:9022)
      connection-timeout: 5000               # Connection timeout in ms (default: 5000)

Or in application.properties:

orbital.schema.publisher.enabled=true
orbital.schema.publisher.base-url=https://my-service-prod/
orbital.schema.publisher.publisher-id=my-service
orbital.schema.publisher.orbital-url=http://localhost:9022
orbital.schema.publisher.connection-timeout=5000

Configuration properties

PropertyDescriptionDefault
orbital.schema.publisher.enabledEnable or disable schema publishingtrue
orbital.schema.publisher.base-urlThe base url for this spring boot applicationNot set
orbital.schema.publisher.publisher-idUnique identifier for this publisherValue of spring.application.name
orbital.schema.publisher.orbital-urlURL of the Orbital serverhttp://localhost:9022
orbital.schema.publisher.connection-timeoutConnection timeout in milliseconds5000

Schema generation

At runtime, the plugin will introspect Spring @RestController and @Service components, and automatically generate Taxi service and operation schemas, along with the associated models for return types an inputs.

If you’re using Taxi annotations on your Java/Kotlin classes, these will be discovered and converted to Taxi schemas:

import lang.taxi.annotations.DataType;

@DataType("com.acme.payments.PaymentRequest")
public class PaymentRequest {

    @DataType("com.acme.payments.PaymentId")
    private String paymentId;

    @DataType("com.acme.payments.Amount")
    private BigDecimal amount;

    // getters and setters...
}

Using semantic types in code

When the schema is generated, type information is read at runtime. By default, only raw primitive types are available (such as String, Int, Decimal, etc).

To use richer semantic types, you can use the @DataType annotation (lang.taxi.annotations.DataType)

import lang.taxi.annotations.DataType;

@DataType("com.acme.payments.PaymentRequest")
public class PaymentRequest {

    @DataType("com.acme.payments.PaymentId")
    private String paymentId;

    @DataType("com.acme.payments.Amount")
    private BigDecimal amount;
}

Importing vs Declaring types

By default, types declared with @DataType are declared as new types in the generated schema.

eg - the above code snippet would result in the following Taxi being generated:

namespace com.acme.payments

 // Types are declared  
 type PaymentId inherits String
 type Amount inherits Decimal

model PaymentRequest {
  paymentId: PaymentId
  amount: Amount
}

If you want to use existing types already decalared in a shared taxonomy, then declare the @DataType as imported:

@DataType("com.acme.payments.PaymentRequest")
public class PaymentRequest {

    @DataType(value = "com.acme.payments.PaymentId", imported = true)
    private String paymentId;

    @DataType(value = "com.acme.payments.Amount", imported = true)
    private BigDecimal amount;
}

This would generate the following:

// Types are imported
import com.acme.payments.Amount
import com.acme.payments.PaymentId

namespace com.acme.payments

model PaymentRequest {
  paymentId: PaymentId
  amount: Amount
}

A good rule of thumb is that Types should be imported (shared), whereas models should be published (declared by your service). This aligns with the Taxi best practice of share types, not models.

Kotlin Type Aliases

You can take advantage of Kotlin type aliases to make your code more semantic, and cleaner:

@DataType(value = "com.acme.films.RentalDuration", imported = true)
typealias RentalDuration = Int
 
 
// elsewhere
data class FilmRental(duration: RentalDuration) 

Using generated Taxi types

Taxi supports generating Java and Kotlin code, using the Kotlin plugin.

This plugin will generate semantic types into a reusable library, which you can import into your spring boot microservice.

For example, given the following taxi code:

namespace films

[[ The Id of a film ]]
type FilmId inherits Int

[[ The title of the film ]]
type Title inherits String

In a Taxi project with the Kotlin plugin enabled:

name: com.petflix/films
version: 0.1.0
sourceRoot: src/
plugins: {
   taxi/kotlin: {
    maven: {
       groupId: "com.petflix"
       artifactId: "films-taxonomy"
    }
   }
}

When taxi build is run, a full Maven project is generated, which you can publish to your local Maven repository, and then pull into your Spring boot project.

@RestController
class FilmsApi {

   @GetMapping("/films/{id}")
   fun findById(id: FilmId): Film {
      // implementation
   }
}

For more information, consult the docs on Taxi’s Kotlin plugin

Disabling the publisher

To disable schema publishing (useful for local development or testing), set:

orbital:
  schema:
    publisher:
      enabled: false

You can also use Spring profiles to control when publishing is enabled:

# application-prod.yml
orbital:
  schema:
    publisher:
      enabled: true
      orbital-url: https://orbital.production.acme.com

# application-dev.yml
orbital:
  schema:
    publisher:
      enabled: false

Environment-specific configuration

Use environment variables or Spring’s configuration management to configure different Orbital servers per environment:

orbital:
  schema:
    publisher:
      orbital-url: ${ORBITAL_SERVER_URL:http://localhost:9022}
      base-url: ${THIS_SERVICE_BASE_URL}

Then set the environment variable in your deployment:

export ORBITAL_SERVER_URL=https://orbital.production.acme.com

Troubleshooting

Publisher fails to connect on startup

If the Orbital server is not available when your application starts, the publisher will log an error but will not prevent your application from starting.

The publisher continues to retry to publish to Orbital.

To adjust the connection timeout:

orbital:
  schema:
    publisher:
      connection-timeout: 10000  # 10 seconds

Next steps

Once your schemas are published to Orbital, you can:

Previous
Local environments and stubs