Providing REST APIs
In addition to calling REST APIs, Longview Application Framework also serves as the framework to provide REST APIs. Rather than providing a fixed set of APIs, Longview provides a framework for Solution Developers to design their own Solution-level APIs. This framework uses Longview Application Framework to expose Apps, that conform to a prescribed format, as REST APIs. In this manner, Longview makes it possible to invoke any Application Framework procedure from a third-party.
Examples of possibilities include:
- retrieving data from Data Tables
- synchronizing environments using Symbol Maintenance and Attribute Maintenance commands
- creating and posting a Tax Provision Calculated JE from a Longview Tax system to a Longview Close system
This section describes how to build an Application Framework Procedure that can be used to provide a REST API.
The general steps involved in Providing a REST API include:
- A Session API is first called from the third-party application (the “REST consumer”), as an http(s) POST request to get a session.
- Once the session is created, a Solution API request is initiated from the third-party application as an http(s) request.
- The request travels via http(s) to Longview instance’s web server.
- Longview launches an Application Framework session to handle the request.
- The Application Framework procedure in the Solution API should be coded to handle the request and generate a response in a defined format.
- Longview delivers the response back to the third-party caller application.
- The calling application processes the results.
- A Session API is called from the third-party application as an http DELETE request to destroy the session.
URL Syntax
REST APIs are delivered via the existing Longview Web Bridge component. Therefore, the URL to access REST APIs will begin with the standard Web Bridge URL (as defined in the server configuration parameter WEB_SERVER_BRIDGE). Appended to this URL will be the Longview system identifier, followed by the keyword “API”, then “session” (for session APIs) or “app” (for Solution APIs). Solution APIs may have additional path elements and query string parameters.
The general http(s) request format is as follows:
method webServerBridge/LVIdentifier/API/type[/pathToAPI][?queryString]
where
- method is one of the following: POST, PUT, GET, DELETE
- webServerBridge is the standard URL for the instance’s web server bridge
- LVIdentifier is the Longview system identifier
- type is one of the following: session, app
-
pathToAPI is an optional parameter specifying the path and Longview Application Framework procedure to run. The default procedure is
rest.lvpro
if this parameter is not specified. If this parameter is specified, it specifies the path, or a specific filename. -
queryString is an optional parameter and specifies any additional variables to be appended to the URL. The queryString must be in the format
name=value
.
Examples of URL Syntax for Calling a Solution API:
GET http://LVWebserver/cgi-bin/DEMO101/lvweb.cgi/DEMO101/API/app
GET http://LVWebserver/cgi-bin/ DEMO101/lvweb.cgi/DEMO101/API/app/hello.lvpro?Var1=Value1&Var2=Value2
GET http://LVWebserver/cgi-bin/ DEMO101/lvweb.cgi/DEMO101/API/app/folder1/hello.lvpro?Var1=Value1
API Status Codes
The following status codes may be returned by Session or Solution API calls:
Code | Description |
---|---|
200 OK (ok) |
OK |
400 |
Bad request (if problem is detected with input parameters) |
401 |
Unauthorized (authentications fails, or API request made without a valid web session ID) |
404 |
Not found (API not found) |
200 OK (error) |
Server error |
Session APIs
Before executing any Solution APIs, the caller must first authenticate and obtain an authentication token to be provided in subsequent calls. Callers should also terminate the session when they have completed all requests.
Creating a New Session - POST "/API/session"
You can create a session using either Longview authentication or Single Sign-On (SSO) authentication.
Note: LongviewClientID must be set to the same value as the Longview Identifier if the Longview Identify Policy (LV_IDENTIFIER_POLICY) is set to ENFORCE.
To create a session using Longview Authentication:
The message body is JSON containing the following parameters (all strings):
- LongviewUserName: name of the user
- LongviewPassword: password for the user
- LongviewGroup (optional, only required if the user belongs to more than one group)
- LongviewClientID: the Longview identifier
To create a session using ISW Platform authentication:
The first step is to obtain an access_token from the ISW platform using the interface it provides. Next, pass the access token to create a new Longview session.
The message body is JSON containing the following parameters (all strings):
- LongviewUserName: name of the user
- AADToken: the access token returned by the SSO provider
- LongviewGroup (optional, only required if the user belongs to more than one group)
- LongviewClientID: the Longview identifier
To create a session using Longview Single Sign-On:
The first step is to obtain an access_token from your SSO provider using the interface it provides. Next, pass the access token to create a new Longview session.
The header includes the authorization via Bearer Token.
The message body is JSON containing the following parameters (all strings):
LongviewGroup (optional, only required if the user belongs to more than one group)
LongviewClientID: the Longview identifier
LongviewAuthMode: “3rdAuth”
To create a session using OPENID/oAuth2 without Longview Single Sign-On:
The first step is to obtain an access_token from your SSO provider using the interface it provides. Next, pass the access token to create a new Longview session.
The message body is JSON containing the following parameters (all strings):
Id_token: The access token provided by OPENID/oAuth2
LongviewGroup (optional, only required if the user belongs to more than one group)
LongviewClientID: the Longview identifier
Result:
In any case, if authenticated, the response body is also JSON, containing the following properties:
LongviewWebSID (string) to be used for subsequent requests
LongviewErrorCode (integer)
LongviewErrorMessage (string).
Destroying a Session – DELETE “/API/session”
Callers should also terminate the session when they have completed all requests by destroying the session. To destroy a session, you must provide the LongviewWebSID as an http header.
Creating Solution-level APIs
Solution-level APIs may be called using any of the following http methods: GET, PUT, POST, DELETE. This method is passed along as a parameter to the Application Framework procedure so that the Solution Developer can implement accordingly. The path to all Solution APIs begins with [webbridge]/API/app/… and must end with a relative path to an Application Framework procedure published to the Longview Data Servers’ applications\APIs folder. The path may point directly to a document, or can specify only the path, in which case rest.lvpro is used.
Note:
The path may also extend beyond the real folder path, allowing for the use of virtual folders to denote a noun resource upon which the http method (or “verb”) is acting. An example of this might be an API to create Longview symbols. The path for such an API could be
/APIs/app/symbols/entities/newEntity
.The method would be POST, meaning the caller intends to create a new symbol. The actual physical path would be only
applications\APIs\symbols
. In that path, the rest.lvpro procedure would be executed.The remaining portion of the path,
/entities/newEntity
, would be passed along as parameters that could mean “create a symbol in the Entities dimension” and “the name of the new symbol is newEntity” respectively.
All calls to Solutions APIs must provide the LongviewWebSID as an HTTP header.
In the case of a PUT or POST method, the message body supplied can be any format. This content is written to a temporary file and passed to the Application Framework procedure for processing by the Solution API.
All methods can return content, again, in any format. This content is written to a temporary file by Application Framework and assembled into the HTTP response.
Application Framework Variables
When an Application Framework Solution API procedure is executed, the following system variables will be provided:
Variable Name | Description |
---|---|
LVS_APIRequestType |
"POST", "PUT", "GET" or "DELETE" |
LVS_APIRequestPath |
path of the URL request For example, if the request is http://localhost/cgi-bin/ LongviewSimple/lvweb.cgi/LongviewSimple/API/app/path1/ path2/path3/path4 and rest.lvpro is found in the folder path2, then LVS_APIRequestPath contains path2/path3/path4 |
LVS_APIInputContentType |
content type of message body (only relevant for POST or PUT) |
LVS_APIInputFile |
name (full path) of temp file containing message body |
LVS_APIOutputFile |
name (full path) of temp file to which message response should be written |
LVS_APIOutputHeaderFile |
output headers set by the Application Framework command RESTAPI SETREQUESTHEADER in the REST API procedure |
LVS_APIRequestPathParameters |
path of the URL request starting from where rest.lvpro is located. This only applies when the default rest.lvpro is used. It does not apply if a specific document has been specified. For example, if the request is http://localhost/cgi-bin/ LongviewSimple/lvweb.cgi/LongviewSimple/API/app/path1/ path2/path3/path4 and rest.lvpro is found in the folder path2, then LVS_APIRequestPathParameters contains path3/path4 |
APIRequestParameters |
form data submitted with the REST request. This variable can be used when the REST API is called by a third-party application via a form submit. |
Additional global variables will be added to the Application Framework session corresponding to any parameters added to the URL of the request. The example below adds two global variables, Param1 and Param2:
http://URL/API/app/pathtoAPI?Param1=Value1&Param2=Value2
Application Framework Commands and Functions
The following table lists the available Application Framework Procedure commands and functions to support providing REST APIs in Longview. For more information, see the Longview Developer Guide.
Command/Function | Usage |
---|---|
RESTAPI SetResponseHeader |
Set customer HTTP headers for a response. |
GetDocumentSize |
Returns the document size in memory. The document must be loaded into memory, and saved if contents have been modified, when this function is called. The GetDocumentSize function is useful when creating Solutions-level REST APIs that may be called by third-party applications. In this case, it can be used to set the content-length header for the REST API. |
The following illustrates a sample series of API calls:
Create Session
API call | Description |
---|---|
URL |
POST http://localhost/cgi-bin/LongviewSimple/ lvweb.cgi/LongviewSimple/API/session |
Message Body |
{ “LongviewUserName”: “user1”, “LongviewPassword”: “password”, “LongviewGroup”: “Administrators”, “LongviewClientID”: “LongviewSimple” } |
Reply Content-type |
JSON |
Reply Content |
{ “LongviewWebSID”: “--authtoken--”, “LongviewErrorCode”: 0, “LongviewErrorMessage”: “” } |
Make a GET Request
API call | Description |
---|---|
HTTP Headers Expected |
Content-type LongviewWebSID |
URL |
GET http://localhost/cgi-bin/LongviewSimple/lvweb.cgi/LongviewSimple/API/app |
Reply Content-type |
The content type that hello.lvpro assigns using the RESTAPI SetResponseHeader command |
Reply Content |
The content that hello.lvpro writes to LVS_APIOutputFile |
Make a POST Request
API call | Description |
---|---|
HTTP Headers Expected |
Content-type LongviewWebSID |
URL |
POST http://localhost/cgi-bin/LongviewSimple/lvweb.cgi/LongviewSimple/API/app |
Content-type |
Text/csv |
Content |
Symbol,symbol,symbol,symbol,symbol,value Symbol,symbol,symbol,symbol,symbol,value etc |
Reply Content-type |
The content type that hello.lvpro assigns using the RESTAPI SetResponseHeader command |
Reply Content |
The content that hello.lvpro writes to LVS_APIOutputFile |
Terminate a Session
API call | Description |
---|---|
HTTP Headers Expected |
Content-type LongviewWebSID |
URL |
Delete http://localhost/cgi-bin/LongviewSimple/lvweb.cgi/LongviewSimple/API/session |
Implementing custom REST APIs
The solutions framework provides utilities to support providing REST APIs with a standard implementation methodology.
API Code Library Variables and Properties
Name | Type | Use |
---|---|---|
API |
OBJECT |
Contains API properties |
API.AcceptableContentTypes |
STRING[] |
Used to define the acceptable content types for a GET request (CheckAccept) or a PUT / POST request (CheckContentType) |
API.AllowedMethods |
STRING |
Comma separated list of methods Default is GET, HEAD Used to confirm the method on the target URI (CheckMethod) and returned as Allow header when 405 returned |
API.BaseURI |
STRING |
The base URI for REST requests. Defaults to $LVS_HTTPPROTOCOL$://$LVS_WEBSERVER$ $LVS_WEBBRIDGE$/$LVS_IDENTIFIER$/api/app |
API.ContentLength |
NUM |
Used to return the Content-Length response header |
API.POSTURI |
STRING |
Used to store the URI for a resource created using the POST method |
API.ResponseContentType |
STRING |
Used to return the Content-Type response header |
API.SaveOutputFileOnFinalize |
NUM |
Indicates whether the Finalize procedure should save the output document Default is 1 |
API.Params |
OBJECT |
Used to hold the parameters defined in the request |
API.Params.RequestType |
STRING |
The method sent in the request Default $LVS_APIRequestType$ |
API.Params.RequestPath |
STRING |
The part of the URI after /app Default $LVS_APIRequestPath$ |
API.Params.Request |
STRING |
The part of the URI that remains after the Rest.lvpro is found. Default $LVS_APIRequestPathParameters$ |
API.Params. |
STRING[] |
Request path parameters expressed as a list (divided by ‘/’) |
API.Params.InputContentType |
STRING |
The Content-Type in the request header (PUT / POST) Default: $LVS_APIInputContentType$ |
API.Params.InputFile |
STRING |
The name of the file containing the body of the request (PUT / POST) Default: $LVS_APIInputFile$ |
API.Params.OutputHeaderFile |
STRING |
The name of the file containing the response header. Set via the RESTAPI SETRESPONSEHEADER command Default: $LVS_APIOutputHeaderFile$ |
API.Params.OutputFile |
STRING |
The name of the file containing the response body. Default: $LVS_APIOutputFile$ |
API.Params.Request |
STRING |
Form data submitted with a REST request. Default $LVS_APIRequestParameters$ or $APIRequestParameters$ |
API.Services |
OBJECT |
Used to determine if a service is provided For each service provided at the location of the URI to your REST API, add a property with the name of the service with type NUM For example, if your base URI is: /api/app/custom And you provide data services at /api/app/custom/data And symbol services at /api/app/custom/symbols Add the following properties to API.Services: API.Services.data API.Services.symbols |
API_Input |
OBJECT |
If the request body Content-Type is applications/json, used to hold the request body in an object for processing |
API_Output |
OBJECT |
If the response body Content-Type is applications/json, used to hold the response body in an object for processing |
API_RequiredQueryParameterList |
STRING[] |
Holds a list of required query parameters for the request handler. Used to check for a bad request due to missing query parameters (CheckRequiredQueryParameters). |
API_ResponseHeaders |
OBJECT[] |
Used to hold the list of response headers |
API_ResponseHeader |
OBJECT |
Used to define a response header |
API_ResponseHeader.Name |
STRING |
The name of the response header field |
API_ResponseHeader.Value |
STRING |
The value of the response header field |
General Structure
A procedure named Rest.lvpro is provided under applications/APIs/custom. The name of the folder (custom) will represent the part of the URI path after /app.
The Rest procedure contains the logic to determine what service it is providing, with all other logic contained the REST configuration library, provided in Longview Designer. This allows you to update and create additional services provided along the /app/custom path without the need to create additional files directly on the application server.
REST.lvpro
////Description: Handles a REST request
//Load supporting code libraries and error handling
LoadKAR "Solutions\CL\API.kar" ""
Run PROCEDURE "API\Init.lvpro"
OnError TERMINATE "$CORE_ErrorFileName$" "API\OnError.lvpro"
//Create response body document for finalize
Create DOCUMENT "$API.Params.OutputFile$"
//Load the REST configuration library that contains the REST handler procedure and initialize it
LoadKAR "Libraries\REST.kar" ""
Run PROCEDURE "Init.lvpro"
If "$API.Params.RequestPathParameters$" == ""
Run PROCEDURE "custom\RestHandler.lvpro"
Else
If PropertyExists("API_Services.$API.Params.RequestPathParameterList[1]$")
Run PROCEDURE "custom\$API.Params.RequestPathParameterList[1]$\RESTHandler.lvpro"
Else
Run PROCEDURE "API\SetStatus_404.lvpro"
END If
END If
//Finalize
Run PROCEDURE "API\Finalize.lvpro"
Overview of execution
- Initialize API code library and set up error handling
- Create a document to hold the response body
- Depending on your process you may need to create your own document or load it if your process creates an output file directly to disk. In that case make sure it is loaded into memory before Finalize is executed.
- Load the REST configuration library and initialize it
- The initialize at a minimum should:
- Add properties to the API_Service object to represent the services that are available
- The initialize at a minimum should:
- Determine which rest handler to execute
- If the URI request ends with the folder that the rest procedure resides in
- Execute the default RESTHandler custom\RESTHandler.lvpro in the REST configuration library
- If the URI request ends in a path beyond the folder
- Check if that service is valid by checking if a property exists in API_Services with the name of the next part of the path
- If so:
- Execute the RESTHandler.lvpro for that path
- Otherwise
- Return 404 Not Found
- The RESTHandler at a minimum should
- Set the list of allowed methods for the initial path
- Set the Acceptable Content Types
- Run the corresponding method service (ie: GET, HEAD, PUT)
- If the URI request ends with the folder that the rest procedure resides in
- Finalize
Configuration Library Structure
This is the recommended structure for the configuration library. The Rest procedure outlined above will execute for all URIs starting from the custom folder. Any additional paths in the URI will be captured as rest path parameters.
- Create procedure RESTHandler.lvpro for each path in your URI (level 2)
- Create a procedure named after the method is handles for each path in your URI (level 2)
Example:
Assume your rest path is named custom and provides the following services:
- custom/data (GET, PUT)
- custom/symbols (GET)
On the data server applications\APIs folder there is a folder named custom with the procedure Rest.lvpro as outlined above.
Your configuration library contains the following:
- Init.lvpro
- Adds the properties data and symbols to the API_Services object
Example:
Create PROPERTY API_Services.data AS NUM
Create PROPERTY API_Services.symbols AS NUM
- custom\RESTHandler.lvpro
- Sets the property API.AllowedMethods to “GET, HEAD, PUT”. This can be adjusted as required.
- Execute API\CheckMethod.lvpro
- Sets the valid Acceptable Content Types to */*, application/json and application/*. This can be adjusted as required.
- If valid
- Execute the procedure custom\$API.Params.RequestType$.lvpro
- custom\GET.lvpro: Handles a GET request for the URI /custom. By default, it will cycle through the available API_Services properties and provide the links in JSON format.
- custom\data\RESTHandler.lvpro
- Sets the property API.AllowedMethods to “GET, PUT”
- Executes API\CheckMethod.lvpro
- If valid
- Executes the procedure custom\$API.Params.RequestType$.lvpro
- custom\data\GET.lvpro: Handles a GET request for the URI / custom/data
- custom\data\PUT.lvpro: Handles a PUT request for the URI / custom/data
- custom\symbols\RESTHandler.lvpro
- Sets the property API.AllowedMethods to “GET”
- Execute API\CheckMethod.lvpro
- If valid
- Execute the procedure custom\$API.Params.RequestType$.lvpro
- custom\symbols\GET.lvpro: Handles a GET request for the URI /custom/symbols
API Code Library Utilities
The API code library contains several procedures that can be used with any rest service and support standard request checks and steps to deliver a proper response to a request.
Init
Procedure Name: API\Init.lvpro
Prerequisites:
- None
Initialize the API code library:
- Creates global variables and initializes the API object
- Writes a message to server audit trail that the REST request is being handled
Set Status
Procedure Name: API\SetStatus_<StatusCode>.lvpro
Where StatusCode is one of 200 / 201 / 400 / 404 / 405 / 406 / 415 / 500
Prerequisites:
- Execute API\Init.lvpro
A procedure for each supported status is provided. Each procedure is named SetStatus<Status Code>.lvpro.
The following status procedure are provided:
- SetStatus_200.lvpro: 200 OK
- Used to report a successful request
- Sets the Status response header to “200 OK”
- Sets the LVStatus response header to “ok”
- SetStatus_201.lvpro: 201 Created
- Used to report a successful POST request
- Property API.POSTURI must be set before calling this procedure
- Sets the Status response header to “201 Created”
- Sets the Location response header to “$API.POSTURI$”
- SetStatus_400.lvpro: 400 Bad Request
- Used to report an invalid request
- Sets the Status response header to “400 Bad Request”
- Sets the Content-Type response header to “text/plain”
- SetStatus_404.lvpro: 404 Not Found
- Used to report a URI that points to an invalid resource
- Sets the Status response header to “404 Bad Request”
- Sets the Content-Type response header to “text/plain”
- SetStatus_405.lvpro: 405 Method Not Allowed
- Used to report when the method in the request is not provided by the resource specified in the URI
- Sets the Status response header to “405 Method Not Allowed”
- Sets the Allow response header to “$API.AllowedMethods$”
- Sets the Content-Type response header to “text/plain”
- Normally called from API\CheckMethod.lvpro, not directly
- SetStatus_406.lvpro: 406 Not Acceptable
- Used to report when the Accept request header does not contain a media type that is supported by the service
- Sets the Status response header to “406 Not Acceptable”
- Sets the Content-Type response header to “application/json”
- Writes an object in JSON to the response body with the property “ContentTypes”, which lists the content types specified in API.AcceptableContentTypes
- Normally called from API\CheckAccept.lvpro, not directly
- SetStatus_415.lvpro: 415 Unsupported Media Type
- Used to report when the Content-Type in the request (PUT / POST) is not supported for the resources specified in the URI
- Sets the Status response header to “415 Unsupported Media Type”
- Sets the Content-Type response header to “application/json”
- Writes an object in JSON to the response body with the property “MediaTypes”, which lists the content types specified in API.AcceptableContentTypes
- Normally called from API\CheckContentType.lvpro, not directly
- SetStatus_500.lvpro: 200 OK
- Used to report any other execution error
- Sets the Status response header to “200 OK”
- Sets the LVStatus response header to “error”
- Sets the Content-Type response header to “text/plain”
- Normally called from API\OnError.lvpro, which writes the contents of the error file to the response body
Check Method
Procedure Name: API\CheckMethod.lvpro
Prerequisites:
- Execute API\Init.lvpro
- Set property API.AllowedMethods (default is GET, HEAD)
Checks if the method in request (API.RequestType) is in the list of allowed methods (API.AllowedMethods). If not:
- Sets variable CORE_IsNoError = 0
- Executes API\SetStatus_405.lvpro
Check Accept (Use with GET / HEAD requests)
Procedure Name: API\CheckAccept.lvpro
Prerequisites:
- Execute API\Init.lvpro
- Set property API.AcceptableContentTypes
Checks if the Accept in request header is in the list of acceptable content types (API. AcceptableContentTypes). If not:
- Sets variable CORE_IsNoError = 0
- Executes API\SetStatus_406.lvpro
Otherwise:
- Sets property API.ResponseContentType to the first acceptable content type found
Check Content Type (Use with POST / PUT requests)
Procedure Name: API\CheckContentType.lvpro
Prerequisites:
- Execute API\Init.lvpro
Checks if the Content-Type in request header is in the list of acceptable content types API.Params.InputContentType). If not:
- Sets variable CORE_IsNoError = 0
- Executes API\SetStatus_415.lvpro
Check Required Query Parameters
Procedure Name: API\CheckRequiredQueryParameters.lvpro
Prerequisites:
- Execute API\Init.lvpro
- Set variable API_RequiredQueryParameterList
Checks if the variables specified in API_RequiredQueryParameterList exist. If not:
- Sets variable CORE_IsNoError = 0
- Executes API\SetStatus_400.lvpro
- Sets the Content-Type response header to text/plain
On Error Handler
Procedure Name: API\OnError.lvpro
Prerequisites:
- Execute API\Init.lvpro
- Execute OnError command to call this procedure when an error occurs
- OnError TERMINATE "$CORE_ErrorFileName$" "API\OnError.lvpro"
Handles any execution errors that occur:
- Sets variable CORE_IsNoError to 0
- Writes the error file generated to the response body (API.Params.OutputFile)
- Executes API\SetStatus_500.lvpro
- Executes API\Finalize.lvpro
Write JSON Result
Procedure Name: API\WriteResultJSON.lvpro
Prerequisites:
- Execute API\Init.lvpro
- Populate the API_Output object
Writes the API_Output object to the response body and sets the Content-Type response header to application/json.
Finalize
Procedure Name: API\Finalize.lvpro
Prerequisites:
- Execute API\Init.lvpro
Finalizes the REST request by:
- Getting the size of the response body document ($API.Params.OutputFile$), which must be in memory
- Set the Content-Length response header
- If $API. SaveOutputFileOnFinalize$ == 1
- Saves the output file
- Writes a message to the server audit trail that the REST request was handled