Summary
Today this library covers one part of Arize: logging model predictions and actuals. I'd like to propose two related changes:
- Split the library into a pure API (interfaces, model types, SPI) and a reference implementation.
- Make the API cover the full Arize REST API, not just logging, by generating it from Arize's published OpenAPI spec. The existing logging API stays, as its own area of the new API.
I'd also like to ask whether the same approach should cover Phoenix's REST API, which would allow container-based integration tests (see Testing below).
I'm willing to contribute all of it, but I want to agree on the shape with maintainers before writing code.
Background
I proposed and implemented the same split for the Langfuse Java client:
I also maintain the Docling Java client, which uses the same structure: an API artifact and a client artifact, discovered via ServiceLoader (docling-serve module). Its API supports both Jackson 2 and 3.
What I see in this repo today
- A single artifact,
com.arize:arize-api-client, targeting Java 1.8.
- Its functionality is limited to logging (
log, bulkLog). There is no Java coverage of the rest of the Arize REST API, such as datasets and experiments.
- An HTTP-based client with hard dependencies on Apache
httpasyncclient 4.1.4, protobuf-java 3.25.5 and protobuf-java-util 3.19.6 (the two protobuf artifacts are on different versions).
- Records are built as protobuf messages (
com.arize.protocol.Public) and serialized to JSON with protobuf-java-util's JsonFormat (see RecordUtil). There is no Jackson dependency. The public logging API takes plain Java types, so protobuf looks like an implementation detail.
- A shade step that relocates
com.google, org.apache and org.codehaus into a shaded classifier.
The shaded jar suggests consumers have already hit dependency conflicts. It fixes that for one distribution, but it doesn't let a framework such as Quarkus or Spring use its own HTTP stack and managed dependency versions.
Arize publishes an OpenAPI spec for its REST API (https://api.arize.com/v2/spec.yaml) and ships Python, TypeScript and Go SDKs for it. Java developers currently have only the logging client.
Proposal
arize-api: interfaces, model types and an SPI, with no HTTP or serialization implementation.
- Generated from the OpenAPI spec at build time, with nothing generated checked in. It covers the full published REST API, so new endpoints appear automatically instead of needing hand-written wrappers.
- The existing logging API is included as a hand-written area of this module (or a sibling module), so current users lose nothing. Since its public types are plain Java, the protobuf conversion could move into the reference client.
- JSON mapping is not forced on users. Frameworks like Spring and Quarkus are opinionated about Jackson and manage their own version of it. In the Langfuse work the generated models carry both Jackson 2 (
com.fasterxml.jackson) and Jackson 3 (tools.jackson) annotations, and the reference client detects which is on the classpath. The same approach would let frameworks on either version use the API without conflicts. Jackson would be new to this repo, which uses protobuf's JsonFormat today, so this is a design choice for the new module, not a change to existing behavior.
arize-client: a reference implementation of the SPI. The current Apache-based transport and protobuf serialization could move here, or it could use java.net.http.HttpClient.
- Discovery via
ServiceLoader, so applications code only against the API and frameworks can provide their own implementation.
- Compatibility: the existing
arize-api-client coordinates keep working, either unchanged or as a thin artifact depending on the new modules.
- Phoenix (optional, if in scope). Phoenix has its own OpenAPI REST API under
/v1, separate from the AX API. The same generation approach could produce a Phoenix API module from its spec. I'm asking whether this belongs here, not assuming it does.
- Testing. In the Langfuse work I added a Testcontainers module that runs the full Langfuse stack, and every API area is tested against it (sync and async). That works because Langfuse is freely self-hostable. Here:
- Phoenix is free to self-host, has public Docker images (
arizephoenix/phoenix), and by default runs as a single container. It is licensed under the Elastic License 2.0. If Phoenix is in scope, it would get a real Testcontainers module, and every generated Phoenix API area could be tested against a real instance.
- Arize AX can't be run this way, since self-hosting is an enterprise offering deployed on Kubernetes. For the AX API I'd propose contract tests against a mock generated from the OpenAPI spec (for example Microcks or WireMock, both of which I contribute to, along with Testcontainers), which run in CI without credentials. Optional integration tests against a real space could be skipped unless an API key and space ID are provided.
Scope note: "Full API" here means the full published AX REST API (the OpenAPI spec). It does not include the gRPC/Arrow Flight bulk-transfer endpoints or OTLP tracing, which the OpenAPI spec doesn't describe. Java tracing is already covered by the OpenInference packages and the OpenTelemetry SDK. Flight could be a follow-up, and the SPI wouldn't preclude a gRPC-based implementation.
What this unlocks
- Java applications can use the whole Arize REST API (datasets, experiments and whatever the API adds next), not just logging.
- Frameworks (Quarkus, Spring, Micronaut) can plug in their own HTTP client, Jackson version and dependency versions without shading.
- Consumers who only use the API stop inheriting
httpasyncclient and protobuf versions transitively.
- Maintenance stays low because most of the API is generated, and the transport can change without breaking the API.
- Tests that run in CI without a live account: against Phoenix in a container, and against spec-driven mocks for AX.
- Potential higher-level api/abstraction in the future (similar to what I've done with Langfuse).
Questions
- Is a split like this wanted at all? "No" is a perfectly good answer and saves us both time.
- Is covering the full AX REST API in scope for this repo, or should that live in a separate repo or module?
- Should Phoenix's REST API be covered as well, in this repo or another? If yes, I'd add a Testcontainers module for it like the one in the Langfuse work.
- What is the minimum Java version? The Langfuse work targets 17, and Arize's OpenInference Java packages already require 17+. This repo targets 8. I would suggest 17, or even 21.
- Should the existing logging API be preserved unchanged? I'd suggest keeping its public types as they are and moving the protobuf conversion into the reference client. Does that match how you see it?
- Should Flight (gRPC bulk transfer) be considered in scope at all, or left to a later proposal? And are there parts of the REST spec you'd want excluded (alpha endpoints, for example)?
- Downstream frameworks like Spring and Quarkus are opinionated about Jackson and manage their own version of it, and they are at different points in the move from Jackson 2 to 3. The current code uses protobuf's
JsonFormat instead. For the generated REST models, is supporting both Jackson 2 and 3 acceptable, even though it means the client would have two JSON mechanisms (protobuf for logging, Jackson for the REST models)?
- How is this client tested today, and is there a sandbox space or API key available for integration tests? If not, would you accept mock-based contract tests generated from the OpenAPI spec as the main safety net for the AX API?
If the answers are favorable, I'll start with a small draft PR that only introduces the module structure and the generation setup, with no behavior changes to existing code.
Summary
Today this library covers one part of Arize: logging model predictions and actuals. I'd like to propose two related changes:
I'd also like to ask whether the same approach should cover Phoenix's REST API, which would allow container-based integration tests (see Testing below).
I'm willing to contribute all of it, but I want to agree on the shape with maintainers before writing code.
Background
I proposed and implemented the same split for the Langfuse Java client:
I also maintain the Docling Java client, which uses the same structure: an API artifact and a client artifact, discovered via
ServiceLoader(docling-servemodule). Its API supports both Jackson 2 and 3.What I see in this repo today
com.arize:arize-api-client, targeting Java 1.8.log,bulkLog). There is no Java coverage of the rest of the Arize REST API, such as datasets and experiments.httpasyncclient4.1.4,protobuf-java3.25.5 andprotobuf-java-util3.19.6 (the two protobuf artifacts are on different versions).com.arize.protocol.Public) and serialized to JSON with protobuf-java-util'sJsonFormat(seeRecordUtil). There is no Jackson dependency. The public logging API takes plain Java types, so protobuf looks like an implementation detail.com.google,org.apacheandorg.codehausinto ashadedclassifier.The shaded jar suggests consumers have already hit dependency conflicts. It fixes that for one distribution, but it doesn't let a framework such as Quarkus or Spring use its own HTTP stack and managed dependency versions.
Arize publishes an OpenAPI spec for its REST API (https://api.arize.com/v2/spec.yaml) and ships Python, TypeScript and Go SDKs for it. Java developers currently have only the logging client.
Proposal
arize-api: interfaces, model types and an SPI, with no HTTP or serialization implementation.com.fasterxml.jackson) and Jackson 3 (tools.jackson) annotations, and the reference client detects which is on the classpath. The same approach would let frameworks on either version use the API without conflicts. Jackson would be new to this repo, which uses protobuf'sJsonFormattoday, so this is a design choice for the new module, not a change to existing behavior.arize-client: a reference implementation of the SPI. The current Apache-based transport and protobuf serialization could move here, or it could usejava.net.http.HttpClient.ServiceLoader, so applications code only against the API and frameworks can provide their own implementation.arize-api-clientcoordinates keep working, either unchanged or as a thin artifact depending on the new modules./v1, separate from the AX API. The same generation approach could produce a Phoenix API module from its spec. I'm asking whether this belongs here, not assuming it does.arizephoenix/phoenix), and by default runs as a single container. It is licensed under the Elastic License 2.0. If Phoenix is in scope, it would get a real Testcontainers module, and every generated Phoenix API area could be tested against a real instance.Scope note: "Full API" here means the full published AX REST API (the OpenAPI spec). It does not include the gRPC/Arrow Flight bulk-transfer endpoints or OTLP tracing, which the OpenAPI spec doesn't describe. Java tracing is already covered by the OpenInference packages and the OpenTelemetry SDK. Flight could be a follow-up, and the SPI wouldn't preclude a gRPC-based implementation.
What this unlocks
httpasyncclientand protobuf versions transitively.Questions
JsonFormatinstead. For the generated REST models, is supporting both Jackson 2 and 3 acceptable, even though it means the client would have two JSON mechanisms (protobuf for logging, Jackson for the REST models)?If the answers are favorable, I'll start with a small draft PR that only introduces the module structure and the generation setup, with no behavior changes to existing code.