agentsclimarketplace

Kora http server

Skill kora-projects/kora-skills/plugins/kora-v1/skills/kora-http-server

Agent Skills for Kora Framework — compile-time DI for Java/Kotlin backend development.

Install
npx -y skills add kora-projects/kora-skills --skill kora-http-server

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Builds Kora HTTP server controllers on the Undertow transport — @HttpController, @HttpRoute, parameter binding (@Path/@Query/@Header/@Cookie), @Json bodies, HttpServerResponse / HttpResponseEntity responses, HttpServerResponseException errors, and HttpServerInterceptor (global via @Tag(HttpServerModule.class) or per-route via @InterceptWith). Use when building REST endpoints, mapping requests to typed methods, returning custom status codes/headers, handling errors centrally, or wiring UndertowHttpServerModule and httpServer ports/telemetry.

SKILL.md

12.4 KB, as published. Nobody here has run it

Kora HTTP Server

Declarative HTTP request handlers compiled (not reflected) into a router. Annotate a @Component @HttpController with @HttpRoute methods; Kora generates the handler/router at build time via the annotation processor.

The base path lives on @HttpRoute, not on @HttpController@HttpController takes no path argument.


Quick Start

1. Dependencies (Java)

configurations {
    koraBom
    annotationProcessor.extendsFrom(koraBom)
    implementation.extendsFrom(koraBom)
}

dependencies {
    koraBom platform("ru.tinkoff.kora:kora-parent:1.2.17")
    annotationProcessor "ru.tinkoff.kora:annotation-processors"  // mandatory

    implementation "ru.tinkoff.kora:http-server-undertow"
    implementation "ru.tinkoff.kora:json-module"
    implementation "ru.tinkoff.kora:config-hocon"
    implementation "ru.tinkoff.kora:logging-logback"
}

Kotlin uses KSP instead: ksp "ru.tinkoff.kora:symbol-processors". All ru.tinkoff.kora:* artifacts inherit their version from the BOM — never pin them individually.

2. Application graph

@KoraApp
public interface Application extends
        HoconConfigModule,
        JsonModule,
        LogbackModule,
        UndertowHttpServerModule {

    static void main(String[] args) {
        KoraApplication.run(ApplicationGraph::graph);
    }
}

3. Controller

@Component
@HttpController
public final class HelloController {

    @HttpRoute(method = HttpMethod.GET, path = "/hello/{name}")
    public String hello(@Path String name) {
        return "Hello " + name;   // 200 OK, text/plain
    }
}

4. Config (application.conf)

httpServer {
  publicApiHttpPort = 8080   // application traffic
  privateApiHttpPort = 8085  // metrics / probes
  telemetry.logging.enabled = true
}

CRUD controller

Adapted from kora-java-guide-http-server-app. JSON requires @Json on the method and on the body parameter; optional inputs are marked @Nullable (Kotlin: a nullable type).

@Component
@HttpController
public final class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @HttpRoute(method = HttpMethod.GET, path = "/users/{userId}")
    @Json
    public UserResponse getUser(@Path String userId) {
        return userService.getUser(userId)
                .orElseThrow(() -> HttpServerResponseException.of(404, "User not found: " + userId));
    }

    @HttpRoute(method = HttpMethod.GET, path = "/users")
    @Json
    public List<UserResponse> getUsers(@Nullable @Query("page") Integer page,
                                       @Nullable @Query("size") Integer size) {
        return userService.getUsers(page == null ? 0 : page, size == null ? 10 : size);
    }

    @HttpRoute(method = HttpMethod.POST, path = "/users")
    @Json
    public HttpResponseEntity<UserResponse> createUser(@Json UserRequest request) {
        UserResponse user = userService.createUser(request);
        return HttpResponseEntity.of(201, HttpHeaders.of("Location", "/users/" + user.id()), user);
    }

    @HttpRoute(method = HttpMethod.DELETE, path = "/users/{userId}")
    public HttpServerResponse deleteUser(@Path String userId) {
        userService.deleteUser(userId);
        return HttpServerResponse.of(204, HttpBody.empty());
    }
}

DTOs are plain records annotated @Json: UserRequest(String email, String name), UserResponse(String id, String email, String name).


Key annotations

AnnotationLevelPurpose
@HttpControllerclassMarks an HTTP controller (no path argument)
@HttpRoute(method, path)methodBinds an HttpMethod + path to a handler
@PathparameterPath segment {name}; name defaults to the argument name
@QueryparameterQuery parameter; name defaults to the argument name
@HeaderparameterRequest header value
@CookieparameterCookie value
@Jsonmethod / parameterJSON serialization for the body
@Mapping(X.class)parameter / methodCustom request/response mapper
@InterceptWith(X.class)method / classApply an interceptor to a route or controller
@NullableparameterMarks a request parameter optional (Java)

HttpMethod values: GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD, TRACE.


Response types

Return typeStatusNotes
String / byte[] / ByteBuffer200Body written directly with the matching content type
T + @Json on method200Body serialized to JSON
HttpResponseEntity<T> + @JsonanyBody + custom status code + headers
HttpServerResponseanyFull control over status, headers and raw body
// JSON body with custom status and headers
return HttpResponseEntity.of(201, HttpHeaders.of("Location", "/users/" + id), user);

// Full manual control
return HttpServerResponse.of(200, HttpHeaders.of("X-Trace", traceId), HttpBody.plaintext("OK"));
return HttpServerResponse.of(204, HttpBody.empty());

Async signatures are supported: Java CompletionStage<T> / Mono<T>, Kotlin suspend fun.

See Response Types for HttpBody, HttpHeaders, and custom HttpServerResponseMapper.


Error handling

Throw HttpServerResponseException.of(code, message) from a handler to short-circuit with a status code. Centralize cross-cutting error translation in a global interceptor (there is no dedicated "exception handler" type — error handling is an interceptor concern).

@HttpRoute(method = HttpMethod.GET, path = "/users/{id}")
@Json
public UserResponse get(@Path String id) {
    return userService.find(id)
        .orElseThrow(() -> HttpServerResponseException.of(404, "Not found: " + id));
}

See Error Handling for the global error interceptor.


Interceptors

HttpServerInterceptor.intercept(Context, HttpServerRequest, InterceptChain) returns CompletionStage<HttpServerResponse>. Call chain.process(context, request) to continue the chain; wrap it with .whenComplete(...) / .exceptionally(...) for after/error logic.

@Tag(HttpServerModule.class)   // makes it global (only one global interceptor allowed)
@Component
public final class LoggingInterceptor implements HttpServerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(LoggingInterceptor.class);

    @Override
    public CompletionStage<HttpServerResponse> intercept(Context context,
                                                         HttpServerRequest request,
                                                         InterceptChain chain) throws Exception {
        long started = System.nanoTime();
        return chain.process(context, request).whenComplete((response, error) -> {
            long ms = (System.nanoTime() - started) / 1_000_000;
            int code = response != null ? response.code() : 500;
            log.info("{} {} -> {} ({} ms)", request.method(), request.path(), code, ms);
        });
    }
}

Scopes:

  • Global — one interceptor tagged @Tag(HttpServerModule.class), runs for every route.
  • Controller@InterceptWith(X.class) on the controller class.
  • Method@InterceptWith(X.class) on a single @HttpRoute method.

Order: global -> controller -> method -> handler.

See Interceptors.


Authentication & Principal

For custom authentication in Kora 1.2.x, use the interceptor pattern — do NOT use Principal as a controller parameter (not auto-wired in 1.2.x, causes 401→400 downgrade).

Pattern: Global @Tag(HttpServerModule) interceptor → store principal in Context → read via Principal.current() in controller.

See Authentication & Principal for complete guide with examples.


Context Propagation

Pass computed values from interceptor to controller (auth session, user profile, request metadata) via ru.tinkoff.kora.common.Context:

  1. Define Context.Key<T> static singleton
  2. Interceptor sets value BEFORE chain.process()
  3. Controller reads with null-check

See Context Propagation for complete guide.


Configuration

httpServer {
  publicApiHttpPort = 8080
  privateApiHttpPort = 8085
  privateApiHttpMetricsPath  = "/metrics"
  privateApiHttpReadinessPath = "/system/readiness"
  privateApiHttpLivenessPath  = "/system/liveness"
  virtualThreadsEnabled = false   // true requires Java 21+
  maxRequestBodySize = "256MiB"
  telemetry {
    logging { enabled = false }
    metrics { enabled = true }
    tracing { enabled = true }
  }
}

Keep publicApiHttpPort (traffic) and privateApiHttpPort (metrics/probes) separate. See Configuration for every key and env substitution.


References

ReferenceCovers
Controller & Routing@HttpController, @HttpRoute, path composition
Request Mapping@Path, @Query, @Header, @Cookie, @Json, bodies, @Mapping
Response TypesHttpServerResponse, HttpResponseEntity, HttpBody, mappers
InterceptorsHttpServerInterceptor, @InterceptWith, @Tag, order
Error HandlingHttpServerResponseException, global error interceptor
ConfigurationhttpServer keys, ports, telemetry, env vars
Authentication & PrincipalCustom auth via interceptor, Principal pattern (Kora 1.2.x)
Context PropagationPassing values from interceptor to controller via Context

Assets

TemplatePurpose
UserController.javaCRUD controller (Java)
UserController.ktCRUD controller (Kotlin)
LoggingInterceptor.javaGlobal logging interceptor (Java)
LoggingInterceptor.ktGlobal logging interceptor (Kotlin)
ErrorInterceptor.javaGlobal error-to-JSON interceptor (Java)

Pitfalls

SymptomFix
404 on a valid URLThe {var} in @HttpRoute path must have a matching @Path argument; base path lives on @HttpRoute, not @HttpController
Request body is null / not parsedAdd @Json on the method and on the body parameter, and depend on json-module
@HttpController("/api") does not compile@HttpController takes no value; put the prefix in each @HttpRoute(path = "/api/...")
Required parameter throws when missingMark it @Nullable (Java) or use a nullable type (Kotlin)
Global interceptor never runsAdd @Tag(HttpServerModule.class) and @Component; only one global interceptor is allowed
Looking for HttpServerResponse.ok() builderIt does not exist — use HttpServerResponse.of(...) / HttpResponseEntity.of(...)
Principal as controller parameter returns 400Kora 1.2.x doesn't auto-bridge HttpServerPrincipalExtractor — use interceptor + Context pattern (see Authentication)
Context.get() returns null in controllerValue must be set in interceptor BEFORE chain.process(); add null-check (see Context Propagation)

Evals

Self-check rubric: evals/evals.json.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.