juneau-rest-server
| Maven | |
|---|---|
| Jar | juneau-rest-server-10.0.0.jar |
| OSGi | org.apache.juneau.rest.server_10.0.0.jar |
| Links | Maven Central · Javadocs · Source |
The juneau-rest-server library allows you to quickly wrap POJOs and expose them as full-fledged REST resources served up
in a servlet container using a bare-minimum amount of code.
The primary goal for Juneau was to make it as easy as possible to implement easy-to-read and self-documenting REST resources using very little code.
One of the biggest advantages of the Juneau REST framework over similar architectures is that it hides the serialization layer from the developer.
The developer can work entirely with POJOs and let the Juneau framework handle all the serialization and parsing work.
The developer need never know what the Accept or Content-Type or Accept-Encoding (etc...) header values are
because those details are all handled by the framework.
The API builds upon the existing JEE Servlet API.
The root class, RestServlet is nothing but a specialized HttpServlet, and the RestRequest and RestResponse classes are nothing more than specialized HttpServletRequest and HttpServletResponse objects.
This allows maximum flexibility for the developer since you can let Juneau handle operations such as serialization, or you can revert to the existing servlet APIs to do low-level processing of requests yourself.
It also means you need nothing more than a Servlet container such as Jetty to use the REST framework.
Contents/Features
- Deployable in standard Servlet containers.
- Deployable in Spring Boot environments with full support for injected beans.
- Serializes POJOs to any format registered on the resource (JSON, XML, HTML, URL-Encoding, UON, OpenAPI, and
more by default; RDF via
juneau-rest-server-rdf), chosen by theAcceptheader. No user code is required to handle these types.- Extensible design that provides ability to override existing content type handlers, or add the ability to handle other kinds of content types.
- Parses content of
POST/PUTrequest bodies to POJOs. - Automatic built-in ability to serialize POJO metadata to JSON+SCHEMA, XML+SCHEMA, or HTML+SCHEMA based on
Acceptheader. - Automatic negotiation of output Writer based on HTTP headers.
- Automatic handling of
Accept-Charsetheader for all character sets supported by the JVM. - Automatic handling of
Accept-Encodingheader with registered encoders.
- Automatic handling of
- Automatic error handling.
- Automatic 401 errors (Unauthorized) on failed guards.
- Automatic 404 errors (Not Found) on unmatched path patterns.
- Automatic 405 errors (Method Not Implemented) on unimplemented methods.
- Automatic 406 errors (Not Acceptable) when no matching serializer was found to handle the Accept header.
- Automatic 412 errors (Precondition Failed) when all matchers failed to match.
- Automatic 415 errors (Unsupported Media Type) when no matching parser was found was found to handle the Content-Type header.
- Automatic 500 errors on uncaught exceptions.
- Support for parsing all HTTP parts (
headers,query,formData,pathvariables) usingSwaggerformatting rules and validations. Not limited to simple POJOs but rather you can represent arbitrarily-complex POJOs in any HTTP part using UON notation. - Auto-created Swagger UI at
/swagger(Swagger v2 JSON at/api, OpenAPI 3.1 at/openapi). - Various useful debugging features that make debugging using a browser extremely simple...
- Ability to pass HTTP header values as URL
GETparameters (e.g.&Accept=text/xml). - Ability to pass HTTP content on
PUT/POSTrequests as a URL GET parameter (e.g.&content=(foo=bar)). - Ability to simulate other methods from a
POSTusing a&methodparameter (e.g.&method=PATCH); aGETcan only be overridden to a safe or read method. - Ability to force
text/plainon response using GET parameter&plainText=true.
- Ability to pass HTTP header values as URL
- Ability to implement overloaded HTTP methods through the use of the
&methodattribute (e.g.&method=FOO). On aGET, only operations declared@RestOp(read=true)can be reached this way. - Ability to match URL patterns (e.g.
/foo/{fooId}/bar/{barId}) against URLs (e.g./foo/123/bar/456/bing). - Ability to associate guards at the resource or method levels through annotations. Typically useful for security but can be used for a variety of purposes.
- Ability to associate converters at the resource or method levels through annotations. Typically useful for performing conversions on input and output, such as for supporting older input and output formats.
Many of the examples in this document are pulled directly from the juneau-petstore showcase application.
@Rest-Annotated Resources
A REST resource is simply a Java class annotated with Rest. The most common case is a class that extends BasicRestServlet, which itself is simply an extension of HttpServlet which allows it to be deployed as a servlet.
For the complete, up-to-date list of @Rest members, see @Rest-Annotated Class.
// Sample REST resource that prints out a simple "Hello world!" message.
@Rest(
path="/helloWorld",
title="Hello World",
description="An example of the simplest-possible resource"
)
@HtmlDocConfig(
navlinks={
"up: request:/..",
"options: servlet:/?method=OPTIONS"
},
aside={
"This page shows a resource that simply response with a 'Hello world!' message",
"The POJO serialized is a simple String.",
}
)
public class HelloWorldResource extends BasicRestServlet {
@RestGet(path="/*", summary="Responds with \"Hello world!\"")
public String sayHello() {
return "Hello world!";
}
}
Requesting /helloWorld from a browser returns the string wrapped in the standard HTML page: the title and
description in the header, the navigation links, the aside text, and Hello world! as the body.
- Parsers for request bodies are selected based on the request
Content-Typeheader. - Serializers for response bodies are selected based on the request
Acceptheader. - In this case, it's the HtmlDocSerializer serializer based on the browser's default
Acceptheader that's asking for HTML.
REST resource classes and methods can be annotated with configuration annotations for the serializers and parsers (such
as @HtmlConfig and @MarshalledConfig shown above).
- Annotations such as the title, summary, and descriptions shown above are used for auto-generated Swagger UI pages (described later).
REST Children
Child Resources are REST servlets or objects that are linked to parent resources through the @Rest(children) annotation.
/** Parent Resource */
@Rest(
path="/parent",
children={
MyChildResource.class
}
)
public class MyParentResource extends BasicRestServlet {...}
/** Child Resource */
@Rest(
path="/child" // Path relative to parent resource.
)
// Note that we don't need to extend from RestServlet.
public class MyChildResource extends BasicRestResource {
...
}
A child extends BasicRestResource, not BasicRestServlet; see Servlet or Resource?.
The path of the child resource gets appended to the path of the parent resource. So in the example above, the child resource is accessed through the URL /parent/child.
The advantage of using child resources is that they do not need to be declared in the JEE web.xml file.
Initialization of and access to the child resources occurs through the parent resource.
Children can be nested arbitrary deep to create complex REST interfaces with a single top-level REST servlet.
Predefined Configuration Interfaces
The servlets in the previous section implemented the BasicUniversalConfig which simply defines a preconfigured set of annotations that get inherited by the child classes:
/**
* Predefined configuration for a REST resource that supports all languages
* and provides common default configuration values.
*/
@Rest(
// Default serializers for all Java methods in the class.
serializers={
HtmlDocSerializer.class,
HtmlStrippedDocSerializer.class,
HtmlSchemaDocSerializer.class,
JsonSerializer.class,
Json5Serializer.class,
JsonSchemaSerializer.class,
XmlDocSerializer.class,
UonSerializer.class,
UrlEncodingSerializer.class,
OpenApiSerializer.class,
MsgPackSerializer.class,
SoapXmlSerializer.class,
PlainTextSerializer.class,
CsvSerializer.class
},
// Default parsers for all Java methods in the class.
parsers={
JsonParser.class,
Json5Parser.class,
XmlParser.class,
HtmlParser.class,
UonParser.class,
UrlEncodingParser.class,
OpenApiParser.class,
MsgPackParser.class,
PlainTextParser.class,
CsvParser.class
}
)
public interface BasicUniversalConfig extends DefaultConfig, DefaultHtmlConfig {}
/**
* Predefined REST configuration that defines common default values for all configurations.
*/
@Rest(
// Configuration file.
config="$S{j.configFile,$E{J_CONFIG_FILE,SYSTEM_DEFAULT}}",
// Standard fields.
path="",
roleGuard="",
rolesDeclared="",
// Configuration beans.
converters={},
encoders={IdentityEncoder.class},
guards={},
parsers={},
partParser=OpenApiParser.class,
partSerializer=OpenApiSerializer.class,
responseProcessors={
ReaderProcessor.class,
InputStreamProcessor.class,
ThrowableProcessor.class,
HttpResponseProcessor.class,
HttpResourceProcessor.class,
HttpBodyProcessor.class,
ResponseBeanProcessor.class,
PlainTextPojoProcessor.class,
SerializedPojoProcessor.class
},
restOpArgs={
AttributeArg.class,
ContentArg.class,
FormDataArg.class,
HasFormDataArg.class,
HasQueryArg.class,
HeaderArg.class,
HttpServletRequestArgs.class,
HttpServletResponseArgs.class,
HttpSessionArgs.class,
InputStreamParserArg.class,
MethodArg.class,
ParserArg.class,
PathArg.class,
QueryArg.class,
ReaderParserArg.class,
RequestBeanArg.class,
ResponseBeanArg.class,
ResponseHeaderArg.class,
ResponseCodeArg.class,
RestContextArgs.class,
RestSessionArgs.class,
RestOpContextArgs.class,
RestOpSessionArgs.class,
RestRequestArgs.class,
RestResponseArgs.class,
DefaultArg.class
},
serializers={},
// Configurable settings.
allowedHeaderParams="$S{j.allowedHeaderParams,$E{J_ALLOWED_HEADER_PARAMS,Accept,Content-Type}}",
allowedMethodHeaders="$S{j.allowedMethodHeaders,$E{J_ALLOWED_METHOD_HEADERS,}}",
allowedMethodParams="$S{j.allowedMethodParams,$E{J_ALLOWED_METHOD_PARAMS,HEAD,OPTIONS}}",
clientVersionHeader="$S{j.clientVersionHeader,$E{J_CLIENT_VERSION_HEADER,Client-Version}}",
defaultAccept="$S{j.defaultAccept,$E{J_DEFAULT_ACCEPT,}}",
defaultCharset="$S{j.defaultCharset,$E{J_DEFAULT_CHARSET,UTF-8}}",
defaultContentType="$S{j.defaultContentType,$E{J_DEFAULT_CONTENT_TYPE,}}",
defaultRequestAttributes="$S{j.defaultRequestAttributes,$E{J_DEFAULT_REQUEST_ATTRIBUTES,}}",
defaultRequestHeaders="$S{j.defaultRequestHeaders,$E{J_DEFAULT_REQUEST_HEADERS,}}",
defaultResponseHeaders="$S{j.defaultResponseHeaders,$E{J_DEFAULT_RESPONSE_HEADERS,}}",
disableContentParam="$S{j.disableContentParam,$E{J_DISABLE_CONTENT_PARAM,false}}",
maxInput="$S{j.maxInput,$E{J_MAX_INPUT,1000000}}",
messages="$S{j.messages,$E{J_MESSAGES,}}",
renderResponseStackTraces="$S{j.renderResponseStackTraces,$E{J_RENDER_RESPONSE_STACK_TRACES,false}}",
uriAuthority="$S{j.uriAuthority,$E{J_URI_AUTHORITY,}}",
uriContext="$S{j.uriContext,$E{J_URI_CONTEXT,}}",
uriRelativity="$S{j.uriRelativity,$E{J_URI_RELATIVITY,}}",
uriResolution="$S{j.uriResolution,$E{J_URI_RESOLUTION,}}",
// Metadata settings.
consumes={},
description="",
produces={},
siteName="$S{j.siteName,$E{J_SITE_NAME,}}",
swagger=@Swagger,
title="$S{j.title,$E{J_TITLE,}}",
// Injectable/overridable beans.
staticFiles=StaticFiles.Void.class, // Defaults to BasicStaticFiles.
swaggerProvider=SwaggerProvider.Void.class // Defaults to BasicSwaggerProvider.
)
@MarshalledConfig(
// When parsing generated beans, ignore unknown properties
// that may only exist as getters and not setters.
ignoreUnknownBeanProperties="true",
ignoreUnknownEnumValues="true"
)
@SerializerConfig(
// Enable automatic resolution of URI objects to root-relative values.
uriResolution="ROOT_RELATIVE"
)
public interface DefaultConfig {}
Request/response debug capture is no longer an @Rest attribute — it's driven by the resource's own JUL logger
level. See Logging / Debugging.
/**
* Predefined REST configuration that defines common default values the HTML Doc serializer.
*/
@HtmlDocConfig(
// Default page header contents.
header={
"$RS{title}", // Use @Rest(title)
"$RS{operationSummary,description}", // Use either @RestOp(summary) or @Rest(description)
"$C{REST/header}" // Extra header HTML defined in external config file.
},
// Basic page navigation links.
navlinks={
"up: request:/.."
},
// Default stylesheet to use for the page.
// Can be overridden from external config file.
// Default is DevOps look-and-feel (aka Depression look-and-feel).
stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}",
// Default contents to add to the section of the HTML page.
// Use it to add a favicon link to the page.
head="$C{REST/head}",
// No default page footer contents.
// Can be overridden from external config file.
footer="$C{REST/footer}",
// By default, table cell contents should not wrap.
nowrap="true"
)
public interface DefaultHtmlConfig {}
The org.apache.juneau.rest.server.config package contains other basic configurations for use. Annotations are aggregated from child-to-parent order allowing for these basic configurations to be extended and modified, or you can create your own annotations from scratch.
REST Group Pages
The BasicRestServletGroup class provides a default "router" page for child resources when a parent resource is nothing more than a grouping of child resources. The RootResources class in the Samples project is an example of a router page:
/**
* Sample REST resource showing how to implement a "router" resource page.
*/
@Rest(
path="/",
title="Root resources",
description="Example of a router resource page.",
children={
HelloWorldResource.class,
PetStoreResource.class,
DtoExamples.class,
ConfigResource.class,
LogsResource.class,
ShutdownResource.class
}
)
public class RootResources extends BasicRestServletGroup {
// NO CODE!!!
}
ConfigResource, LogsResource, and ShutdownResource are demo admin resources that live in the unpublished
juneau-microservice-examples module (package org.apache.juneau.microservice.examples) rather than in
juneau-microservice itself — see Predefined Resource Classes. They change
state, so register their AdminBoundary CSRF filter wherever a browser can reach them, as described in
Protecting the admin resources.
When you bring up this resource in a browser, the page lists each child resource by path, title and description, as a navigable link.
REST Resource Methods
The real power behind the REST server API is the ability to define Java methods as REST endpoints.
@RestPost(path="/pets", guards=AdminGuard.class)
public Ok addPet(
@Content CreatePet createPetBean,
@Header("E-Tag") UUID etag,
@Query("debug") boolean debug
) throws BadRequest, Unauthorized, InternalServerError {
// Process request.
return Ok.OK;
}
Java methods on @Rest-annotated classes have the following format:
@RestOp(method="...", path="...")
public method() throws {
...
}
The various parts require their own topics to fully appreciate the scope of abilities but the following is a summary:
- Annotated with @RestOp.
- Also available: @RestGet / @RestPut / @RestPost / @RestDelete.
- Annotation optional if using standard naming conventions (e.g.
getFoo()equivalent to@RestGet(path="/foo")). - Optionally annotated with config annotations such as @MarshalledConfig and @HtmlDocConfig that customize the behavior of serializers and parsers at the method level.
- Returned object gets serialized as the HTTP response body.
- Typically a POJO serialized based on Accept request header.
- Support for raw values such as
ReadersandInputStreams(among others). - Support for response beans annotated with @Response.
- Support for Apache Http Core interfaces: HttpEntity / HttpResponse / HttpResource.
- Standard HTTP responses such as Ok and TemporaryRedirect provided in org.apache.juneau.http.response package.
- Extensible API for defining custom return types.
- A wide range of possible argument types including:
- Standard HttpServletRequest / HttpServletResponse objects.
- Extended RestRequest / RestResponse objects.
- Parsed HTTP parts with either the arguments or beans annotated with @Path / @Header / @Query / @FormData.
- Parsed HTTP body with either the argument or bean annotated with @Content.
- Raw HTTP request body with
InputStreamorReader. - Raw HTTP response body with
OutputStreamorWriter. - Request beans annotated with @Request.
- Response beans annotated with @Response.
- Standard HTTP headers such as Accept and ContentType provided in org.apache.juneau.http.header package.
- Auto-generated Swagger.
- Various other standard objects such as Principal, Cookie, HttpSession, and ResourceBundle.
- Spring beans or other injectable beans.
- Extensible API for defining custom argument types.
- Throwables can be anything.
- Typically one of the standard HTTP responses such as BadRequest or NotFound provided in org.apache.juneau.http.response package.
- Can define your own @Response-annotated throwables.
- Anything else gets converted to an InternalServerError.
Deploying as a Servlet
The BasicRestServlet class is the entry point for
your REST resources.
It extends directly from HttpServlet and is deployed like any other servlet (such as a standard web.xml file).
When the servlet init() method is called, it triggers the code to find and process the @Rest annotations on that class
and all child classes.
These get constructed into a RestContext object that holds all
the configuration information about your resource in a read-only object.
Most developers are not going to be using the RestServlet class itself, and instead will extend from one of the preconfigured default servlets such as BasicRestServlet and BasicRestServletGroup which provides universal language support, basic instrumentation, and auto-generated Swagger UI.
Deploying in Spring Boot
The BasicSpringRestServlet class is typically entry point for your REST resources when working within a Spring Boot environment. It extends from SpringRestServlet which provides additional capabilities including:
- Your REST resources can be defined as injectable Spring beans.
- Various capabilities within the REST Server library (e.g. logging, instrumentation, call handling, API extensions) can be defined via
Spring beans and automatically pulled into the framework.
Most developers are not going to be using the RestServlet class itself, and instead will extend from one of the preconfigured default servlets such as BasicSpringRestServlet and BasicSpringRestServletGroup that have the same capabilites as the BasicRestServlet and BasicRestServletGroup counterparts.
@Configuration
public class MySpringConfiguration {
/**
* Our root REST bean.
* Note that this must extend from SpringRestServlet so that child resources can be
* resolved as Spring beans.
* All REST objects are attached to this bean using the Rest.children() annotation.
*/
@Bean
public RootResources getRootResources() {
return new RootResources();
}
/**
* Optionally return the HelloWorldResource object as an injectable bean.
*/
@Bean
public HelloWorldResource getHelloWorldResource() {
return new HelloWorldResource();
}
/**
* Map our servlet to a path.
*/
@Bean
public ServletRegistrationBean getRootServlet(RootResources rootResources) {
return new ServletRegistrationBean(rootResources, "/*");
}
}
@Rest(
children={
HelloWorldResource.class
}
)
public class RootResources extends BasicSpringRestServletGroup {
// No code!
}
See REST Server — Programmatic Fluent Builder for configuring REST
resources entirely in code via the RestBuilder<SELF> API, without @Rest annotation attributes.
In This Section
🗃️ Basics and Structure
13 items
🗃️ Built-in Features
10 items
🗃️ Views and API Docs
6 items
🗃️ HTTP Behavior
8 items
🗃️ Security
6 items
🗃️ Operations and Observability
5 items
🗃️ Advanced and Internals
13 items
🗃️ Admin Console and Rich UI
6 items