SDKs

Publishing schemas from Spring Boot applications

Learn how to automatically publish Taxi schemas from your Spring Boot microservices to Orbital

Available since 0.37.0-M3

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=trueorbital.schema.publisher.base-url=https://my-service-prod/orbital.schema.publisher.publisher-id=my-serviceorbital.schema.publisher.orbital-url=http://localhost:9022orbital.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
orbital.schema.publisher.auth.headersMap of HTTP headers to send on every schema submission. See Authentication.Not set

Authentication

If your Orbital instance sits behind an authenticating proxy (or any reverse proxy that requires a token, API key, or tenant header), you can configure arbitrary headers to be sent on every schema submission.

Headers are configured as a map under orbital.schema.publisher.auth.headers, and apply to both HTTP and WebSocket transports. For WebSocket transport, headers are sent on the connection handshake, and are re-sent automatically on every reconnect.

orbital:  schema:    publisher:      auth:        headers:          Authorization: "Bearer eyJhbGc..."          X-Tenant-Id: "acme-corp"

Or in application.properties:

orbital.schema.publisher.auth.headers.Authorization=Bearer eyJhbGc...orbital.schema.publisher.auth.headers.X-Tenant-Id=acme-corp

If no auth block is configured, no authentication headers are sent — this is the default behaviour.

HTTP vs WebSocket transport

The transport protocol is selected automatically based on the URL scheme configured in orbital-url:

  • http:// or https:// — uses HTTP transport
  • ws:// or wss:// — uses WebSocket transport

HTTP transport (default)

With HTTP, schemas are published as a one-shot POST request to Orbital on startup. This is the simplest option and works well for development and testing.

Available since 0.37.0-M4

WebSocket transport maintains a persistent connection between your service and Orbital. If the connection is lost (e.g., Orbital restarts), the publisher automatically reconnects and re-publishes the schema.

To enable WebSocket transport, change the URL scheme to ws:// or wss://:

orbital:  schema:    publisher:      orbital-url: ws://orbital.production.acme.com

The WebSocket connection uses the same port as Orbital’s HTTP API — no additional ports or configuration are required on the Orbital side.

If the connection cannot be established immediately (e.g., Orbital is not yet running), the publisher will retry automatically with a configurable interval:

orbital:  schema:    publisher:      orbital-url: ws://localhost:9022      retry-interval: 5s   # How long to wait between reconnection attempts (default: 3s)

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 importedimport com.acme.payments.Amountimport 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  // elsewheredata 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/filmsversion: 0.1.0sourceRoot: 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.

@RestControllerclass 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.ymlorbital:  schema:    publisher:      enabled: true      orbital-url: https://orbital.production.acme.com
# application-dev.ymlorbital:  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: