Agent Skills: GuicedEE REST Client

Annotation-driven REST client for GuicedEE using Vert.x 5 WebClient: @Endpoint declarations, RestClient<Send, Receive> injection, authentication strategies (Bearer, Basic, API Key, OAuth2, mTLS), path parameters, environment variable overrides, package-level endpoints, service registry integration (bare name or registry: prefix), and RestClientConfigurator SPI. Use when making outbound REST calls, configuring REST client endpoints, or wiring reactive HTTP clients with Guice injection.

UncategorizedID: GuicedEE/ai-rules/guicedee-rest-client

Install this agent skill to your local

pnpm dlx add-skill https://github.com/GuicedEE/ai-rules/tree/HEAD/skills/.system/guicedee-rest-client

Skill Files

Browse the full folder contents for guicedee-rest-client.

Download Skill

Loading file tree…

skills/.system/guicedee-rest-client/SKILL.md

Skill Metadata

Name
guicedee-rest-client
Description
"Annotation-driven REST client for GuicedEE using Vert.x 5 WebClient: @Endpoint declarations, RestClient<Send, Receive> injection, authentication strategies (Bearer, Basic, API Key, OAuth2, mTLS), path parameters, environment variable overrides, package-level endpoints, service registry integration (bare name or registry: prefix), and RestClientConfigurator SPI. Use when making outbound REST calls, configuring REST client endpoints, or wiring reactive HTTP clients with Guice injection."

GuicedEE REST Client

Annotation-driven REST client using the Vert.x 5 WebClient, fully managed by GuicedEE.

Core Concept

Declare an @Endpoint on any RestClient<Send, Receive> field, add @Named, and inject — URL, HTTP method, authentication, timeouts, and connection options are all driven from the annotation. Every call returns a Uni<Receive> for fully reactive composition.

Required Flow

  1. Add com.guicedee:rest-client dependency.
  2. Configure module-info.java:
    module my.app {
        requires com.guicedee.rest.client;
        opens my.app.clients to com.google.guice, com.guicedee.rest.client;
        opens my.app.dto to com.fasterxml.jackson.databind;
    }
    
  3. Declare a REST client field with @Endpoint:
    public class UserService {
        @Endpoint(url = "https://api.example.com/users", method = "POST",
                  security = @EndpointSecurity(value = SecurityType.Bearer,
                                               token = "${API_TOKEN}"))
        @Named("create-user")
        private RestClient<CreateUserRequest, UserResponse> createUserClient;
    
        public Uni<UserResponse> createUser(CreateUserRequest request) {
            return createUserClient.send(request);
        }
    }
    
  4. Once defined, inject the same client elsewhere by name only:
    public class OrderService {
        @Inject @Named("create-user")
        private RestClient<CreateUserRequest, UserResponse> client;
    }
    

Service Registry Integration

When service-registry is on the classpath, URLs auto-resolve from the registry (no hard dependency):

// 1. Explicit registry: prefix — always resolves from registry
@Endpoint(url = "registry:jwebmp-website")
@Named("jwebmp") private RestClient<Void, Response> client;

// 2. Bare service name — if registered, uses registry URL
@Endpoint(url = "jwebmp-website")
@Named("jwebmp") private RestClient<Void, Response> client;

// 3. Full URL — passes through unchanged
@Endpoint(url = "https://api.example.com/v1")
@Named("example") private RestClient<Void, Response> client;

Resolution logic in RestClientRegistry.resolveUrl():

  1. Resolves ${ENV_VAR} placeholders first
  2. If starts with registry: → resolves via ServiceRegistry.resolve()
  3. If bare name (no ://, no / prefix) → tries registry, falls back to original value
  4. Uses reflection — no compile-time dependency on service-registry module

Sending Requests

client.send();                           // no body
client.send(body);                       // with body
client.send(body, headers, queryParams); // with headers and query params
client.publish(body);                    // fire-and-forget (no response)

All methods return Uni<Receive>.

Path Parameters

Use {paramName} placeholders in the endpoint URL:

@Endpoint(url = "https://api.example.com/users/{userId}", method = "GET")
@Named("get-user")
private RestClient<Void, UserResponse> getUserClient;

// Usage
getUserClient.pathParam("userId", "123").send();

Authentication

| Strategy | Annotation | |---|---| | Bearer/JWT | @EndpointSecurity(value = SecurityType.Bearer, token = "${API_TOKEN}") | | Basic | @EndpointSecurity(value = SecurityType.Basic, username = "user", password = "${PASSWORD}") | | API Key | @EndpointSecurity(value = SecurityType.ApiKey, apiKey = "${API_KEY}", apiKeyHeader = "X-API-Key") | | OAuth2 | @EndpointSecurity(value = SecurityType.OAuth2, oauth2TokenUrl = "...", oauth2ClientId = "...", oauth2ClientSecret = "${SECRET}") | | mTLS | @EndpointSecurity(value = SecurityType.ClientCert, clientCertPath = "...", clientCertPassword = "${CERT_PASS}") |

Package-Level Endpoints

Declare a shared base URL on package-info.java:

@Endpoint(url = "http://localhost:8080/api",
          options = @EndpointOptions(readTimeout = 1000))
package com.example.api;

Field-level URLs starting with / are appended to the package-level base URL.

Environment Variable Overrides

Every annotation attribute can be overridden via REST_CLIENT_* environment variables without code changes.

Startup Flow

IGuiceContext.instance().inject()
 └─ RestClientPreStartup (scans for @Endpoint-annotated fields)
 └─ RestClientBinder (binds RestClient instances per @Named endpoint)
     ├─ RestClientRegistry (metadata: URL, types, security, options)
     ├─ WebClient cache (one per endpoint)
     └─ RestClientConfigurator SPI (custom WebClientOptions)

Non-Negotiable Constraints

  • Client packages must opens to com.google.guice and com.guicedee.rest.client.
  • DTO packages must opens to com.fasterxml.jackson.databind.
  • Module must requires transitive com.guicedee.rest.client;.
  • Only one @Endpoint field is needed per named endpoint; other classes inject by @Named alone.
  • RestClientConfigurator SPI implementations must be dual-registered for tests.