QPillars LogoQPillars
SolutionsCase StudiesAboutBlogCareersContact
Book a Demo
Back to Blog
Engineering

Why REST APIs and SiLA2 Don't Talk - And How to Bridge Them

April 17, 202611 min readIacob Marian

Why REST APIs and SiLA2 Don't Talk - And How to Bridge Them

REST APIs and SiLA2 cannot interoperate directly because SiLA2 is built on gRPC over HTTP/2 with Protocol Buffers, while REST is JSON over HTTP/1.1 - two fundamentally different wire protocols. The standard workaround in labs today is hand-authoring SiLA2 Feature Definition Language (FDL) XML to wrap each REST endpoint, which is slow, error-prone, and rarely maintained. The open-source tool openapi-to-sila2 (released April 2026 by QPillars) automates this: feed it an OpenAPI spec, get back validated FDL XML, gRPC stubs, and Python type classes - in one command.

The Mismatch - Two Standards That Don't Speak

SiLA2 (Standardization in Lab Automation, version 2) is the industry standard for laboratory instrument communication. It is governed by the SiLA Consortium, a non-profit whose board includes representatives from major IVD manufacturers, Tecan, Novartis, GSK, Takeda, Novo Nordisk, Fraunhofer IPA, and Zeiss Digital Innovation. If you integrate lab instruments at a serious pharma or biotech, SiLA2 is on the roadmap.

But SiLA2 is gRPC-native. The protocol runs over HTTP/2, payloads are encoded in Protocol Buffers, and instrument capabilities are described in an XML dialect called Feature Definition Language (FDL), validated against an official XSD schema.

Meanwhile, almost everything else in the modern lab stack ships REST/OpenAPI:

  • LIMS and ELN platforms expose REST APIs (Benchling, LabVantage, STARLIMS)
  • Cloud lab services (Strateos, Emerald Cloud Lab) ship REST
  • New instrument vendors default to REST/OpenAPI before they even consider SiLA2
  • Internal lab software written in the last five years is almost universally FastAPI, Express, or Spring Boot - all REST-first

The result: a SiLA2-compliant orchestrator cannot call a REST endpoint without a translation layer, and a REST-based LIMS cannot consume a SiLA2 instrument without a gRPC client. Two standards, no bridge.

Why SiLA2 Chose gRPC (And Why That Choice Matters)

SiLA2's choice of gRPC was not arbitrary. Lab instrument control has requirements that REST handles poorly:

Long-running commands with progress streams. A liquid handler's "run protocol" command can take 45 minutes. SiLA2 defines Observable Commands that stream intermediate state - current step, estimated remaining time, sub-task progress - over a single bi-directional gRPC stream. Doing this with REST means polling, webhooks, or Server-Sent Events, all of which are second-class citizens.

Strong typing across the wire. SiLA2 Features define exact data types (Real, Integer, String, Timestamp, custom Structures, Lists). gRPC + protobuf enforces these types at serialization time. REST/JSON has no native type enforcement - you bolt on JSON Schema validation, but it's optional and frequently skipped.

Discovery and self-description. A SiLA2 server publishes its FDL files. A client can query, parse, and statically validate every command before sending it. OpenAPI does the same conceptually, but FDL is purpose-built for lab instrument semantics (commands vs. properties, observable vs. unobservable, defined errors).

Bi-directional communication. Some instruments need to push events to the orchestrator (door opened, sample loaded, error condition). gRPC streaming handles this in one connection. REST requires a second channel.

These are real engineering wins for instrument control. They also create real friction with the REST-first world.

The Status Quo - Hand-Authoring FDL XML

Today, when a lab needs to expose a REST endpoint as a SiLA2 service, an engineer typically:

  1. Reads the OpenAPI spec (or the REST docs, if no spec exists).
  2. Designs a SiLA2 Feature - choosing identifiers, display names, descriptions.
  3. Maps each REST operation to a SiLA2 Command or Property.
  4. Translates each request/response schema into SiLA2 Data Types.
  5. Authors the FDL XML by hand, validating against the XSD.
  6. Runs sila2-codegen to generate .proto and gRPC stubs.
  7. Writes a Python (or Java/.NET) wrapper that translates SiLA2 calls into REST calls.

Steps 2-5 take hours per Feature, days for a real instrument with 20+ endpoints, and the result drifts the moment the REST API changes. Most teams maintain these wrappers reluctantly. Some give up and write a custom HTTP-to-gRPC adapter that bypasses SiLA2 entirely - which defeats the purpose of having a standard.

The repetitive, mechanical nature of this work is exactly what code generation is for.

The Bridge - openapi-to-sila2

openapi-to-sila2 is an open-source (Apache 2.0) Python tool that automates the entire pipeline. Version 0.1.1 shipped to PyPI on April 8, 2026.

The pipeline is four stages, executed by a single CLI command:

Pipeline diagram showing four stages from OpenAPI spec through FDL XML and gRPC codegen to Python type classes

Each stage is deterministic, validated, and reproducible:

  1. OpenAPI Parsing - reads JSON or YAML spec, validates structure.
  2. FDL Generation - emits SiLA2 Feature Definition XML, validated against the official XSD.
  3. gRPC Codegen - invokes the upstream sila2-codegen to produce .proto files and gRPC stubs.
  4. Python Type Classes - extracts protobuf types into idiomatic Python dataclasses for client-side use.

Install and Run

pip install openapi-to-sila2

openapi-to-sila2 generate \
  --input plate-reader-api.openapi.json \
  --output ./generated \
  --codegen \
  --types

That's it. Output: a fully wired SiLA2 Feature, ready to plug into a SiLA2 server skeleton.

How REST Concepts Map to SiLA2

The mapping is opinionated and consistent:

OpenAPI conceptSiLA2 conceptNotes
tagsFeatureEach tag becomes one SiLA2 Feature.
GET (no parameters)PropertyRead-only value, fetched on demand.
GET / POST / PUT / DELETE (with parameters)CommandParameterized operation.
Object schemasStructureNamed collection of typed fields.
ArraysListOrdered collection.
HTTP error responsesExecutionErrorMapped into SiLA2's defined error type.
Path + query + body paramsUnified Parameters StructureCombined into a single SiLA2 input.

This is not a perfect 1:1 mapping - the two standards have genuinely different shapes - but it's faithful enough to use directly for most lab instrument and LIMS APIs.

Concrete Example - A Plate Reader

Consider a fictional plate reader that exposes a small REST API:

# plate-reader-api.openapi.yaml (excerpt)
openapi: 3.0.3
info:
  title: AcmeReader API
  version: 1.2.0
paths:
  /status:
    get:
      tags: [Diagnostics]
      operationId: getStatus
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InstrumentStatus'
  /measurements:
    post:
      tags: [Measurement]
      operationId: runMeasurement
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MeasurementRequest'
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MeasurementResult'
components:
  schemas:
    InstrumentStatus:
      type: object
      properties:
        ready: { type: boolean }
        temperature_c: { type: number }
    MeasurementRequest:
      type: object
      required: [wells, wavelength_nm]
      properties:
        wells:
          type: array
          items: { type: string, pattern: '^[A-H](?:[1-9]|1[0-2])$' }
        wavelength_nm: { type: integer, minimum: 200, maximum: 1000 }

Running openapi-to-sila2 generate -i plate-reader-api.openapi.yaml -o ./generated --codegen --types produces, among other artifacts, an FDL XML that looks like this (abbreviated):

<?xml version="1.0" encoding="UTF-8"?>
<Feature xmlns="http://www.sila-standard.org"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.sila-standard.org
                             https://gitlab.com/SiLA2/sila_base/raw/master/schema/FeatureDefinition.xsd"
         SiLA2Version="1.0" FeatureVersion="1.0"
         Originator="com.acme" Category="instrument">
  <Identifier>Measurement</Identifier>
  <DisplayName>Measurement</DisplayName>
  <Description>Operations from the Measurement tag of AcmeReader API.</Description>

  <Command>
    <Identifier>RunMeasurement</Identifier>
    <DisplayName>Run Measurement</DisplayName>
    <Description>Trigger a plate read at a specified wavelength.</Description>
    <Observable>No</Observable>
    <Parameter>
      <Identifier>Parameters</Identifier>
      <DisplayName>Parameters</DisplayName>
      <Description>Combined request parameters.</Description>
      <DataType>
        <DataTypeIdentifier>MeasurementRequest</DataTypeIdentifier>
      </DataType>
    </Parameter>
    <Response>
      <Identifier>Result</Identifier>
      <DisplayName>Result</DisplayName>
      <Description>Measurement result payload.</Description>
      <DataType>
        <DataTypeIdentifier>MeasurementResult</DataTypeIdentifier>
      </DataType>
    </Response>
  </Command>
  <!-- DataType definitions follow ... -->
</Feature>

The companion .proto file (generated by sila2-codegen on the FDL) and Python dataclasses are produced in the same run. You implement one method - the actual REST call - and the rest is generated.

# Your implementation (the only hand-written part)
import httpx
from generated.measurement_pb2 import MeasurementRequest, MeasurementResult

async def run_measurement(req: MeasurementRequest) -> MeasurementResult:
    async with httpx.AsyncClient(base_url="http://reader.local") as client:
        resp = await client.post("/measurements", json={
            "wells": list(req.wells),
            "wavelength_nm": req.wavelength_nm,
        })
        resp.raise_for_status()
        return MeasurementResult(**resp.json())

A 20-endpoint instrument that previously took two engineering days to wrap in SiLA2 is now a 30-minute job: run the generator, write the thin REST adapter functions, ship.

Known Limitations

The tool is honest about what it doesn't do:

  • Complex unions (allOf, oneOf, anyOf) collapse to SiLA2's Any type. SiLA2's type system does not have native sum types.
  • Multiple error schemas map to a single ExecutionError per Feature - a SiLA2 limitation, not the tool's.
  • Streaming endpoints (Server-Sent Events, WebSocket upgrades) are not represented as SiLA2 Observable Commands. Generate the static surface, then add observability by hand for the few endpoints that need it.
  • Dynamic objects without declared properties default to Any.

These are upstream SiLA2 constraints, not bugs. The tool generates what is mappable and stays out of the way for the rest.

Where This Fits in the Modern Lab Stack

A 2026 lab is layered. Each layer has its own protocol, optimized for its own job:

Stack diagram showing MCP for AI agents at the top, SiLA2 for instrument interoperability in the middle, and REST APIs for everything else at the bottom

  • MCP (Model Context Protocol) is the AI agent layer. It is how language models discover and invoke tools, including lab instruments. We covered MCP in depth in our guide to connecting AI agents to lab instruments with MCP.
  • SiLA2 is the instrument interop layer. It is what major IVD manufacturers, Tecan, and SiLA Consortium members converge on for cross-vendor orchestration.
  • REST/OpenAPI is the everything-else layer - LIMS, ELN, scheduling, sample tracking, internal services, cloud lab APIs.

openapi-to-sila2 lives at the boundary between the bottom two layers. It lets a REST-native instrument or service join a SiLA2 orchestration without a hand-written adapter. Combined with an MCP wrapper on top, the same instrument is reachable from both classical orchestrators (SiLA2-aware schedulers like the SiLA2 Manager) and modern AI agents.

This is the architecture we use at QPillars on real client work - bridging instrument vendors who shipped REST years ago with SiLA2-native LIMS deployments at pharma customers. See our AI for Instruments and LiquidBridge services for more.

Frequently Asked Questions

Why doesn't SiLA2 just support REST natively?

Because the protocol's design goals - long-running observable commands with progress streams, strong cross-language typing, bi-directional communication, and a self-describing schema - are all easier to deliver on gRPC than on REST. SiLA2 chose the substrate that fit the lab instrument problem; bridging to REST is a separate, solvable problem.

What does openapi-to-sila2 actually generate?

A complete SiLA2 Feature pipeline: an XSD-validated FDL XML file describing the Feature, .proto files (via the upstream sila2-codegen tool), gRPC stubs, and idiomatic Python dataclasses for the request and response types. You write the thin function bodies that call the REST API; everything else is generated.

Can I use this in production today?

The tool is at version 0.1.1 (released April 2026), Apache 2.0 licensed, with a working test suite. It is appropriate for internal projects, prototypes, and non-regulated environments today. For GxP environments, treat the generated code as you would any third-party library - validate, version-pin, and document.

How is this different from just calling the REST API directly from Python?

Calling REST directly works inside one application. But if your orchestrator, LIMS, or scheduler is SiLA2-native (which is the case at most large pharma deployments), it speaks gRPC and expects a SiLA2 server endpoint, not an HTTP URL. openapi-to-sila2 produces that SiLA2 surface so the REST instrument or service joins the SiLA2 ecosystem without code changes on the consumer side.

How does this relate to MCP-based AI agent integration?

They are complementary. MCP is the protocol AI agents use to discover and invoke tools. SiLA2 is the protocol classical lab orchestrators use to drive instruments. A single instrument can have both an MCP server (for AI agents) and a SiLA2 server (for orchestrators) on top of one underlying REST API. openapi-to-sila2 generates the SiLA2 side; an MCP wrapper handles the agent side.

Key Takeaways

  • REST and SiLA2 cannot interoperate directly - SiLA2 is gRPC over HTTP/2 with protobuf, REST is JSON over HTTP/1.1.
  • SiLA2 chose gRPC for good reasons: observable commands, strong typing, bi-directional streams, native discovery - all hard on REST.
  • The standard workaround - hand-authoring FDL XML per endpoint - costs hours per Feature and rots when the REST API changes.
  • openapi-to-sila2 (v0.1.1, April 2026) automates the full pipeline: OpenAPI spec to validated FDL XML to gRPC stubs to Python types, in one command.
  • In the 2026 lab stack, MCP serves AI agents, SiLA2 serves instrument orchestration, and REST serves everything else - openapi-to-sila2 bridges the bottom two layers so REST instruments and services can join SiLA2 deployments without hand-written adapters.

The tool is open source. Try it on one of your instrument APIs, file issues, send pull requests: github.com/qpillars/openapi-to-sila2.


Written by Iacob Marian, Technical Lead and Co-founder at QPillars. Published 2026-04-17.

Iacob Marian

Technical Lead & Co-founder at QPillars

Iacob builds intelligent software infrastructure for life sciences laboratories, with a focus on Rust for instrument control and agentic AI for lab automation.

Full profileLinkedInPublished April 17, 2026
SiLA2OpenAPIlab automationgRPCinstrument integration

Related Articles

Engineering

Agentic AI for Lab Workflows - From Scripts to Autonomous Systems

Mar 31, 2026

Engineering

How to Connect AI Agents to Lab Instruments with MCP

Mar 21, 2026

Engineering

Why Rust Is the Future of Laboratory Instrument Control

Mar 18, 2026

QPillars LogoQPillars

Intelligent software for scientific instruments

Solutions

  • AI for Instruments
  • Systems Engineering
  • LiquidBridge

Company

  • About
  • Case Studies
  • Blog
  • Careers
  • Contact

Offices

Zurich, Switzerland

Chisinau, Moldova

© 2024-2026 QPillars GmbH. All rights reserved.

info@qpillars.com+41 78 262 97 97