| <!-- |
| /*************************************************************************************************************************** |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations under the License. |
| ***************************************************************************************************************************/ |
| --> |
| |
| PetStoreResource |
| |
| <p> |
| The <code>PetStoreResource</code> class provides examples for creating a Swagger-based interface. |
| </p> |
| |
| <h5 class='figure'>PetStoreResource.java</h5> |
| <p class='bpcode w800'> |
| <ja>@RestResource</ja>( |
| path=<js><js>"/petstore"</js></js>, |
| title=<js><js>"Petstore application"</js></js>, |
| description= { |
| <js><js>"This is a sample server Petstore server based on the Petstore sample at Swagger.io."</js></js>, |
| <js>"You can find out more about Swagger at <a class='link' href='http://swagger.io'>http://swagger.io</a>."</js>, |
| }, |
| htmldoc=<ja>@HtmlDoc</ja>( |
| widgets={ |
| ContentTypeMenuItem.<jk>class</jk>, |
| ThemeMenuItem.<jk>class</jk>, |
| }, |
| navlinks={ |
| <js>"up: request:/.."</js>, |
| <js>"options: servlet:/?method=OPTIONS"</js>, |
| <js>"$W{ContentTypeMenuItem}"</js>, |
| <js>"$W{ThemeMenuItem}"</js>, |
| <js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/petstore/$R{servletClassSimple}.java"</js> |
| }, |
| head={ |
| <js>"<link rel='icon' href='$U{servlet:/htdocs/cat.png}'/>"</js> <jc>// Add a cat icon to the page.</jc> |
| }, |
| header={ |
| <js>"<h1>$R{resourceTitle}</h1>"</js>, |
| <js>"<h2>$R{methodSummary}</h2>"</js>, |
| <js>"$C{PetStore/headerImage}"</js> |
| }, |
| aside={ |
| <js>"<div style='max-width:400px' class='text'>"</js>, |
| <js>" <p>This page shows a standard nested REST resource.</p>"</js>, |
| <js>" <p>It shows how different properties can be rendered on the same bean in different views.</p>"</js>, |
| <js>" <p>It also shows examples of HtmlRender classes and <ja>@BeanProperty</ja>(format) annotations.</p>"</js>, |
| <js>" <p>It also shows how the Queryable converter and query widget can be used to create searchable interfaces.</p>"</js>, |
| <js>"</div>"</js> |
| } |
| ), |
| properties= { |
| <jc>// Resolve recursive references when showing schema info in the swagger.</jc> |
| <ja>@Property</ja>(name=<jsf>SWAGGERUI_resolveRefsMaxDepth</jsf>, value=<js>"99"</js>) |
| }, |
| swagger=<ja>@ResourceSwagger</ja>(<js>"$F{PetStoreResource.json}"</js>), |
| staticFiles={<js>"htdocs:htdocs"</js>} |
| ) |
| <jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena { |
| |
| <jk>private</jk> PetStore <jf>store</jf>; |
| |
| <ja>@RestHook</ja>(<jsf>INIT</jsf>) |
| <jk>public void</jk> initDatabase(RestContextBuilder builder) <jk>throws</jk> Exception { |
| <jf>store</jf> = <jk>new</jk> PetStore().init(); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/"</js>, |
| summary=<js>"Navigation page"</js> |
| ) |
| <jk>public</jk> ResourceDescriptions getTopPage() { |
| <jk>return new</jk> ResourceDescriptions() |
| .append(<js>"pet"</js>, <js>"All pets in the store"</js>) |
| .append(<js>"store"</js>, <js>"Orders and inventory"</js>) |
| .append(<js>"user"</js>, <js>"Petstore users"</js>) |
| ; |
| } |
| |
| <jc>//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| // Pets |
| //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</jc> |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/pet"</js>, |
| summary=<js>"All pets in the store"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| parameters={ |
| Queryable.<jsf>SWAGGER_PARAMS</jsf> |
| } |
| ), |
| bpx=<js>"Pet: tags"</js>, |
| htmldoc=<ja>@HtmlDoc</ja>( |
| widgets={ |
| QueryMenuItem.<jk>class</jk>, |
| AddPetMenuItem.<jk>class</jk> |
| }, |
| navlinks={ |
| <js>"INHERIT"</js>, <jc>// Inherit links from class.</jc> |
| <js>"[2]:$W{QueryMenuItem}"</js>, <jc>// Insert QUERY link in position 2.</jc> |
| <js>"[3]:$W{AddPetMenuItem}"</js> <jc>// Insert ADD link in position 3.</jc> |
| } |
| ), |
| converters={Queryable.<jk>class</jk>} |
| ) |
| <jk>public</jk> Collection<Pet> getPets() <jk>throws</jk> NotAcceptable { |
| <jk>return</jk> <jf>store</jf>.getPets(); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/pet/{petId}"</js>, |
| summary=<js>"Find pet by ID"</js>, |
| description=<js>"Returns a single pet"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| value={ |
| <js>"security:[ { api_key:[] } ]"</js> |
| } |
| ) |
| ) |
| <jk>public</jk> Pet getPet( |
| <ja>@Path</ja>( |
| name=<js>"petId"</js>, |
| description=<js>"ID of pet to return"</js>, |
| example=<js>"123"</js> |
| ) |
| <jk>long</jk> petId |
| ) <jk>throws</jk> IdNotFound, NotAcceptable { |
| |
| <jk>return</jk> <jf>store</jf>.getPet(petId); |
| } |
| |
| <ja>@RestMethod</ja>( |
| summary=<js>"Add a new pet to the store"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| value={ |
| <js>"security:[ { petstore_auth:['write:pets','read:pets'] } ]"</js> |
| } |
| ) |
| ) |
| <jk>public</jk> Ok postPet( |
| <ja>@Body</ja>(description=<js>"Pet object to add to the store"</js>) PetCreate pet |
| ) <jk>throws</jk> IdConflict, NotAcceptable, UnsupportedMediaType { |
| |
| <jf>store</jf>.create(pet); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>PUT</jsf>, |
| path=<js>"/pet/{petId}"</js>, |
| summary=<js>"Update an existing pet"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| value={ |
| <js>"security:[ { petstore_auth: ['write:pets','read:pets'] } ]"</js> |
| } |
| ) |
| ) |
| <jk>public</jk> Ok updatePet( |
| <ja>@Body</ja>(description=<js>"Pet object that needs to be added to the store"</js>) PetUpdate pet |
| ) <jk>throws</jk> IdNotFound, NotAcceptable, UnsupportedMediaType { |
| |
| <jf>store</jf>.update(pet); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/pet/{petId}/edit"</js>, |
| summary=<js>"Pet edit page"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| value={ |
| <js>"security:[ { petstore_auth:['write:pets','read:pets'] } ]"</js> |
| } |
| ) |
| ) |
| <jk>public</jk> Div editPetPage( |
| <ja>@Path</ja>( |
| name=<js>"petId"</js>, |
| description=<js>"ID of pet to return"</js>, |
| example=<js>"123"</js> |
| ) |
| <jk>long</jk> petId |
| ) <jk>throws</jk> IdConflict, NotAcceptable, UnsupportedMediaType { |
| |
| Pet pet = getPet(petId); |
| |
| <jk>return</jk> <jsm>div</jsm>( |
| <jsm>form</jsm>().id(<js>"form"</js>).action(<js>"servlet:/pet/"</js> + petId).method(<jsf>POST</jsf>).children( |
| <jsm>table</jsm>( |
| <jsm>tr</jsm>( |
| <jsm>th</jsm>(<js>"Id:"</js>), |
| <jsm>td</jsm>(<jsm>input</jsm>().name(<js>"id"</js>).type(<js>"text"</js>).value(petId).readonly(<jk>true</jk>)), |
| <jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"The name of the pet."</js>, <jsm>br</jsm>(), <js>"e.g. 'Fluffy'"</js>)) |
| ), |
| <jsm>tr</jsm>( |
| <jsm>th</jsm>(<js>"Name:"</js>), |
| <jsm>td</jsm>(<jsm>input</jsm>().name(<js>"name"</js>).type(<js>"text"</js>).value(pet.getName())), |
| <jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"The name of the pet."</js>, <jsm>br</jsm>(), <js>"e.g. 'Fluffy'"</js>)) |
| ), |
| <jsm>tr</jsm>( |
| <jsm>th</jsm>(<js>"Species:"</js>), |
| <jsm>td</jsm>( |
| <jsm>select</jsm>().name(<js>"species"</js>).children( |
| <jsm>option</jsm>(<js>"cat"</js>), <jsm>option</jsm>(<js>"dog"</js>), <jsm>option</jsm>(<js>"bird"</js>), <jsm>option</jsm>(<js>"fish"</js>), <jsm>option</jsm>(<js>"mouse"</js>), <jsm>option</jsm>(<js>"rabbit"</js>), <jsm>option</jsm>(<js>"snake"</js>) |
| ).choose(pet.getSpecies()) |
| ), |
| <jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"The kind of animal."</js>)) |
| ), |
| <jsm>tr</jsm>( |
| <jsm>th</jsm>(<js>"Price:"</js>), |
| <jsm>td</jsm>(<jsm>input</jsm>().name(<js>"price"</js>).type(<js>"number"</js>).placeholder(<js>"1.0"</js>).step(<js>"0.01"</js>).min(1).max(100).value(pet.getPrice())), |
| <jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"The price to charge for this pet."</js>)) |
| ), |
| <jsm>tr</jsm>( |
| <jsm>th</jsm>(<js>"Tags:"</js>), |
| <jsm>td</jsm>(<jsm>input</jsm>().name(<js>"tags"</js>).type(<js>"text"</js>).value(Tag.<jsm>asString</jsm>(pet.getTags()))), |
| <jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"Arbitrary textual tags (comma-delimited)."</js>, <jsm>br</jsm>(), <js>"e.g. 'fluffy,friendly'"</js>)) |
| ), |
| <jsm>tr</jsm>( |
| <jsm>th</jsm>(<js>"Status:"</js>), |
| <jsm>td</jsm>( |
| <jsm>select</jsm>().name(<js>"status"</js>).children( |
| <jsm>option</jsm>(<js>"AVAILABLE"</js>), <jsm>option</jsm>(<js>"PENDING"</js>), <jsm>option</jsm>(<js>"SOLD"</js>) |
| ).choose(pet.getStatus()) |
| ), |
| <jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"The current status of the animal."</js>)) |
| ), |
| <jsm>tr</jsm>( |
| <jsm>td</jsm>().colspan(2).style(<js>"text-align:right"</js>).children( |
| <jsm>button</jsm>(<js>"reset"</js>, <js>"Reset"</js>), |
| <jsm>button</jsm>(<js>"button"</js>,<js>"Cancel"</js>).onclick(<js>"window.location.href='/'"</js>), |
| <jsm>button</jsm>(<js>"submit"</js>, <js>"Submit"</js>) |
| ) |
| ) |
| ).style(<js>"white-space:nowrap"</js>) |
| ) |
| ); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/pet/findByStatus"</js>, |
| summary=<js>"Finds Pets by status"</js>, |
| description=<js>"Multiple status values can be provided with comma separated strings."</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| value={ |
| <js>"security:[{petstore_auth:['write:pets','read:pets']}]"</js> |
| } |
| ) |
| ) |
| <jk>public</jk> Collection<Pet> findPetsByStatus( |
| <ja>@Query</ja>( |
| name=<js>"status"</js>, |
| description=<js>"Status values that need to be considered for filter."</js>, |
| required=<jk>true</jk>, |
| type=<js>"array"</js>, |
| collectionFormat=<js>"csv"</js>, |
| items=<ja>@Items</ja>( |
| type=<js>"string"</js>, |
| _enum=<js>"AVAILABLE,PENDING,SOLD"</js>, |
| _default=<js>"AVAILABLE"</js> |
| ), |
| example=<js>"AVALIABLE,PENDING"</js> |
| ) |
| PetStatus[] status |
| ) <jk>throws</jk> NotAcceptable { |
| |
| <jk>return</jk> <jf>store</jf>.getPetsByStatus(status); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/pet/findByTags"</js>, |
| summary=<js>"Finds Pets by tags"</js>, |
| description=<js>"Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing."</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| value={ |
| <js>"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]"</js> |
| } |
| ) |
| ) |
| <ja>@Deprecated</ja> |
| <jk>public</jk> Collection<Pet> findPetsByTags( |
| <ja>@Query</ja>( |
| name=<js>"tags"</js>, |
| description=<js>"Tags to filter by"</js>, |
| required=<jk>true</jk>, |
| example=<js>"['tag1','tag2']"</js> |
| ) |
| String[] tags |
| ) <jk>throws</jk> InvalidTag, NotAcceptable { |
| |
| <jk>return</jk> <jf>store</jf>.getPetsByTags(tags); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>DELETE</jsf>, |
| path=<js>"/pet/{petId}"</js>, |
| summary=<js>"Deletes a pet"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| value={ |
| <js>"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]"</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 { |
| |
| <jf>store</jf>.removePet(petId); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>POST</jsf>, |
| path=<js>"/pet/{petId}/uploadImage"</js>, |
| summary=<js>"Uploads an image"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"pet"</js>, |
| value={ |
| <js>"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]"</js> |
| } |
| ) |
| ) |
| <jk>public</jk> Ok uploadImage( |
| <ja>@Path</ja>( |
| name=<js>"petId"</js>, |
| description=<js>"ID of pet to update"</js>, |
| example=<js>"123"</js> |
| ) |
| <jk>long</jk> petId, |
| <ja>@FormData</ja>( |
| name=<js>"additionalMetadata"</js>, |
| description=<js>"Additional data to pass to server"</js>, |
| example=<js>"Foobar"</js> |
| ) |
| String additionalMetadata, |
| <ja>@FormData</ja>( |
| name=<js>"file"</js>, |
| description=<js>"file to upload"</js>, |
| required=<jk>true</jk>, |
| type=<js>"file"</js> |
| ) |
| <jk>byte</jk>[] file |
| ) <jk>throws</jk> NotAcceptable, UnsupportedMediaType { |
| |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <jc>//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| // Orders |
| //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</jc> |
| |
| <ja>@RestMethod</ja>( |
| summary=<js>"Store navigation page"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"store"</js> |
| ) |
| ) |
| <jk>public</jk> ResourceDescriptions getStore() { |
| <jk>return new</jk> ResourceDescriptions() |
| .append(<js>"store/order"</js>, <js>"Petstore orders"</js>) |
| .append(<js>"store/inventory"</js>, <js>"Petstore inventory"</js>) |
| ; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/store/order"</js>, |
| summary=<js>"Petstore orders"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"store"</js> |
| ), |
| htmldoc=<ja>@HtmlDoc</ja>( |
| widgets={ |
| QueryMenuItem.<jk>class</jk>, |
| AddOrderMenuItem.<jk>class</jk> |
| }, |
| navlinks={ |
| <js>"INHERIT"</js>, <jc>// Inherit links from class.</jc> |
| <js>"[2]:$W{QueryMenuItem}"</js>, <jc>// Insert QUERY link in position 2.</jc> |
| <js>"[3]:$W{AddOrderMenuItem}"</js> <jc>// Insert ADD link in position 3.</jc> |
| } |
| ) |
| ) |
| <jk>public</jk> Collection<Order> getOrders() <jk>throws</jk> NotAcceptable { |
| <jk>return</jk> <jf>store</jf>.getOrders(); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/store/order/{orderId}"</js>, |
| summary=<js>"Find purchase order by ID"</js>, |
| description=<js>"Returns a purchase order by ID."</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"store"</js> |
| ) |
| ) |
| <jk>public</jk> Order getOrder( |
| <ja>@Path</ja>( |
| name=<js>"orderId"</js>, |
| description=<js>"ID of order to fetch"</js>, |
| maximum=<js>"1000"</js>, |
| minimum=<js>"101"</js>, |
| example=<js>"123"</js> |
| ) |
| <jk>long</jk> orderId |
| ) <jk>throws</jk> InvalidId, IdNotFound, NotAcceptable { |
| |
| <jk>if</jk> (orderId < 101 || orderId > 1000) |
| <jk>throw new</jk> InvalidId(); |
| <jk>return</jk> <jf>store</jf>.getOrder(orderId); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>POST</jsf>, |
| path=<js>"/store/order"</js>, |
| summary=<js>"Place an order for a pet"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"store"</js> |
| ), |
| pojoSwaps={ |
| DateSwap.<jsf>ISO8601D</jsf>.<jk>class</jk> |
| } |
| ) |
| <jk>public</jk> Order placeOrder( |
| <ja>@FormData</ja>( |
| name=<js>"petId"</js>, |
| description=<js>"Pet ID"</js> |
| ) |
| <jk>long</jk> petId, |
| <ja>@FormData</ja>( |
| name=<js>"shipDate"</js>, |
| description=<js>"Ship date"</js> |
| ) |
| Date shipDate |
| ) <jk>throws</jk> IdConflict, NotAcceptable, UnsupportedMediaType { |
| |
| CreateOrder co = <jk>new</jk> CreateOrder(petId, shipDate); |
| <jk>return</jk> <jf>store</jf>.create(co); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>DELETE</jsf>, |
| path=<js>"/store/order/{orderId}"</js>, |
| summary=<js>"Delete purchase order by ID"</js>, |
| description= { |
| <js>"For valid response try integer IDs with positive integer value."</js>, |
| <js>"Negative or non-integer values will generate API errors."</js> |
| }, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"store"</js> |
| ) |
| ) |
| <jk>public</jk> Ok deletePurchaseOrder( |
| <ja>@Path</ja>( |
| name=<js>"orderId"</js>, |
| description=<js>"ID of the order that needs to be deleted"</js>, |
| minimum=<js>"1"</js>, |
| example=<js>"5"</js> |
| ) |
| <jk>long</jk> orderId |
| ) <jk>throws</jk> InvalidId, IdNotFound, NotAcceptable { |
| |
| <jk>if</jk> (orderId < 0) |
| <jk>throw new</jk> InvalidId(); |
| <jf>store</jf>.removeOrder(orderId); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/store/inventory"</js>, |
| summary=<js>"Returns pet inventories by status"</js>, |
| description=<js>"Returns a map of status codes to quantities"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"store"</js>, |
| responses={ |
| <js>"200:{ 'x-example':{AVAILABLE:123} }"</js>, |
| }, |
| value={ |
| <js>"security:[ { api_key:[] } ]"</js> |
| } |
| ) |
| ) |
| <jk>public</jk> Map<PetStatus,Integer> getStoreInventory() <jk>throws</jk> NotAcceptable { |
| <jk>return</jk> <jf>store</jf>.getInventory(); |
| } |
| |
| <jc>//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| // Users |
| //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</jc> |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/user"</js>, |
| summary=<js>"Petstore users"</js>, |
| bpx=<js>"User: email,password,phone"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"user"</js> |
| ) |
| ) |
| <jk>public</jk> Collection<User> getUsers() <jk>throws</jk> NotAcceptable { |
| <jk>return</jk> <jf>store</jf>.getUsers(); |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/user/{username}"</js>, |
| summary=<js>"Get user by user name"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"user"</js> |
| ) |
| ) |
| <jk>public</jk> User getUser( |
| <ja>@Path</ja>( |
| name=<js>"username"</js>, |
| description=<js>"The name that needs to be fetched. Use user1 for testing."</js> |
| ) |
| String username |
| ) <jk>throws</jk> InvalidUsername, IdNotFound, NotAcceptable { |
| |
| <jk>return</jk> <jf>store</jf>.getUser(username); |
| } |
| |
| <ja>@RestMethod</ja>( |
| summary=<js>"Create user"</js>, |
| description=<js>"This can only be done by the logged in user."</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"user"</js> |
| ) |
| ) |
| <jk>public</jk> Ok postUser( |
| <ja>@Body</ja>(description=<js>"Created user object"</js>) User user |
| ) <jk>throws</jk> InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType { |
| |
| <jf>store</jf>.add(user); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>POST</jsf>, |
| path=<js>"/user/createWithArray"</js>, |
| summary=<js>"Creates list of users with given input array"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"user"</js> |
| ) |
| ) |
| <jk>public</jk> Ok createUsers( |
| <ja>@Body</ja>(description=<js>"List of user objects"</js>) User[] users |
| ) <jk>throws</jk> InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType { |
| |
| <jk>for</jk> (User user : users) |
| <jf>store</jf>.add(user); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>PUT</jsf>, |
| path=<js>"/user/{username}"</js>, |
| summary=<js>"Update user"</js>, |
| description=<js>"This can only be done by the logged in user."</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"user"</js> |
| ) |
| ) |
| <jk>public</jk> Ok updateUser( |
| <ja>@Path</ja>( |
| name=<js>"username"</js>, |
| description=<js>"Name that need to be updated"</js> |
| ) |
| String username, |
| <ja>@Body</ja>( |
| description=<js>"Updated user object"</js> |
| ) |
| User user |
| ) <jk>throws</jk> InvalidUsername, IdNotFound, NotAcceptable, UnsupportedMediaType { |
| |
| <jf>store</jf>.update(user); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>DELETE</jsf>, |
| path=<js>"/user/{username}"</js>, |
| summary=<js>"Delete user"</js>, |
| description=<js>"This can only be done by the logged in user."</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"user"</js> |
| ) |
| ) |
| <jk>public</jk> Ok deleteUser( |
| <ja>@Path</ja>( |
| name=<js>"username"</js>, |
| description=<js>"The name that needs to be deleted"</js> |
| ) |
| String username |
| ) <jk>throws</jk> InvalidUsername, IdNotFound, NotAcceptable { |
| |
| <jf>store</jf>.removeUser(username); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/user/login"</js>, |
| summary=<js>"Logs user into the system"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"user"</js> |
| ) |
| ) |
| <jk>public</jk> Ok login( |
| <ja>@Query</ja>( |
| name=<js>"username"</js>, |
| description=<js>"The username for login"</js>, |
| required=<jk>true</jk>, |
| example=<js>"myuser"</js> |
| ) |
| String username, |
| <ja>@Query</ja>( |
| name=<js>"password"</js>, |
| description=<js>"The password for login in clear text"</js>, |
| required=<jk>true</jk>, |
| example=<js>"abc123"</js> |
| ) |
| String password, |
| <ja>@ResponseHeader</ja>( |
| name=<js>"X-Rate-Limit"</js>, |
| type=<js>"integer"</js>, |
| format=<js>"int32"</js>, |
| description=<js>"Calls per hour allowed by the user."</js>, |
| example=<js>"123"</js> |
| ) |
| Value<Integer> rateLimit, |
| Value<ExpiresAfter> expiresAfter, |
| RestRequest req, |
| RestResponse res |
| ) <jk>throws</jk> InvalidLogin, NotAcceptable { |
| |
| <jk>if</jk> (! <jf>store</jf>.isValid(username, password)) |
| <jk>throw new</jk> InvalidLogin(); |
| |
| Date d = <jk>new</jk> Date(System.<jsm>currentTimeMillis</jsm>() + 30 * 60 * 1000); |
| req.getSession().setAttribute(<js>"login-expires"</js>, d); |
| rateLimit.set(1000); |
| expiresAfter.set(<jk>new</jk> ExpiresAfter(d)); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| |
| <ja>@ResponseHeader</ja>( |
| name=<js>"X-Expires-After"</js>, |
| type=<js>"string"</js>, |
| format=<js>"date-time"</js>, |
| description=<js>"Date in UTC when token expires"</js>, |
| example=<js>"2012-10-21"</js> |
| ) |
| <jk>public static class</jk> ExpiresAfter { |
| <jk>private final</jk> Calendar c; |
| <jk>public</jk> ExpiresAfter(Date d) { |
| <jk>this</jk>.c = <jk>new</jk> GregorianCalendar(); |
| c.setTime(d); |
| } |
| <jk>public</jk> Calendar toCalendar() { |
| <jk>return</jk> c; |
| } |
| } |
| |
| <ja>@RestMethod</ja>( |
| name=<jsf>GET</jsf>, |
| path=<js>"/user/logout"</js>, |
| summary=<js>"Logs out current logged in user session"</js>, |
| swagger=<ja>@MethodSwagger</ja>( |
| tags=<js>"user"</js> |
| ) |
| ) |
| <jk>public</jk> Ok logout(RestRequest req) <jk>throws</jk> NotAcceptable { |
| req.getSession().removeAttribute(<js>"login-expires"</js>); |
| <jk>return</jk> <jsf>OK</jsf>; |
| } |
| } |
| </p> |
| <p> |
| Pointing a browser to the resource shows the following: |
| </p> |
| <p class='bpcode w800'> |
| http://localhost:10000/petstore |
| </p> |
| <img class='bordered w800' src='doc-files/juneau-examples-rest.PetStoreResource.1.png'> |
| <p> |
| Clicking the <code>QUERY</code> link renders the following menu pop-up complete with tooltips: |
| </p> |
| <img class='bordered w800' src='doc-files/juneau-examples-rest.PetStoreResource.2.png'> |
| <p> |
| The <code>STYLES</code> menu item allows you to try out the other default look-and-feels: |
| </p> |
| <h5 class='figure'>Light look-and-feel</h5> |
| <img class='bordered w800' src='doc-files/juneau-examples-rest.PetStoreResource.3.png'> |
| <h5 class='figure'>Dark look-and-feel</h5> |
| <img class='bordered w800' src='doc-files/juneau-examples-rest.PetStoreResource.4.png'> |