-
Notifications
You must be signed in to change notification settings - Fork 9
gServ Request Handling
#Request Handling Requests are handled by action functions. All path variable values will be passed to the action function in order. Each HTTP method is described below:
#Request Types ##Get Requests
get "/accounts/:accountId/transactions/:startDate/:endDate", { accountId, startDate, endDate -> List transactions = someService.getTransactions( accountId, startDate, endDate) writeJson transactions }
##Put/Post Requests
put "/books/:id", {instream, id -> // Parse the JSON input stream Map data = to.json(instream) // save the data somewhere def ok = someService.save( id, data ) writeJSON [success:ok] }
##Delete Requests delete "/accounts/:accountId/transactions/:transId", {accountId, transId -> boolean success=someService.removeAccountTransaction(accountId,transId) writeJson [ok: success] }
##Patch Requests Not (yet) supported
#Request Context The request context represents the current request and is of type io.github.javaconductor.gserv.requesthandler.RequestContext. The builtin variable 'requestContext' is available to all action functions. Below are some of the values in the RequestContext
interface RequestContext { Map requestHeaders Map responseHeaders InputStream requestBody OutputStream responseBody Map attributes String requestMethod URI requestURI int responseCode Principal principal InetSocketAddress localAddress InetSocketAddress remoteAddress String protocol Object getAttribute(String key) void setAttribute(String key, Object value) def close() def isClosed() def setStreams(InputStream is, OutputStream os) void sendResponseHeaders(int responseCode, long size) def id() }
#Accessing Headers
##Request Headers Request headers can be accessed using the built-in functions:
def userAgent = requestHeader("User-Agent") List acceptList = requestHeaders("Accept")
Example:
get() { requestHeaders('Accept').each { acceptValue -> println "Accepts $acceptValue" } }
Above is an example where we print all the acceptable content types. The requestContext contains a Map called requestHeaders which contains an entry for each HTTP header contained in the request. Each entry is stored as a List therefore some header may have multiple values.
##Response Headers There are 3 functions to acccess the request headers:
responseHeader "Content-Type", "plain/text" responseHeaders "Content-Type", ["plain/text"] def contentType = responseHeader("Content-Type")
Example:
get('/sales/:year/:month/:day'){ yr, month,day -> def csvData = service.getSalesForDate(yr,month,day) responseHeader 'Content-Type', 'text/csv' write(csvData) }
Above is an example where we get sales data for a particular day in the CSV format. We set the content-type header value to 'text/csv' as a List.
#Implicit Conversions ###Incoming Data On PUT/POST requests, the first argument to the action function is in the input stream to the data being sent. However, if the first argument is declared as a String or byte[] then that argument will be converter to that type.
put "/user/:userId/posts/:topicId", {String commentText, userId, topicId -> // save the data somewhere def ok = someService.savePost( userId, topicId, commentText ) writeJSON [success:ok] }
In the above example, the first argument passed to the action function, commentText, is of type String. By default, this works for types String and byte[]. To implicitly convert input into other types, conversion functions may be declared in the server config. Let's see an example:
class Post { def userId, topicId, commentText } gserv.http { conversion(Post.class){ instream -> def data = new JSONSlurper().parse(instream) new Post(userId: data.userId, topicId: data.topicId, commentText: data.commentText) } put "/posts/:topicId", {Post post, topicId -> // save the data somewhere def ok = someService.broadcastPost( topicId, post) writeJSON [success:ok] } }
In the above example, the first argument to the action function is of type Post. The argument was converted by the conversion defined in the server config.
###Action Path Variable Conversion Action path variables are, by default, strings. To specify that a particular variable is an integer, append ':Integer' to the variable name. This will guarantee that the value passed in the request is an integer and is of type java.lang.Integer.
get "/books/:id:Integer", { id -> def bk = someService.getBook(id) writeJson asMap(bk) }
##HTML Form Handling
An action may be used to handle a PUT/POST HTML form. Two things must be done:
First, the action attribute of the form must be the URL for the action.
Second, take advantage of the implicit conversion to FormData (io.github.javaconductor.gserv.converters.FormData) class.
Example:
For a form such as this:
<form action="/user/photo/form" method="POST"> Description: <input type="text" name="description"> </br> Image: <input type="file" name="imagefile"> </br> Upload File: <input type="submit" > </form>
The action to handle the form would look something like this:
post "/user/photo/form", { FormData fd -> // use the fieldValue collection in FormData to get form field values def description = fd.fieldValue['description'] // The FormData instance also contains a list 'files' representing each file uploaded. if (!fd.hasFiles()){ // return an error - no file was uploaded } if (fd.files[0].size > 10000000){ // return an error - file too large } def fileInputStream = fd.files[0].content def contentType = fd.files[0].contentType def imageFilename = fd.files[0].name // do some stuff ... def image = someService.readImage(fileInputStream) def imageId = someService.saveImage(imageFileName, contentType, description, image); // write response writeJson [success:true, id: imageId] }
#Action Function Delegate There are built-in functions available to every action function.
The following is list:
-
write(byte[] data) - writes data and closes connection
-
write(contentType, byte[] data) - sets Content-Type header to contentType then writes data and closes connection
-
writeJson(Map | List) - writes Map or List as JSON document data and closes connection
-
error(int status, String message) - sets status, sends text message then closes connection
-
header(String httpHeader, String headerValue) - sets header on response
-
location(uri) - sets the location header to uri
-
contentType(contentType) - sets Content-Type header on response
-
redirect(url) - Issues HTTP Redirect (302), sets Location header to the new location.
-
link(actionName, data) - creates a URI to a named-action
-
useResourceDocs(boolean) - If set to true, the classpath:/docs folder will be searched. The first one found will be returned.
-
static_root(String path) - Path to search for static content
-
requestHeader( String header) - returns the specified request header. If multiple values, the first is returned.
-
requestHeaders(String header) - returns all values for the specified request header as List.
-
responseHeader(String headerName) - returns values for response header. If multiple
-
responseHeaders(String headerName) - returns values for response header as List
-
responseHeader(String headerName, String value) - add value to specified response header values to
-
responseHeaders(String headerName, List valueList) - set response header values to valueList
-
toMap(Object bean) - converts objects into Map instances. Bean property names become the keys and bean property values become the value.
gServ © 2014-2017 Lee Collins. All rights reserved.