Open Source Java 21 SDK

JBrave: search API correctness you can inspect.

A source-backed case study in turning Brave Search calls into typed, replayable Java workflows: query modeling, request export, execution control, response extraction, and fixture-friendly JSON.

Role

Founder-led engineering

API modeling, execution semantics, docs

Type

Open-source Java SDK

Unofficial Brave Search API tooling

Status

Alpha / 0.1.0

Core model active, public API evolving

Stack

Java 21

Maven, JDK HTTP client, Jackson 3

Evidence

157 tests

Builder, fixture, option, and response coverage

License

Apache 2.0

Independent YGBStudio project

Problem

A search API call is not just a URL once it becomes part of a system.

A search SDK has to do more than assemble a URL: it has query limits, optional execution paths, quota signals, typed success and error responses, and fixtures that need to survive without live API access.

The sealed builder contract keeps every search vertical on the same lifecycle: export a request, execute only when needed, inspect quota metadata, and deserialize either a success or an error.

BraveQueryBuilder.java sealed API surface
public sealed interface BraveQueryBuilder<T, E extends ApiResponse>
    permits BraveNewsQuery, BraveWebQuery, BraveImageQuery,
            BraveVideoQuery, BraveSuggestQuery, BraveSpellcheckQuery {

  // request export and optional execution
  URI toURI();
  HttpRequest toHttpRequest();
  T execute();
  boolean hasExecuted();
  Optional<HttpResponse<String>> getHttpResponse();

  // quota signals from the executed response
  Optional<XRateLimit> getRateLimits();
  Optional<XRateLimitPolicy> getRateLimitPolicy();
  Optional<XRateLimitRemaining> getRateLimitRemaining();

  // typed success/error extraction
  Class<E> getResponseType();
  Optional<E> getPOJO();
  Optional<ErrorResponse> getErrorPOJO();
  Optional<ApiResponse> getEitherPOJO();

  T reset();
}

Workflow

The SDK models the full search interaction, not only the request.

Each stage has a separate responsibility, which makes it easier to keep production transport, testing, and offline analysis from collapsing into one ad-hoc helper.

  1. 01 BraveWebQuery

    Model query

    A builder owns the search vertical and collects language, market, result filters, headers, operators, and token context.

  2. 02 AbstractQueryUrlBuilder

    Validate before HTTP

    The URL builder rejects empty or oversized queries before a remote request can turn a local mistake into an API failure.

  3. 03 toURI / toHttpRequest / execute

    Export or execute

    The same configured query can become a URI, a standard HttpRequest, or a built-in execution session.

  4. 04 AbstractRequestExecutor

    Decode response

    The executor reads byte responses, handles gzip when present, and adapts the result back to a string response.

  5. 05 getPOJO / getEitherPOJO

    Extract outcome

    Consumers can ask for a typed success object, a typed error object, or a unified ApiResponse after one execution.

  6. 06 WebSearchApiResponse.from

    Replay JSON

    Response records read from files, strings, readers, or HttpResponse instances, then write back to portable JSON.

Source Evidence

What the implementation makes visible.

The source shows how the SDK treats validation, execution coordination, response decoding, and replay as first-class design concerns.

Validation

The query builder encodes Brave's request limits as local invariants.

Source

core/builders/AbstractQueryUrlBuilder.java

int chars = queryTerm.codePointCount(0, queryTerm.length());
int words = queryTerm.trim().isEmpty()
    ? 0
    : queryTerm.trim().split("\\s+").length;

return chars <= 400 && words <= 50;

Takeaway

The validation rule is enforced as an invariant, which makes malformed search input fail locally before it reaches the API.

Execution

Token-scoped execution is serialized fairly before rate-limit retry logic runs.

Source

core/executors/BraveExecutionGate.java

startLock = new ReentrantLock(true);

startLock.lockInterruptibly();
HttpResponse<String> response = processNext(request, maxRetries);

RateLimitResponse limit = RateLimitResponse.from(response);
TimeUnit.SECONDS.sleep(
    limit.xRateLimitReset().secondsUntilNextRequest()
);

Takeaway

JBrave treats rate-limited search as a coordinated resource instead of scattering retry sleeps across application code.

Transport

The built-in executor keeps transport decoding explicit and replaceable.

Source

core/executors/AbstractRequestExecutor.java

HttpResponse<byte[]> bytes =
    client.send(request, HttpResponse.BodyHandlers.ofByteArray());

String body = decodeByteHttpResponse(bytes);

return adaptHttpResponse(bytes, body);

Takeaway

Teams can use JBrave's executor, but the builders also produce plain URI and HttpRequest values for existing infrastructure.

Replay

Response records are built to move between live API calls and offline fixtures.

Source

api/response/WebSearchApiResponse.java

WebSearchApiResponse.from(new File("response.json"));
WebSearchApiResponse.from(jsonString);
WebSearchApiResponse.from(reader);
WebSearchApiResponse.from(httpResponse);

response.write(new File("fixture.json"));
String json = response.toJson();

Takeaway

The same response model can support live calls, saved fixtures, ranking experiments, and regression tests.

Use Cases

Where JBrave creates value after the first API call works.

These scenarios show the practical value of separating request modeling, execution control, and fixture-friendly response handling.

Use case

Search gateway integration

Problem

A service needs Brave Search in the mix, but the production stack already owns HTTP clients, retries, logging, and gateway policy.

How it helps

JBrave builds safe URI and HttpRequest objects while keeping execution optional, so the team can use its existing transport layer.

Why it matters

Integration stays typed without forcing a second HTTP abstraction into production.

Use case

RAG and ranking fixtures

Problem

RAG and ranking experiments need repeatable search inputs, not live network drift in every test run.

How it helps

Typed response records can be serialized, deserialized, and replayed from frozen JSON fixtures.

Why it matters

Search data becomes a deterministic input for prompt enrichment, feature extraction, and regression testing.

Use case

Batch research sessions

Problem

Batch collection has to respect query limits, rate metadata, and later inspection across many result types.

How it helps

Stateful sessions retain the executed response, expose typed rate metadata, and support web, image, news, video, suggest, and spellcheck builders.

Why it matters

Search collection can be paced, audited, and analyzed without hand-parsing URLs or response headers.

Boundaries

The useful edges are documented, not hidden.

JBrave is intentionally small enough to inspect. That means it should be clear where it helps, where it stops, and what alpha status implies.

Designed for

  • Java services that need explicit search request modeling.
  • Custom HTTP stacks that still benefit from typed URI and HttpRequest generation.
  • Offline fixtures for tests, ranking experiments, and search-data analysis.
  • Developers who want public Brave Search surfaces represented as inspectable Java objects.

Not designed for

  • Replacing Brave's official API documentation or account/plan rules.
  • Hiding every HTTP detail behind a generic client abstraction.
  • Sharing one mutable builder as a thread-safe singleton.
  • Guaranteeing stable method signatures before the alpha API settles.

Status

Alpha 0.1.0: the lifecycle model is clear, while public method signatures may still evolve before a stable release.

Independence

JBrave is an independent Apache 2.0 project by YGBStudio. It is not affiliated with, endorsed by, or supported by Brave Software, Inc.

If you like what you see

I'm always open to interesting work. Say hello.

Independent software studio. Open source.