AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Kora Http Client

skill-kora-projects-kora-skills-kora-http-client · by kora-projects

Declarative Kora HTTP clients - @HttpClient interface with @HttpRoute, parameter mapping (@Path/@Query/@Header/@Cookie), @Json bodies, HttpResponseEntity, @Mapping and @ResponseCodeMapper, @InterceptWith interceptors, and OkHttp/AsyncHttpClient/JDK transports. Use when building a typed outbound HTTP client in a Kora service, wiring auth interceptors (Basic/ApiKey/Bearer), configuring per-client t…

No reviews yet
0 installs
43 views
0.0% view→install

Install

$ agentstack add skill-kora-projects-kora-skills-kora-http-client

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-kora-projects-kora-skills-kora-http-client)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Kora Http Client? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Kora HTTP Client

Declarative, compile-time HTTP clients: annotate an interface with @HttpClient, declare methods with @HttpRoute, and the annotation processor generates the implementation. No reflection, no runtime proxies. Inject the client interface like any other Kora component.

Dependencies: http-client-ok (transport) + json-module (for @Json) + annotation-processors.

All Kora artifacts inherit their version from the ru.tinkoff.kora:kora-parent BOM (the examples pin 1.2.17). Never version individual ru.tinkoff.kora:* artifacts.


Quick Start

1. Dependencies (Java)

dependencies {
    koraBom platform("ru.tinkoff.kora:kora-parent:1.2.17")

    annotationProcessor "ru.tinkoff.kora:annotation-processors"

    implementation "ru.tinkoff.kora:http-client-ok"
    implementation "ru.tinkoff.kora:json-module"
    implementation "ru.tinkoff.kora:config-hocon"
}

For Kotlin, use ksp "ru.tinkoff.kora:symbol-processors" instead of annotationProcessor.

2. Plug the transport module into @KoraApp

@KoraApp
public interface Application extends
        HoconConfigModule,
        JsonModule,
        OkHttpClientModule {
}

3. Declare the client interface

@HttpClient(configPath = "httpClient.userApi")
public interface UserApiClient {

    @HttpRoute(method = HttpMethod.GET, path = "/users/{userId}")
    @Json
    UserResponse getUser(@Path String userId);

    @HttpRoute(method = HttpMethod.GET, path = "/users")
    @Json
    List listUsers(@Query("page") int page, @Query("size") int size);

    @HttpRoute(method = HttpMethod.POST, path = "/users")
    @Json
    HttpResponseEntity createUser(@Json CreateUserRequest request);

    @HttpRoute(method = HttpMethod.DELETE, path = "/users/{userId}")
    void deleteUser(@Path String userId);
}

4. Configuration (HOCON)

The client resolves config at httpClient.{lower-case class name} by default, or at the path given in configPath. The url key is required.

httpClient {
  userApi {
    url = "http://localhost:8080"
    url = ${?USER_API_URL}
    requestTimeout = "10s"
  }
}

5. Inject and use

@Component
public final class UserService {

    private final UserApiClient client;

    public UserService(UserApiClient client) {
        this.client = client;
    }

    public UserResponse getUser(String id) {
        return client.getUser(id);
    }
}

What's in references/ and assets/

| File | Purpose | |------|---------| | references/declarative-client-reference.md | @HttpClient, @HttpRoute, parameter & body mapping, @Mapping, @ResponseCodeMapper, signatures, per-client/per-method config | | references/async-client-reference.md | CompletionStage, Project Reactor Mono, Kotlin suspend, AsyncHttpClient/JDK transports | | references/error-handling-guide.md | HttpClientResponseException, HttpClientDecoderException, HttpResponseEntity, status-aware decoding | | references/interceptors-reference.md | HttpClientInterceptor, @InterceptWith, built-in Basic/ApiKey/Bearer auth, resilience | | references/okhttp-transport-reference.md | OkHttp config keys, HTTP versions, proxy, OkHttpConfigurer, telemetry | | assets/UserApiClient.java.template | Base CRUD client (Java) | | assets/UserApiClient.kt.template | Base CRUD client (Kotlin) | | assets/ResilientApiClient.java.template | Client with @Retry/@CircuitBreaker/@Timeout/@Fallback | | assets/AsyncApiClient.java.template | Async client returning CompletionStage | | assets/CustomMapperClient.java.template | @Mapping request body + @ResponseCodeMapper | | assets/ApiKeyAuthInterceptor.java.template | Custom HttpClientInterceptor for API key auth |


When to use vs NOT

Use this skill when:

  • Building a typed outbound HTTP client interface with @HttpClient + @HttpRoute.
  • Mapping parameters via @Path, @Query, @Header, @Cookie, @Json.
  • Adding @InterceptWith interceptors for auth, logging, or tracing.
  • Configuring per-client timeouts, proxy, HTTP version, or telemetry under httpClient.*.

Do NOT use when:

  • You have an OpenAPI contract and want a generated client - use kora-openapi-generator-client.
  • You need the inbound HTTP server (@HttpController) - use kora-http-server.
  • You need only the raw imperative HttpClient.execute(request) API - that is covered briefly below and in full in the docs.

Core patterns

Parameter mapping

| Annotation | Import | Example | |------------|--------|---------| | @Path | ru.tinkoff.kora.http.common.annotation.Path | @Path String id -> /users/{id} | | @Query | ru.tinkoff.kora.http.common.annotation.Query | @Query("page") int p -> ?page=1 | | @Header | ru.tinkoff.kora.http.common.annotation.Header | @Header("X-Trace-ID") String tid | | @Cookie | ru.tinkoff.kora.http.common.annotation.Cookie | @Cookie("sessionId") String sid | | @Json | ru.tinkoff.kora.json.common.annotation.Json | @Json CreateUserRequest req | | @Mapping | ru.tinkoff.kora.common.Mapping | @Mapping(TextMapper.class) Body b |

The parameter name defaults to the method argument name; override it with value (e.g. @Path("userId")). Arguments are required by default; mark @Nullable to make them optional.

Response handling

By default the response is decoded for 2xx status codes; any other status throws HttpClientResponseException (carrying code(), the body, and headers). To inspect the status and headers yourself, return HttpResponseEntity:

@HttpRoute(method = HttpMethod.GET, path = "/users/{userId}")
@Json
HttpResponseEntity getUser(@Path String userId);

// In the caller:
HttpResponseEntity response = client.getUser("123");
if (response.code() == 200) {
    return response.body();
}

HttpResponseEntity exposes code(), body(), and headers(). See [error-handling-guide](references/error-handling-guide.md).

JSON bodies

@Json on a parameter writes it as JSON; @Json on the method reads the response as JSON. The json-module dependency is required.

@HttpRoute(method = HttpMethod.POST, path = "/users")
@Json
UserResponse createUser(@Json CreateUserRequest request);

@Json
record CreateUserRequest(String email, String name) {}

@Json
record UserResponse(String id, String email, String name) {}

Interceptors

Implement HttpClientInterceptor and attach it with @InterceptWith on the interface (client-wide) or a single method. Mutate the request via request.toBuilder() - mutating in place has no effect.

@Component
public final class ApiKeyAuthInterceptor implements HttpClientInterceptor {

    private final ApiKeyAuthConfig config;

    public ApiKeyAuthInterceptor(ApiKeyAuthConfig config) {
        this.config = config;
    }

    @Override
    public CompletionStage processRequest(
            Context ctx, InterceptChain chain, HttpClientRequest request) throws Exception {
        var authorized = request.toBuilder()
                .header("Authorization", config.value())
                .build();
        return chain.process(ctx, authorized);
    }
}

@InterceptWith(ApiKeyAuthInterceptor.class)
@HttpClient(configPath = "httpClient.dataApi")
public interface DataApiClient { }

@InterceptWith imports from ru.tinkoff.kora.http.common.annotation.InterceptWith. Kora also ships built-in auth interceptors (BasicAuthHttpClientInterceptor, ApiKeyHttpClientInterceptor, BearerAuthHttpClientInterceptor) - see [interceptors-reference](references/interceptors-reference.md).

Async signatures

Methods may return T, CompletionStage, or (with reactor-core) Mono. In Kotlin a method may be suspend (requires kotlinx-coroutines-core).

@HttpRoute(method = HttpMethod.GET, path = "/items/{id}")
@Json
CompletionStage getItemAsync(@Path String id);

See [async-client-reference](references/async-client-reference.md).

Resilience

Resilience comes from the separate resilient-kora module (ResilientModule), not from the HTTP client itself. Its aspect annotations take a single config name; the actual values live under resilient.* in config.

implementation "ru.tinkoff.kora:resilient-kora"
@HttpClient(configPath = "httpClient.itemApi")
public interface ItemApiClient {

    @Retry("itemApi")
    @HttpRoute(method = HttpMethod.GET, path = "/items/{id}")
    @Json
    ItemResponse getItem(@Path String id);

    @CircuitBreaker("itemApi")
    @HttpRoute(method = HttpMethod.POST, path = "/items")
    @Json
    ItemResponse createItem(@Json CreateItemRequest request);

    @Timeout("itemApi")
    @Fallback(value = "itemApi", method = "listItemsFallback()")
    @HttpRoute(method = HttpMethod.GET, path = "/items")
    @Json
    List listItems();

    default List listItemsFallback() {
        return List.of();
    }
}
resilient {
  retry { itemApi { delay = "100ms", attempts = 3 } }
  circuitbreaker { itemApi { slidingWindowSize = 20, minimumRequiredCalls = 10, failureRateThreshold = 50 } }
  timeout { itemApi { duration = "5s" } }
}

> The annotation does not take maxAttempts, failureThreshold, or a @Backoff. There is no inline tuning - use the named resilient.* config block. See the kora-aop-resilient skill for the full configuration reference.

Transport selection

| Module | Artifact | HTTP/2 | HTTP/3 | Note | |--------|----------|--------|--------|------| | OkHttpClientModule | http-client-ok | yes | yes | Default choice | | AsyncHttpClientModule | http-client-async | no | no | Async HTTP Client based | | JdkHttpClientModule | http-client-jdk | yes | no | JDK built-in client |

Only one transport module is plugged into @KoraApp at a time. See [okhttp-transport-reference](references/okhttp-transport-reference.md).

Imperative client

Inject the base HttpClient and build requests by hand when a declarative interface does not fit:

HttpClientRequest request = HttpClientRequest.of("POST", "http://localhost:8090/pets/{petId}")
        .templateParam("petId", "1")
        .queryParam("page", 1)
        .header("token", "12345")
        .body(HttpBody.plaintext("refresh"))
        .build();
CompletionStage response = httpClient.execute(request);

Common pitfalls

| Symptom | Fix | |---------|-----| | @HttpClient(baseUrl = ...) does not compile | @HttpClient has no baseUrl. Use configPath and supply url in config. | | "Required dependency not found" for the client | Plug a transport module (OkHttpClientModule) into @KoraApp and add annotation-processors. | | @Json body not serialized | Add json-module and JsonModule; annotate the DTO with @Json. | | Interceptor header change ignored | Build a new request with request.toBuilder().header(...).build(); do not mutate in place. | | Wrong @InterceptWith import | It is ru.tinkoff.kora.http.common.annotation.InterceptWith. | | Non-2xx silently swallowed | Non-2xx throws HttpClientResponseException unless you return HttpResponseEntity or use @ResponseCodeMapper. | | @Retry(maxAttempts = ...) rejected | Resilient annotations take a config name string; tune values under resilient.*. |


References

  • [declarative-client-reference](references/declarative-client-reference.md) - @HttpClient, @HttpRoute, parameters, mappers, config
  • [async-client-reference](references/async-client-reference.md) - CompletionStage, Reactor, coroutines, transports
  • [error-handling-guide](references/error-handling-guide.md) - exceptions, HttpResponseEntity, status-aware decoding
  • [interceptors-reference](references/interceptors-reference.md) - interceptors, auth, request/response modification
  • [okhttp-transport-reference](references/okhttp-transport-reference.md) - OkHttp config, HTTP versions, proxy

Source of truth: .kora-agent/kora-docs/mkdocs/docs/en/documentation/http-client.md; examples .kora-agent/kora-examples/guides/java/kora-java-guide-http-client-app and kora-java-guide-http-client-advanced-app.

Related skills

  • kora-http-server - inbound @HttpController
  • kora-openapi-generator-client - generate clients from an OpenAPI spec
  • kora-aop-resilient - @Retry, @CircuitBreaker, @Timeout, @Fallback
  • kora-json - @Json DTOs

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.