You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/10/26 16:21:01 UTC
[juneau-website] branch asf-site updated: Documentation.
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/juneau-website.git
The following commit(s) were added to refs/heads/asf-site by this push:
new 7b22694 Documentation.
7b22694 is described below
commit 7b2269419d38b90e8868054617ff3ee155c8fc15
Author: JamesBognar <ja...@apache.org>
AuthorDate: Fri Oct 26 12:20:50 2018 -0400
Documentation.
---
content/rest-client.html | 93 ++++++++++++++++++++++++-
content/rest-server.html | 175 ++---------------------------------------------
2 files changed, 97 insertions(+), 171 deletions(-)
diff --git a/content/rest-client.html b/content/rest-client.html
index 4d3b10b..ada2702 100644
--- a/content/rest-client.html
+++ b/content/rest-client.html
@@ -138,10 +138,101 @@
price: 9.99
}
</p>
+ <br><hr>
+ <p>
+ A common coding practice is to use the same Java interface to define both your server and client side REST interfaces.
+ The advantage to this approach is that changes that you make to your REST interface can be reflected in both places
+ at the same time, reducing the chances for compatibility mistakes.
+ </p>
+ <p>
+ What makes this possible is that method-level annotations such as <ja>@RestMethod</ja> and parameter-level annotations
+ such as <ja>@Query</ja> are inherited from parent classes.
+ This normally isn't possible, but the framework will spider up the parent hierarchy of classes to find method and parameter level
+ annotations defined on overridden methods.
+ </p>
+ <p>
+ The general approach is to define your <ja>@RemoteResource</ja>-annotated interface first.
+ The following example is pulled from the PetStore app:
+ </p>
+ <p class='bcode w800'>
+ <ja>@RemoteResource</ja>(path=<js>"/petstore"</js>)
+ <jk>public interface</jk> PetStore {
+
+ <ja>@RemoteMethod</ja>(method=<jsf>GET</jsf>, path=<js>"/pet"</js>)
+ <jk>public</jk> Collection<Pet> getPets() <jk>throws</jk> NotAcceptable;
+
+ <ja>@RemoteMethod</ja>(method=<jsf>DELETE</jsf>, path=<js>"/pet/{petId}"</js>)
+ <jk>public</jk> Ok deletePet(
+ <ja>@Header</ja>(
+ name=<js>"api_key"</js>,
+ description=<js>"Security API key"</js>,
+ required=<jk>true</jk>,
+ example=<js>"foobar"</js>
+ )
+ String apiKey,
+ <ja>@Path</ja>(
+ name=<js>"petId"</js>,
+ description=<js>"Pet id to delete"</js>,
+ example=<js>"123"</js>
+ )
+ <jk>long</jk> petId
+ ) <jk>throws</jk> IdNotFound, NotAcceptable;
+
+ ...
+ </p>
+ <p>
+ Next you define the implementation of your interface as a normal Juneau REST resource:
+ </p>
+ <p class='bcode w800'>
+ <ja>@RestResource</ja>(
+ path=<js>"/petstore"</js>,
+ title=<js>"Petstore application"</js>,
+ ...
+ )
+ <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena <jk>implements</jk> PetStore {
+
+ ...
+
+ <ja>@Override</ja> <jc>/* PetStore */</jc>
+ <ja>@RestMethod</ja>(
+ name=<jsm>GET</jsm>,
+ path=<js>"/pet"</js>,
+ summary=<js>"All pets in the store"</js>,
+ ...
+ )
+ <jk>public</jk> Collection<Pet> getPets() <jk>throws</jk> NotAcceptable {
+ <jk>return</jk> <jsf>store</jsf>.getPets();
+ }
+
+ <ja>@Override</ja> <jc>/* PetStore */</jc>
+ <ja>@RestMethod</ja>(
+ name=<jsf>DELETE</jsf>,
+ path=<js>"/pet/{petId}"</js>,
+ summary=<js>"Deletes a pet"</js>,
+ ...
+ )
+ <jk>public</jk> Ok deletePet(String apiKey, long petId) <jk>throws</jk> IdNotFound, NotAcceptable {
+ <jsf>store</jsf>.removePet(petId);
+ <jk>return</jk> <jsf>OK</jsf>;
+ }
+ </p>
+ <p>
+ Then use the interface as a remote resource like so:
+ </p>
+ <p class='bcode w800'>
+ <jk>try</jk> (RestClient rc = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build()) {
+ PetStore ps = rc.getRemoteResource(PetStore.<jk>class</jk>);
+
+ <jk>for</jk> (Pet x : ps.getPets()) {
+ ps.deletePet(<js>"my-special-key"</js>, x.getId());
+ System.<jsf>err</jsf>.println(<js>"Deleted pet: id="</js> + x.getId());
+ }
+ }
+ </p>
<h5 class='section'>More Information:</h5>
<ul class='doctree'>
- <li><a class='doclink' href='http://juneau.apache.org/site/apidocs/overview-summary.html#juneau-rest-client.RestProxies'>juneau-rest-client > REST Proxies</a>
+ <li><a class='doclink' href='http://juneau.apache.org/site/apidocs/overview-summary.html#juneau-rest-client.RestProxies.DualPurposeInterfaces'>juneau-rest-client > Dual-Purpose Interfaces</a>
</ul>
</div>
</body>
diff --git a/content/rest-server.html b/content/rest-server.html
index bcafd57..9488799 100644
--- a/content/rest-server.html
+++ b/content/rest-server.html
@@ -409,176 +409,6 @@
<br><code>Locale</code>, <code>ResourceBundle</code>, <code>MessageBundle</code>, <code>InputStream</code>, <code>OutputStream</code>, <code>Reader</code>, <code>Writer</code>...
<li>User-defined parameter types.
</ul>
- <p>
- It's up to you how you want to define your REST methods.
- As a general rule, there are 3 broad approaches typically used:
- </p>
-
- <h5 class='topic'>Methodology #1 - Annotated parameters</h5>
- <p>
- This approach uses annotated parameters for retrieving input from the request.
- </p>
- <p class='bcode w800'>
- <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example1/{p1}/{p2}/{p3}/*"</js>)
- <jk>public</jk> String example1(
- <ja>@Method</ja> String method, <jc>// HTTP method.</jc>
- <ja>@Path</ja>(<js>"p1"</js>) String p1, <jc>// Path variables.</jc>
- <ja>@Path</ja>(<js>"p2"</js>) <jk>int</jk> p2,
- <ja>@Path</ja>(<js>"p3"</js>) UUID p3,
- <ja>@Query</ja>(<js>"q1"</js>) <jk>int</jk> q1, <jc>// Query parameters.</jc>
- <ja>@Query</ja>(<js>"q2"</js>) String q2,
- <ja>@Query</ja>(<js>"q3"</js>) UUID q3,
- <ja>@PathRemainder</ja> String remainder, <jc>// Path remainder after pattern match.</jc>
- <ja>@Header</ja>(<js>"Accept-Language"</js>) String lang, <jc>// Headers.</jc>
- <ja>@Header</ja>(<js>"Accept"</js>) String accept,
- <ja>@Header</ja>(<js>"DNT"</js>) <jk>int</jk> doNotTrack
- ) {
-
- <jc>// Send back a simple String response</jc>
- String output = String.<jsm>format</jsm>(
- <js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>,
- method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack);
- <jk>return</jk> output;
- }
- </p>
-
- <h5 class='topic'>Methodology #2 - Low-level request/response objects</h5>
- <p>
- This approach uses low-level request/response objects to perform the same as above.
- </p>
- <p class='bcode w800'>
- <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example2/{p1}/{p2}/{p3}/*"</js>)
- <jk>public</jk> String example2(
- RestRequest req, <jc>// A direct subclass of HttpServletRequest.</jc>
- RestResponse res <jc>// A direct subclass of HttpServletResponse.</jc>
- ) {
-
- <jc>// HTTP method.</jc>
- String method = req.getMethod();
-
- <jc>// Path variables.</jc>
- RequestPathMatch path = req.getPathMatch();
- String p1 = path.get(<js>"p1"</js>, String.<jk>class</jk>);
- <jk>int</jk> p2 = path.get(<js>"p2"</js>, <jk>int</jk>.<jk>class</jk>);
- UUID p3 = path.get(<js>"p3"</js>, UUID.<jk>class</jk>);
-
- <jc>// Query parameters.</jc>
- RequestQuery query = req.getQuery();
- <jk>int</jk> q1 = query.get(<js>"q1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
- String q2 = query.get(<js>"q2"</js>, String.<jk>class</jk>);
- UUID q3 = query.get(<js>"q3"</js>, UUID.<jk>class</jk>);
-
- <jc>// Path remainder after pattern match.</jc>
- String remainder = req.getPathMatch().getRemainder();
-
- <jc>// Headers.</jc>
- String lang = req.getHeader(<js>"Accept-Language"</js>);
- String accept = req.getHeader(<js>"Accept"</js>);
- <jk>int</jk> doNotTrack = req.getHeaders().get(<js>"DNT"</js>, <jk>int</jk>.<jk>class</jk>);
-
- <jc>// Send back a simple String response</jc>
- String output = String.format(
- <js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>,
- method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack);
- res.setOutput(output); <jc>// Or use getWriter().</jc>
- }
- </p>
-
- <h5 class='topic'>Methodology #3 - Intermediate-level API objects</h5>
- <p>
- This approach is sort of the middle ground where you get access functional area APIs.
- </p>
- <p class='bcode w800'>
- <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example3/{p1}/{p2}/{p3}/*"</js>)
- <jk>public</jk> String example3(
- HttpMethod method, <jc>// HTTP method.</jc>
- RequestPathMatch path, <jc>// Path variables.</jc>
- RequestQuery query, <jc>// Query parameters.</jc>
- RequestHeaders headers, <jc>// Headers.</jc>
- AcceptLanguage lang, <jc>// Specific header classes.</jc>
- Accept accept
- ) {
-
- <jc>// Path variables.</jc>
- String p1 = path.get(<js>"p1"</js>, String.<jk>class</jk>);
- <jk>int</jk> p2 = path.get(<js>"p2"</js>, <jk>int</jk>.<jk>class</jk>);
- UUID p3 = path.get(<js>"p3"</js>, UUID.<jk>class</jk>);
-
- <jc>// Query parameters.</jc>
- <jk>int</jk> q1 = query.get(<js>"q1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
- String q2 = query.get(<js>"q2"</js>, String.<jk>class</jk>);
- UUID q3 = query.get(<js>"q3"</js>, UUID.<jk>class</jk>);
-
- <jc>// Path remainder after pattern match.</jc>
- String remainder = path.getRemainder();
-
- <jc>// Headers.</jc>
- <jk>int</jk> doNotTrack = headers.get(<js>"DNT"</js>, <jk>int</jk>.<jk>class</jk>);
-
- <jc>// Send back a simple String response</jc>
- String output = String.format(
- <js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>,
- method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack);
- res.setOutput(output);
- }
- </p>
- <p>
- All three are completely equivalent. It's up to your own coding preferences which methodology you use.
- </p>
- <br><hr>
- <p>
- Lifecycle hooks allow you to hook into lifecycle events of the servlet or REST call.
- Like <ja>@RestMethod</ja> methods, the list of parameters are specified by the developer.
- </p>
- <p>
- For example, if you want to add an initialization method to your resource:
- </p>
- <p class='bcode w800'>
- <ja>@RestResource</ja>(...)
- <jk>public class</jk> MyResource {
-
- <jc>// Our database.</jc>
- <jk>private</jk> Map<Integer,Object> <jf>myDatabase</jf>;
-
- <ja>@RestHook</ja>(<jsf>INIT</jsf>)
- <jk>public void</jk> initMyDatabase(RestConfig config) <jk>throws</jk> Exception {
- <jf>myDatabase</jf> = <jk>new</jk> LinkedHashMap<>();
- }
- }
- </p>
- <p>
- Or if you want to intercept REST calls:
- </p>
- <p class='bcode w800'>
- <ja>@RestResource</ja>(...)
- <jk>public class</jk> MyResource {
-
- <jc>// Add a request attribute to all incoming requests.</jc>
- <ja>@RestHook</ja>(<jsf>PRE_CALL</jsf>)
- <jk>public void</jk> onPreCall(RestRequest req) {
- req.setAttribute(<js>"foo"</js>, <js>"bar"</js>);
- }
- }
- </p>
- <p>
- The hook events can be broken down into two categories:
- </p>
- <ul class='spaced-list'>
- <li>Resource lifecycle events:
- <ul>
- <li><jsf>INIT</jsf> - Right before initialization.
- <li><jsf>POST_INIT</jsf> - Right after initialization.
- <li><jsf>POST_INIT_CHILD_FIRST</jsf> - Right after initialization, but run child methods first.
- <li><jsf>DESTROY</jsf> - Right before servlet destroy.
- </ul>
- <li>REST call lifecycle events:
- <ul>
- <li><jsf>START_CALL</jsf> - At the beginning of a REST call.
- <li><jsf>PRE_CALL</jsf> - Right before the <ja>@RestMethod</ja> method is invoked.
- <li><jsf>POST_CALL</jsf> - Right after the <ja>@RestMethod</ja> method is invoked.
- <li><jsf>END_CALL</jsf> - At the end of the REST call after the response has been flushed.
- </ul>
- </ul>
<br><hr>
<p>
Navigable hierarchies of REST resources are easy to set up either programmatically or through annotations.
@@ -762,6 +592,11 @@
<h5 class='figure'>Dark look-and-feel</h5>
<img class='bordered w800' src='images/juneau-examples-rest.PetStoreResource.4.png'>
<br><hr>
+ <p>
+ Navigable hierarchies of REST resources are easy to set up either programmatically or through annotations.
+ </p>
+
+ <br><hr>
<p>
Automatic error handling is provided for a variety of conditions:
</p>