This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch docs
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/docs by this push:
     new 4a3f736db1 Redesign REST Proxies landing page as a capabilities 
showcase
4a3f736db1 is described below

commit 4a3f736db1a41847b20f16a47a47590f238dd836
Author: James Bognar <[email protected]>
AuthorDate: Sun Jul 26 08:07:25 2026 -0400

    Redesign REST Proxies landing page as a capabilities showcase
    
    - Add end-to-end quick-start walkthrough for @RestProxy-based clients
    - Add annotation-reference table linking out to each sub-page
    - Showcase capabilities: path/query/formdata params, content, request,
      response, and error-handling patterns
    - Document previously-undocumented @Header("*") map form in a new
      dedicated dynamic/multiple-headers section
    - Rename title "REST Proxy" -> "REST Proxies" to match the sidebar label
    
    Co-authored-by: Cursor <[email protected]>
---
 pages/topics/13.09.00.RestProxies.md | 324 ++++++++++++++++++++---------------
 1 file changed, 187 insertions(+), 137 deletions(-)

diff --git a/pages/topics/13.09.00.RestProxies.md 
b/pages/topics/13.09.00.RestProxies.md
index 2d06170405..ac290e20b0 100644
--- a/pages/topics/13.09.00.RestProxies.md
+++ b/pages/topics/13.09.00.RestProxies.md
@@ -1,13 +1,20 @@
 ---
 id: 13.09.RestProxies
-title: "REST Proxy"
+title: "REST Proxies"
 slug: RestProxies
 ---
 
-One of the more powerful features of the REST client class is the ability to 
produce Java interface proxies against
-arbitrary 3rd party REST resources.
+One of the most powerful features of the REST client class is the ability to 
turn a plain Java interface into a
+fully-working client for a 3rd-party REST resource.
 
-The methods to retrieve remote interfaces are:
+You describe the API with a Java interface and a handful of annotations — the 
HTTP method, the path, which
+arguments become headers, query parameters, form data, or the request body, 
and what the response should be parsed
+into.
+<a href="/site/apidocs/org/apache/juneau/rest/client/classic/RestClient.html" 
target="_blank">RestClient</a> then hands you
+back a dynamic proxy that implements the interface, translating every method 
call into an HTTP request and every
+response back into a Java return value.
+
+The methods used to retrieve remote interfaces are:
 
 <tree>
 <node-0><java-class><a 
href="/site/apidocs/org/apache/juneau/rest/client/classic/RestClient.html" 
target="_blank">RestClient</a></java-class></node-0>
@@ -16,20 +23,9 @@ The methods to retrieve remote interfaces are:
 <node-1><java-method><a 
href="/site/apidocs/org/apache/juneau/rest/client/classic/RestClient.html#getRemote(java.lang.Class)"
 
target="_blank">getRemote(Class,Object,Serializer,Parser)</a></java-method></node-1>
 </tree>
 
-Annotations are used on the interface and interface methods to specify how to 
convert input and output to HTTP headers,
-query parameters, form post parameters, or request/response bodies:
+## Quick Start
 
-<tree>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/remote/Remote.html" 
target="_blank">Remote</a></java-annotation> - Applied to interface 
class.</node-0>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/remote/RemoteOp.html" 
target="_blank">RemoteOp</a></java-annotation> - Applied to interface 
methods.</node-0>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/Content.html" 
target="_blank">Content</a></java-annotation></node-0>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/Header.html" 
target="_blank">Header</a></java-annotation></node-0>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/FormData.html" 
target="_blank">FormData</a></java-annotation></node-0>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/Query.html" 
target="_blank">Query</a></java-annotation></node-0>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/Path.html" 
target="_blank">Path</a></java-annotation></node-0>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/Request.html" 
target="_blank">Request</a></java-annotation></node-0>
-<node-0><java-annotation><a 
href="/site/apidocs/org/apache/juneau/http/Response.html" 
target="_blank">Response</a></java-annotation></node-0>
-</tree>
+Define an interface, annotate it, and get a proxy from a `RestClient`:
 
 :::tip Example
 ```java
@@ -42,6 +38,9 @@ public interface PetStore {
         @Header("E-Tag") UUID etag,
         @Query("debug") boolean debug
     );
+
+    @RemoteGet("/pets/{petId}")
+    Pet getPet(@Path("petId") int petId);
 }
 ```
 
@@ -52,13 +51,16 @@ RestClient client = RestClient.create().json5().build();
 // Instantiate our proxy interface.
 PetStore store = client.getRemote(PetStore.class, "http://localhost:10000";);
 
-// Use it to create a pet.
+// Use it to create a pet...
 CreatePet createPet = new CreatePet("Fluffy", 9.99);
 Pet pet = store.addPet(createPet, UUID.randomUUID(), true);
+
+// ...and fetch it back.
+Pet sameCat = store.getPet(pet.getId());
 ```
 :::
 
-The call above translates to the following REST call:
+The `addPet(...)` call above translates to a real HTTP request under the hood:
 
 ```text
 POST http://localhost:10000/petstore/pets?debug=true HTTP/1.1
@@ -72,180 +74,228 @@ E-Tag: 475588d4-0b27-4f56-9296-cc683251d314
 }
 ```
 
-The <a href="/site/apidocs/org/apache/juneau/http/remote/RemoteOp.html" 
target="_blank">@RemoteOp</a> annotations can be eliminated if you use specific 
naming conventions on your method names to identify
-the HTTP method and path.
+No hand-written URL building, serialization, or response parsing required — 
the interface *is* the contract.
 
-:::tip Example
-```java
-@Remote(path="/petstore")
-public interface PetStore {
+:::info See Also
+The <a href="/site/apidocs/org/apache/juneau/http/remote/RemoteOp.html" 
target="_blank">@RemoteOp</a> annotation (and
+its `method`/`path`) can often be skipped entirely if your Java method names 
follow a simple naming convention. See
+[@RemoteOp](/docs/topics/RemoteMethod) for the inference rules.
+:::
 
-    // @RemoteOp optional since method and path is inferred from method name.
-    String postPets(@Content CreatePet pet);
-}
+## Annotation Reference
+
+Method behavior is driven entirely by annotations on the interface, its 
methods, and their parameters:
+
+| Annotation | Applies to | Purpose |
+|---|---|---|
+| [`@Remote`](/docs/topics/Remote) | Interface | Marks the interface as a REST 
proxy; sets the base path, common headers, and client versioning. |
+| [`@RemoteOp`](/docs/topics/RemoteMethod) (and 
`@RemoteGet`/`@RemotePost`/`@RemotePut`/`@RemotePatch`/`@RemoteDelete`) | 
Method | Maps a method to an HTTP verb + path. Often optional if the method 
name implies the verb. |
+| [`@Path`](/docs/topics/Path) | Parameter | URL path variables 
(`{petId}`-style placeholders). |
+| [`@Query`](/docs/topics/Query) | Parameter | Query-string parameters. |
+| [`@Header`](/docs/topics/Header) | Parameter | HTTP request headers — 
including dynamic, multi-value forms. |
+| [`@FormData`](/docs/topics/FormData) | Parameter | 
`application/x-www-form-urlencoded` body parameters. |
+| [`@Content`](/docs/topics/Content) | Parameter | The HTTP request body. |
+| [`@Request`](/docs/topics/Request) | Parameter or class | Bundles multiple 
parts (content/headers/query/etc.) behind a single request bean. |
+| [`@Response`](/docs/topics/Response) | Return type | Bundles 
content/headers/status behind a single response bean. |
+
+Every one of these supports both **single-value** forms (`@Query("limit") int 
limit`) and **dynamic, multi-value**
+forms (`@Query Map<String,Object> params`) — see the [dynamic 
headers](#dynamic-and-multiple-headers) example below
+for the pattern in detail.
+
+## Capabilities Showcase
+
+The sections below are short teasers of what's possible. Each links to a 
deep-dive page with the full set of
+supported types and edge cases.
+
+### Sending data to the server
+
+**Path variables** ([@Path](/docs/topics/Path)) fill in `{placeholders}` in 
the URL:
+
+```java
+@RemoteGet("/pets/{petId}")
+Pet getPet(@Path("petId") int petId);
 ```
-:::
 
-## Default Values
+**Query parameters** ([@Query](/docs/topics/Query)) — and the equivalent for
+[@FormData](/docs/topics/FormData) form posts:
 
-As of Juneau 9.2.0, you can specify default values for method parameters using 
the `def` attribute. Defaults can be specified either at the **method level** 
(on the method itself) or at the **parameter level** (on individual 
parameters). Parameter-level defaults take precedence when both are present.
+```java
+@RemoteGet("/pets")
+Pet[] findPets(@Query("species") String species, @Query("limit") int limit);
+```
 
-### Basic Usage - Parameter-Level Defaults
+#### Dynamic and multiple headers
 
-The most straightforward approach is to specify defaults directly on the 
parameters:
+[@Header](/docs/topics/Header) (and `@Query`/`@FormData`/`@Path`) isn't 
limited to one header per parameter. Leave
+the name off (or use the explicit wildcard `"*"`) and pass a `Map`, a 
`HeaderList`, or a bean — every entry or
+property is expanded into its own header:
 
-:::tip Example
 ```java
 @Remote(path="/petstore")
 public interface PetStore {
 
+    // Every map entry becomes its own header.
     @RemoteGet("/pets")
-    Pet[] getPets(
-        @Header(name="Accept-Language", def="en-US") String language,
-        @Query(name="limit", def="10") Integer limit
-    );
+    Pet[] getPets(@Header("*") Map<String,Object> headers);
+
+    // Same idea via a pre-built HeaderList...
+    @RemoteGet("/pets")
+    Pet[] getPetsViaHeaderList(@Header HeaderList headers);
+
+    // ...or a bean whose properties become individual headers.
+    @RemoteGet("/pets")
+    Pet[] getPetsViaBean(@Header PetHeaders headers);
 }
 ```
 
 ```java
-PetStore store = client.getRemote(PetStore.class, "http://localhost:10000";);
+Map<String,Object> headers = JsonMap.of("X-Client-Id", "acme", "X-Trace-Id", 
UUID.randomUUID());
+Pet[] pets = store.getPets(headers);
+```
 
-// Uses default language="en-US" and limit=10
-Pet[] pets1 = store.getPets(null, null);
+This is a great way to forward a variable, caller-supplied set of headers 
(correlation IDs, feature flags, tenant
+context, etc.) without adding a new interface parameter every time one shows 
up. See
+[@Header](/docs/topics/Header) for the full list of supported dynamic forms.
 
-// Uses custom language, default limit=10
-Pet[] pets2 = store.getPets("fr-FR", null);
+**Request bodies** ([@Content](/docs/topics/Content)) accept any serializable 
POJO, or raw `Reader`/`InputStream`:
 
-// Uses default language="en-US", custom limit
-Pet[] pets3 = store.getPets(null, 25);
+```java
+@RemotePost("/pets")
+Pet addPet(@Content CreatePet pet);
 ```
-:::
 
-The above examples translate to the following REST calls:
+**Request beans** ([@Request](/docs/topics/Request)) bundle several of the 
above behind one argument, so callers pass
+a single object instead of a long parameter list:
 
-```text
-GET http://localhost:10000/petstore/pets?limit=10 HTTP/1.1
-Accept-Language: en-US
+```java
+@RemotePost
+String postPet(CreatePetRequest bean);
+```
+```java
+@Request
+public class CreatePetRequest {
+
+    @Content
+    public CreatePet getContent() { ... }
 
-GET http://localhost:10000/petstore/pets?limit=10 HTTP/1.1
-Accept-Language: fr-FR
+    @Query
+    public Map<String,Object> getQueryParams() { ... }
 
-GET http://localhost:10000/petstore/pets?limit=25 HTTP/1.1
-Accept-Language: en-US
+    @Header("E-Tag")
+    public UUID getUUID() { ... }
+}
 ```
 
-### Supported Annotations
+### Getting results back
 
-Default values are supported on the following annotations:
+Return types are flexible — parsed POJOs, raw streams, async wrappers, or just 
the status code:
 
-- `@Header(name="...", def="...")` - HTTP request headers
-- `@Query(name="...", def="...")` - Query string parameters
-- `@FormData(name="...", def="...")` - Form post parameters
-- `@Path(name="...", def="...")` - Path variables
-- `@Content(def="...")` - Request body (new in 9.2.0)
+```java
+@Remote(path="/petstore")
+public interface PetStore {
 
-### Method-Level Defaults (Alternative Approach)
+    @RemoteGet("/pets")                            Pet[] getPets();            
   // Parsed POJO
+    @RemoteGet(path="/pets", returns=STATUS)        int getPetsStatus();       
    // Just the HTTP status
+    @RemoteGet("/pets")                             Future<Pet[]> 
getPetsAsync();  // Async
+    @RemoteGet("/pets/{petId}")                     InputStream 
getPetRaw(@Path("petId") int petId); // Raw stream
+}
+```
 
-You can also specify defaults at the method level, which can be useful for 
interface-level configuration:
+See [@RemoteOp](/docs/topics/RemoteMethod) for the complete list of supported 
return types.
+
+**Response beans** ([@Response](/docs/topics/Response)) do the same thing in 
reverse — bundle the body, headers, and
+status code of a response behind one typed object:
 
-:::tip Example
 ```java
-@Remote(path="/api")
-public interface MyApi {
-
-    @RemotePost("/resource")
-    @Header(name="X-API-Key", def="default-key")
-    @Header(name="X-Client-Version", def="1.0")
-    @Query(name="format", def="json")
-    @Content(def="{}")
-    String createResource(
-        @Header("X-API-Key") String apiKey,
-        @Header("X-Client-Version") String clientVersion,
-        @Query("format") String format,
-        @Content String data
-    );
+@RemotePost
+CreatePetResponse postPet(@Content CreatePet pet);
+```
+```java
+@Response
+public interface CreatePetResponse {
+
+    @Content Pet getContent();
+    @Header("E-Tag") UUID getUUID();
+    @StatusCode int getStatus();
 }
 ```
 
+**Error handling** happens automatically through checked exceptions. Declare a 
`throws` clause using any of the
+roughly 60 predefined <a 
href="/site/apidocs/org/apache/juneau/http/response/package-summary.html" 
target="_blank">HTTP response exceptions</a>
+(or your own), and Juneau throws the matching one when the server returns that 
status code:
+
 ```java
-// All parameters null - all defaults applied
-String result = api.createResource(null, null, null, null);
-// POST /api/resource?format=json
-// X-API-Key: default-key
-// X-Client-Version: 1.0
-// Content: {}
+@RemoteGet("/pets/{petId}")
+Pet getPet(@Path("petId") int petId) throws NotFound;
+```
 
-// Mix of provided and null values
-String result = api.createResource("my-key", null, "xml", "{data:true}");
-// POST /api/resource?format=xml
-// X-API-Key: my-key
-// X-Client-Version: 1.0
-// Content: {data:true}
+```java
+try {
+    Pet pet = store.getPet(999);
+} catch (NotFound e) {
+    // HTTP 404 was returned - Juneau matched the status to the declared 
exception type.
+}
 ```
-:::
 
-### Precedence: Parameter vs. Method Level
+## Power-User Patterns
 
-When defaults are specified at both the parameter and method level, the 
**parameter-level default takes precedence**:
+### Default Values
 
-:::tip Example
-```java
-@Remote(path="/api")
-public interface MyApi {
+Default values let you specify fallbacks for `null` arguments right on the 
annotation, so callers don't have to
+pass every parameter every time:
 
-    @RemoteGet("/data")
-    @Query(name="format", def="xml")  // Method-level default
-    String getData(
-        @Query(name="format", def="json") String format  // Parameter-level 
default (takes precedence)
-    );
-}
+```java
+@RemoteGet("/pets")
+Pet[] getPets(
+    @Header(name="Accept-Language", def="en-US") String language,
+    @Query(name="limit", def="10") Integer limit
+);
 ```
 
 ```java
-// Uses parameter-level default: format=json
-String result = api.getData(null);
+// Uses default language="en-US" and limit=10.
+Pet[] pets = store.getPets(null, null);
 ```
-:::
 
-This precedence allows you to:
-- Define common defaults at the method level for multiple parameters
-- Override specific parameters with more specific defaults at the parameter 
level
-- Keep your interface clean by placing defaults where they're most relevant
+`def` is supported on [@Header](/docs/topics/Header), 
[@Query](/docs/topics/Query), [@FormData](/docs/topics/FormData),
+[@Path](/docs/topics/Path), and [@Content](/docs/topics/Content), at either 
the parameter or method level (parameter
+wins when both are set).
 
-### Content Body Defaults
+### Dual-Purpose Interfaces
 
-The `@Content` annotation now supports a `def` attribute for specifying a 
default request body:
+The *same* Java interface can define both the client proxy and the server 
implementation, so a signature change is
+caught by the compiler on both sides instead of drifting apart at runtime:
 
-:::tip Example
 ```java
 @Remote(path="/petstore")
 public interface PetStore {
-
-    @RemotePost("/pets")
-    @Content(def="{name:'Unknown',price:0}")
-    Pet addPet(@Content CreatePet pet);
+    @RemoteGet("/pet")
+    Collection<Pet> getPets() throws NotAcceptable;
 }
 ```
-
 ```java
-// When pet is null, sends default JSON
-Pet result = store.addPet(null);
-// POST /petstore/pets
-// Content-Type: application/json
-// Content: {name:'Unknown',price:0}
+@Rest(path="/petstore")
+public class PetStoreResource extends BasicRestServlet implements PetStore {
+    @Override
+    @RestOp(method=GET, path="/pet")
+    public Collection<Pet> getPets() throws NotAcceptable {
+        return store.getPets();
+    }
+}
 ```
-:::
 
-### Use Cases
-
-Default values are particularly useful for:
-
-1. **API Keys and Authentication**: Provide default credentials that can be 
overridden per call
-2. **Versioning**: Specify default API versions
-3. **Pagination**: Set default page sizes and limits
-4. **Content Negotiation**: Specify default content types and languages
-5. **Feature Flags**: Enable/disable features with default values
-
-:::note
-Default values are only applied when the parameter value is `null`. Empty 
strings, zero values, and empty collections are considered valid values and 
will not trigger the default.
-:::
\ No newline at end of file
+See [Dual-purpose (end-to-end) interfaces](/docs/topics/DualPurposeInterfaces) 
for the full walkthrough, including how
+parameter-level annotations like `@Header` and `@Path` are inherited from the 
interface for free.
+
+:::info See Also
+- [@Remote](/docs/topics/Remote) - Interface-level configuration: base path, 
common headers, versioning.
+- [@RemoteOp](/docs/topics/RemoteMethod) - HTTP method/path mapping, 
naming-convention inference, return types.
+- [@Content](/docs/topics/Content) - The request body.
+- [@FormData](/docs/topics/FormData) - Form post parameters.
+- [@Query](/docs/topics/Query) - Query-string parameters.
+- [@Header](/docs/topics/Header) - Request headers, including 
dynamic/multi-value forms.
+- [@Path](/docs/topics/Path) - URL path variables.
+- [@Request](/docs/topics/Request) - Bean-style bundling of request parts.
+- [@Response](/docs/topics/Response) - Bean-style bundling of response parts.
+- [Dual-purpose (end-to-end) interfaces](/docs/topics/DualPurposeInterfaces) - 
Sharing one interface between client and server.
+:::

Reply via email to