Step 3: Parse the request
Using methods of the com.HttpServiceRequest class (among others), parse the details of the request.
An HTTP service request has been received and stored in an instance of a com.HttpServiceRequest
object.
To use the details of the request, the next step is to define a record to hold the pieces of
information that come in with a request and to parse the request into the record. The
demo creates a user-defined type (reqInfoTyp
) to reference when
defining the record.
This topic details how the calculator demo server application parses the instance of the
HttpServiceRequest
object. While your specific HTTP service
requests may differ in the details, the parsing needs will be similar.
TYPE reqInfoTyp RECORD
method STRING,
ctype STRING, # check the Content-Type
informat STRING, # short word for Content Type
caccept STRING, # check which format the client accepts
outformat STRING, # short word for Accept
path STRING,
query STRING, # the query string
items DYNAMIC ARRAY OF RECORD
name STRING,
value STRING
END RECORD
END RECORD
DEFINE m_reqInfo reqInfoTyp
com.HttpServiceRequest
object as input. The purpose of the function will be to
parse the HTTP service request into its components.CALL getReqInfo(req)
The getReqInfo function
reqInfoTyp
record. FUNCTION getReqInfo(req)
req
references the instance of the
HTTP service request object. The variables str
, val
,
token
, and i
are used when parsing out details with the
StringTokenizer classes and
methods.DEFINE req com.HttpServiceRequest
DEFINE str, val base.StringTokenizer
DEFINE token STRING
DEFINE i INT
For
the remainder of this topic, you are retrieving data from the instance of the HTTP service request
object (referenced by the variable req
) and populating the record variable designed
to hold this data (m_reqInfo
).Initialize m_reqInfo
to NULL
. This ensures that there are no
pre-existing values in the record variable.
The variable m_reqInfo
record was defined at the top of the module,
and therefore can be used in this function.
INITIALIZE m_reqInfo TO NULL
m_reqInfo.informat
) with either "XML" or
"JSON".LET m_reqInfo.ctype = getHeaderByName(req,"Content-Type")
IF m_reqInfo.ctype.getIndexOf("/xml",1) THEN
LET m_reqInfo.informat = "XML"
ELSE
LET m_reqInfo.informat = "JSON"
END IF
getHeaderByName
function retrieves the value of the Accept header, and
based on the returned value, populates the output format variable
(m_reqInfo.outformat
) with either "XML" or
"JSON".LET m_reqInfo.caccept = getHeaderByName(req,"Accept")
IF m_reqInfo.caccept.getIndexOf("/xml",1) THEN
LET m_reqInfo.outformat = "XML"
ELSE
LET m_reqInfo.outformat = "JSON"
END IF
m_reqInfo.method
) with the
result.LET m_reqInfo.method = req.getMethod()
While possible values could
include GET, POST, PUT, HEAD, and DELETE, our demo server application expects GET, and the
processing part of the server application code does not test or code for any verbs aside from
GET.parseUrl
function. The path is placed in the path variable
(m_reqInfo.path)
and the query string is placed in the query variable
(m_reqInfo.query)
.CALL parseUrl(req.getUrl()) RETURNING m_reqInfo.path, m_reqInfo.query
m_reqInfo.query
) and parse out the value pairs using
the StringTokenizer class and methods. The value pairs of variable name and value
are stored in the m_reqInfo.items
dynamic
array.LET str = base.StringTokenizer.create(m_reqInfo.query,"&")
LET i=1
CALL m_reqInfo.items.clear()
WHILE str.hasMoreTokens()
LET token = str.nextToken()
LET val = base.StringTokenizer.create(token,"=")
IF val.hasMoreTokens() THEN LET m_reqInfo.items[i].name = val.nextToken() END IF
IF val.hasMoreTokens() THEN LET m_reqInfo.items[i].value = val.nextToken() END IF
LET i=i+1
END WHILE
By the end of the custom getReqInfo()
function, the HTTP service request object
is parsed into the variables that comprise a reqInfoType
record. The application
can now access the values it needs to process the request.
getHeaderByName function
- The HTTP service request object in an
com.HttpServiceRequest
variable. - The name of the header type whose value you want to return.
In the demo application, this function is used to parse out the value for the Content-Type header request and the Accept header request.
com.HttpServiceRequest
object. The function first counts the number of header
requests, and then cycles through them until it finds the specific header request that is being
asked for. When the match happens, the value for that header is returned; if no match is found, then
NULL is
returned.FUNCTION getHeaderByName(areq,hname)
DEFINE areq com.HttpServiceRequest
DEFINE hname STRING
DEFINE aname STRING
DEFINE iname STRING
DEFINE i INT
DEFINE n INT
LET aname = hname.toLowerCase()
LET n = areq.getRequestHeaderCount()
FOR i=1 TO n
LET iname = areq.getRequestHeaderName(i)
IF aname.equals(iname.toLowerCase()) THEN
RETURN areq.getRequestHeaderValue(i)
END IF
END FOR
RETURN NULL
END FUNCTION
parseUrl fuction
FUNCTION parseUrl(url)
DEFINE url STRING
DEFINE i INT
LET i = url.getIndexOf("?",1)
IF i = 0 THEN
RETURN url, NULL
ELSE
RETURN url.subString(1,i), url.subString(i+1,url.getLength())
END IF
END FUNCTION
For example, the URL being passed in by the demo client application is "http://localhost:8090/add?a=1&b=2". The function then returns the path ("http://localhost:8090/add?") and the query ("a=1&b=2").
For more information see com.WebServiceEngine methods
In the next step we process the incoming request, Step 4: Process the request