Skip to content

Java

Obstruo exposes an OpenAI-compatible API. Any Java library that supports a custom base URL works with Obstruo. This page covers the official OpenAI Java SDK and Spring AI.

Prerequisites

  • An ObstruoKey and endpoint URL - see Quick Start
  • A Logical Model configured in your project
  • Java 17 or later

OpenAI Java SDK

Add the dependency (Maven):

<dependency>
  <groupId>com.openai</groupId>
  <artifactId>openai-java</artifactId>
  <version>0.8.0</version>
</dependency>

Or Gradle:

implementation 'com.openai:openai-java:0.8.0'

Chat completions

import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.ChatCompletion;
import com.openai.models.ChatCompletionCreateParams;
import com.openai.models.ChatCompletionUserMessageParam;

OpenAIClient client = OpenAIOkHttpClient.builder()
    .apiKey(System.getenv("OBSTRUO_API_KEY"))
    .baseUrl(System.getenv("OBSTRUO_BASE_URL"))
    .build();

ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
    .model("obstruo-chat")
    .addMessage(ChatCompletionUserMessageParam.builder()
        .content("Summarise this contract: ...")
        .build())
    .build();

ChatCompletion completion = client.chat().completions().create(params);
System.out.println(completion.choices().get(0).message().content().orElse(""));

Streaming

client.chat().completions().createStreaming(params).stream()
    .flatMap(chunk -> chunk.choices().stream())
    .map(choice -> choice.delta().content().orElse(""))
    .forEach(System.out::print);

Embeddings

import com.openai.models.CreateEmbeddingResponse;
import com.openai.models.EmbeddingCreateParams;

EmbeddingCreateParams embeddingParams = EmbeddingCreateParams.builder()
    .model("obstruo-embedding")
    .input(EmbeddingCreateParams.Input.ofString("The quick brown fox"))
    .build();

CreateEmbeddingResponse result = client.embeddings().create(embeddingParams);
List<Double> vector = result.data().get(0).embedding();

Spring AI

If you are using Spring Boot, Spring AI provides a ChatClient that accepts a custom base URL:

# application.yml
spring:
  ai:
    openai:
      api-key: ${OBSTRUO_API_KEY}
      base-url: ${OBSTRUO_BASE_URL}
      chat:
        options:
          model: obstruo-chat
@Service
public class AiService {
    private final ChatClient chatClient;

    public AiService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    public String ask(String question) {
        return chatClient.prompt()
            .user(question)
            .call()
            .content();
    }
}

Environment variables

export OBSTRUO_API_KEY="your-obstruo-key"
export OBSTRUO_BASE_URL="https://api.obstruo.ai/your-org/v1"
OpenAIClient client = OpenAIOkHttpClient.builder()
    .apiKey(System.getenv("OBSTRUO_API_KEY"))
    .baseUrl(System.getenv("OBSTRUO_BASE_URL"))
    .build();

Reading gateway metadata

The openai-java SDK does not expose extra response fields. Use java.net.http.HttpClient to read the obstruo key directly:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

var http = HttpClient.newHttpClient();
var body = """
    {"model":"obstruo-chat","messages":[{"role":"user","content":"Hello!"}]}
    """;

var req = HttpRequest.newBuilder()
    .uri(URI.create(System.getenv("OBSTRUO_BASE_URL") + "/chat/completions"))
    .header("Authorization", "Bearer " + System.getenv("OBSTRUO_API_KEY"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

var resp = http.send(req, HttpResponse.BodyHandlers.ofString());
// Parse resp.body() with your JSON library of choice (Jackson, Gson, etc.)
// The obstruo field has this structure:
// {
//   "routing":   { "resolved_model": "gpt-4o-mini", "provider_type": "OpenAI", "duration_ms": 412 },
//   "redaction": { "total_entities": 0, "by_category": {}, "duration_ms": 3 }
// }

// Streaming header, available on the HttpResponse directly:
var streamHeader = resp.headers().firstValue("x-obstruo-pii-state");
// "no-pii" | "redacted" | "disabled"

Next steps