WSHeader
Defines custom headers in the request and response of Web service functions.
Syntax
WSHeader
Where:
WSHeader
in an ATTRIBUTES()
clause of an input parameter
or return value of the function defines a HTTP header.
WSHeader
is an optional attribute.
Usage
Use the WSHeader
attribute to define a custom header in an input parameter
or in a return value. Custom headers are commonly used to provide information; however, you
can also use them to pass data that implements logic on the server or client side.
Typically, you use WSHeader
to pass data related to the service in the
form of an HTTP header. For example, an input parameter defined with
ATTRIBUTES(WSHeader,
sets the
standard HTTP authorization header. WSName="Authorization"
)
You can set the WSHeader
attribute on parameters defined as primitive
types, records, arrays, and simple dictionary type.
WSHeader
supports the OpenAPI default styles: style:
simple
and explode: false
. Table 1
shows how the header (X-MyHeader
) is serialized when the parameter
(id
) is a primitive type, an array, record, and a dictionary type. The
dictionary and record types are defined as objects according to the OpenAPI specification.
For further information on OpenAPI serialization, see the Parameter serialization page. style | explode | URI template | Primitive value X-MyHeader = 5 | Array X-MyHeader = [3, 4, 5] | Object X-MyHeader = {"role": "admin", "firstName": "Alex"} |
---|---|---|---|---|---|
simple | false | {id} | X-MyHeader:5 | X-MyHeader: 3,4,5 | X-MyHeader: role,admin,firstName,Alex |
:/?#[]@!$&'()*+,;=
), the GWS engine
serializes them with percent-encoding in the parameter. For
example:DEFINE b DYNAMIC ARRAY OF STRING = ["O,ne", "Two", "Three", NULL, "Five"]
The parameter contains:
O%2Cne,Two,Three,,Five
. The server and the client must deserialize
"O%2Cne
" to "O,ne
" for insertion in Genero
BDL.Use WSName
with
WSHeader
to name headers; otherwise the GWS gives the headers default
names ("rv0", "rv1", etc) at runtime.
Example: WSHeader and WSName in input parameter
In the sample REST function, the Genero Application Server (GAS) environment variable
"X-FourJs-Environment-Variable-REMOTE_ADDR
" that contains the IP address
of the remote client is passed in a header.
As the GAS variable has hyphens ("-"), which are not allowed in Genero BDL variables, the
WSName
attribute is set on the ip_addr
parameter to
identify "X-FourJs-Environment-Variable-REMOTE_ADDR
" in the HTTP request.
ip_addr
parameter is BDL friendly and this is used in the function.
The parameter is also optional as defined by the attribute WSOptional
.
The WSContext attribute, if set, can provide your service with access to environment variables set by the GAS.
PUBLIC FUNCTION getRemoteAddress (ip_addr STRING
ATTRIBUTES(WSHeader,
WSOptional,
WSName = "X-FourJs-Environment-Variable-REMOTE_ADDR") )
ATTRIBUTES (WSGet,
WSPath = "/users/ip",
WSDescription = "Get remote address of the client")
RETURNS (INTEGER ATTRIBUTES(WSHeader), STRING)
DEFINE ip STRING
LET ip = ip_addr
IF ip IS NULL THEN
LET ip = "Got no remote address."
ELSE
LET ip = SFMT("Hello there, you're at %1",ip )
END if
RETURN 3, ip
END FUNCTION
Example responses in header and body
RETURNS
clause has two return values: - An integer is returned in a header. It is specified with the
WSHeader
attribute. - A string is returned in the body. It is specified without an attribute.
PUBLIC FUNCTION help()
ATTRIBUTES (WSGet,
WSPath = "/help")
RETURNS (INTEGER ATTRIBUTE(WSHeader, WSDescription = "Reference number"),
STRING)
RETURN 3, "Hello world"
END FUNCTION
Setting
a standard HTTP header on a response must be handled with care,
especially for those that define the response body such as Content-Type
, or
Content-Encoding
. Make sure what you define with WSName
does not
conflict with what is specified in the OpenAPI documentation for the service.
Example: WSHeader returns a record
RETURNS
clause of the function on a user-defined record type
("T_RECORD
"). The string ("Return record in header: ..." ) is returned in
the response body. PUBLIC TYPE t_user RECORD
user_id INTEGER,
user_name VARCHAR(50)
END RECORD
PUBLIC FUNCTION getUserInfo(
p_user_id INTEGER ATTRIBUTES(WSHeader, WSOptional))
ATTRIBUTES(WSGet,
WSPath = "/v1/ok",
WSDescription = "Return user record in header",
WSRetCode = "202:Accepted",
WSThrows = "400:Bad Request,401:Unauthorized,500:Internal Server Error")
RETURNS(STRING ATTRIBUTES(WSMedia = "application/json"),
t_user ATTRIBUTES(WSHeader))
DEFINE u t_user
SELECT * INTO u.* FROM user WHERE user_id = p_user_id
RETURN "User info is in header...", u
END FUNCTION
Example: WSHeader returns data in a dictionary
In this sample REST function a list of available bikes is returned in a DICTIONARY
OF STRING
set in the custom header dict
.
The function's input parameter thisBike passes a value representing a
model of bike in a header. The WSGet
attribute is set to request details
about thisBike from the service. The dictionary dict
is
queried for details of thisBike.
WSThrows is set to handle errors.
The message
field of the userError
variable is set if the
bike is not found, and a call to SetRestError()
returns the message defined in WSThrows
for the error.
IMPORT com
PUBLIC DEFINE userError RECORD ATTRIBUTE(WSError = "User error")
message STRING
END RECORD
PUBLIC FUNCTION getBikeDetails(
thisBike STRING ATTRIBUTES(WSHeader))
ATTRIBUTES(WSGet,
WSPath = "/bikes",
WSDescription = "Get bike details. Return list of available bikes",
WSRetCode = "202:Accepted",
WSThrows = "404:@userError")
RETURNS(STRING ATTRIBUTES(WSMedia = "application/xml, application/json"),
DICTIONARY ATTRIBUTES(WSHeader, WSName = "dict") OF STRING)
DEFINE b STRING
DEFINE dict DICTIONARY OF STRING
DEFINE keys DYNAMIC ARRAY OF STRING
DEFINE i INT
LET dict["YZF"] = "250cc"
LET dict["Z650"] = "652cc"
LET dict["MT-07"] = "689cc"
LET b = "Bike details"
LET keys = dict.getKeys()
DISPLAY "Number bikes: ", dict.getLength()
FOR i = 1 TO keys.getLength()
DISPLAY i, " ", keys[i], " ", dict[keys[i]]
END FOR
IF dict.contains(thisBike) THEN
LET b = SFMT("This bike has: %1 ", dict[thisBike])
ELSE
LET userError.message = SFMT("Could not find '%1' ", thisBike)
CALL com.WebServiceEngine.SetRestError(404, userError)
END IF
RETURN b, dict
END FUNCTION