OHI HTTP Library
Introduction
The OHI HTTP Library simplifies interaction with Java REST APIs, enabling developers to write dynamic logic in a Groovy-friendly style.
Key Components
-
OhiHttpRequest
: A class designed to configure request parameters and execute HTTP calls based on a specified payload. -
OhiHttpResponse
: A class responsible for storing responses received from HTTP calls, simplifying the handling of API interactions.
Working with the OHI HTTP Library
OhiHttpRequest
This class simplifies the creation of requests using the ohiHttpRequest()
method and facilitates making HTTP calls to the provided URL.
def request = ohiHttpRequest("destinationCode") String response = request.get("eclipse/callout", paramsMap)
ohiHttpRequest(String destinationCode)
Method to create an instance of OhiHttpRequest
for making HTTP calls to the specified destination code.
OIG Use Case
The URL is fetched based on the destinationCode
defined in the RestDestination
(OIG_DESTINATIONS) configuration.
- Example
def httpRequest = ohiHttpRequest(POLICIES_API_GET)
Here the destination code POLICIES_API_GET will be resolved from OIG Destinations configuration.
Non OIG use case
The URL is constructed from the value defined in the property ohi.{0}.endpoint.request
; here, the placeholder {0} is replaced by the destination code to fetch the endpoint.
Typically, the destination code used in this context corresponds to either the dynamic-logic code associated with the callout rule or the callout rule code itself.
- Example
def httpRequest = ohiHttpRequest("enrollment")
Here the destination code is passed as enrollment, then the URL will be derived from the property ohi.enrollment.endpoint.request
.
ohiHttpRequest(String destinationCode, String location)
This API enables the reuse of credential keys and allows you to leverage location headers returned from previous HTTP calls, provided that the context path of the location matches the path defined in the RestDestination configuration associated with the specified destinationCode
.
- Example
def httpRequest = ohiHttpRequest(POLICIES_API_GET, previousResponse.stringHeaders.Location) def paramsMap = [headers: ["Accept": "application/json"]] //Invoke the API to get the OHI response def newResponse = httpRequest.get(paramsMap) if(newResponse.status == 200){ String strResponse = response.body }
ohiHttpRequest()
Create an instance of OhiHttpRequest
to perform HTTP calls. The destination endpoint is dynamically resolved based on the currently executing dynamic logic code.
Non OIG use case only
The URL is constructed from the value defined in the property ohi.{0}.endpoint.request
; here, the placeholder {0} is replaced by dynamic-logic code associated with the callout rule or the callout rule code itself.
- Example
-
For instance, the HTTP calls are made from dynamic logic
POL_DYLO_PROCESS_REFUND
def httpRequest = ohiHttpRequest()
When an instance of OhiHttpRequest is created without specifying a destination code, the endpoint is dynamically generated based on the dynamic logic code associated to the current execution context. The placeholder {0} in the property ohi.{0}.endpoint.request is replaced with the dynamic logic code, creating a property name like ohi.POL_DYLO_PROCESS_REFUND.endpoint.request , which is then used to retrieve the corresponding endpoint.
|
If no endpoint can be derived using the dynamic logic code, the system falls back to using the CallOutRule code. In this case, the placeholder {0} is replaced with the CallOutRule code, forming a property name like ohi.PROCESS_REFUND.endpoint.request
, which is then used to determine the endpoint.
OhiHttpResponse put(String path, Map<String, Map<String, Object>> paramsMap)
Method for HTTP PUT
operation returns OhiHttpResponse
.
- Example
def procedureGroupDetailPayload = <payload> def existingProcedureGroup = <some_existing_procedure_group_object> def paramsMap = [ headers: [ "Accept": "application/json" ], data: ["json": procedureGroupDetailPayload] ] def response = ohiHttpRequest(CLAIMS_API_GET) .put("generic/proceduregroupdetails" + existingProcedureGroup.id.toString(), paramsMap)
OhiHttpResponse put(Map<String, Map<String, Object>> paramsMap)
Method for HTTP PUT
operation returns OhiHttpResponse
.
Use this approach if the absolute path is already defined during the creation of the OhiHttpRequest
[ohiHttpRequest(String destinationCode)].
- Example
def procedureGroupDetailPayload = <payload> def paramsMap = [ headers: [ "Accept": "application/json" ], data: ["json": procedureGroupDetailPayload] ] def response = ohiHttpRequest(CLAIMS_API_GET).put(paramsMap)
OhiHttpResponse post(String path, Map<String, Map<String, Object>> paramsMap)
Method for HTTP POST
operation returns OhiHttpResponse
.
- Example
def searchPayload = <payload> def httpRequest = ohiHttpRequest(CLAIMS_API_GET) def paramsMap = [ headers: [ "Accept": "application/json" ], data: ["json": searchPayload] ] def response = httpRequest.post("claims/search", paramsMap)
OhiHttpResponse post(Map<String, Map<String, Object>> paramsMap)
Method for HTTP POST
operation returns OhiHttpResponse
.
Use this approach if the absolute path is already defined during the creation of the OhiHttpRequest
[ohiHttpRequest(String destinationCode)].
- Example
def searchPayload = <payload> def httpRequest = ohiHttpRequest(CLAIMS_API_SEARCH) def paramsMap = [ headers: ["Accept": "application/json"], data: ["json": searchPayload] ] def response = httpRequest.post(paramsMap)
OhiHttpResponse patch(String path, Map<String, Map<String, Object>> paramsMap)
Method for HTTP PATCH
operation returns OhiHttpResponse
.
- Example
def groupClientPayload = <payload> def paramsMap = [ headers: ["Accept": "application/json"], data: ["json": groupClientPayload] ] def response = ohiHttpRequest(POLICIES_API_GET).patch("groupclients", paramsMap)
OhiHttpResponse patch(Map<String, Map<String, Object>> paramsMap)
Method for HTTP PATCH
operation returns OhiHttpResponse
.
Use this approach if the absolute path is already defined during the creation of the OhiHttpRequest
[ohiHttpRequest(String destinationCode)].
- Example
def groupClientPayload = <payload> def paramsMap = [ headers: ["Accept": "application/json"], data: ["json": groupClientPayload] ] def response = ohiHttpRequest(POLICIES_API_GET).patch(paramsMap)
OhiHttpResponse get(String path, Map<String, Map<String, Object>> paramsMap)
Method for HTTP GET
operation returns OhiHttpResponse
.
- Example
def premiumScheduleURL = "premiumschedulelines/PS_TEST_001/defaulttimeperiod/2025-04-07" def paramsMap = [ queryParams: ["limit": "200"], headers: ["Accept": "application/json"] ] def queryResponse = ohiHttpRequest("POLICIES_API_DEST_CODE").get("generic/" + premiumScheduleURL, paramsMap)
OhiHttpResponse get(Map<String, Map<String, Object>> paramsMap)
Method for HTTP GET
operation returns OhiHttpResponse
.
Use this approach if the absolute path is already defined during the creation of the OhiHttpRequest
[ohiHttpRequest(String destinationCode)].
- Example
def httpRequest = ohiHttpRequest("premiumSchedules") def paramsMap = [ queryParams: ["limit": "200"], headers: ["Accept": "application/json"] ] def queryResponse = httpRequest.get(paramsMap)
OhiHttpResponse delete(String path)
Method for HTTP DELETE
operation returns OhiHttpResponse
.
- Example
def refSheetLineId = <reference_sheet_line_id> def refSheetLinesResponse = ohiHttpRequest(RestDestinationsConstants.CLAIMS_API_GET).delete( "generic/referencesheetlines/reprocessARHGProviders/"+ refSheetLineId )
Contents of the paramsMap in the OhiHttpResponse APIs
Allowed Keys | Description | Possible Values | Example |
---|---|---|---|
queryParams |
Key to pass query params |
key-value pair of the query params |
queryParams: ['person': eligibilityCheck.person.code, |
headers |
Key to pass headers |
key-value pairs of headers |
headers: ['Accept': |
data |
Key to pass payload data in the request |
Possible keys are:
|
|
property |
Key to pass properties associated with jersey client |
key-value pair of the property params |
property: ['jersey.config.client.followRedirects', |
APIs of OhiHttpResponse
Method | Description | Example |
---|---|---|
int getStatus() |
Returns HTTP status code from the response |
if(response.status == 200) { //logic here} |
String reasonPhrase() |
Returns response code as String |
if(response.reasonPhrase == "Created") { // logic here} |
Map<String, Object> getHeaders() |
Returns all the headers from the response Use this method when you need to access headers that might have values in other formats (e.g., dates or custom objects) or when you’re unsure of the types of the header values |
URI location = response.headers.Location |
Map<String, String> getStringHeaders() |
Returns map of headers from the response Use this method when you know that the headers you are interested in will be simple strings |
String location = response.stringHeaders.Location |
String getHeaderString(String headerName) |
Returns the specific header as String Use when you only need to access the value of a specific header and you are sure that the header will exist |
String location = response.headerString("Location") |
getBody() |
To get the response body as String |
String responseData = response.body |
Examples
The following examples demonstrate how to utilize these custom classes to create dynamic logic in a Groovy-style syntax, showcasing their flexibility and ease of use.
Reuse of OhiHttpRequest
Once the OhiHttpRequest
is declared, it can be reused multiple times to make different API calls.
In the following example, OhiHttpRequest
is initialized with the Policies endpoint (http://host:port/policies-ws/api).
This OhiHttpRequest
object can be reused to make different API calls:
-
Search policies -
generic/policies/search
-
Search providers -
generic/providers/search
// Initialize the request with required target. def httpRequest = ohiHttpRequest(POLICIES_API_GET) //define the search policy destination path def searchPolicies = "generic/policies/search" //define search policy body def strBody = '''{"resource": { "q": "code.like('TEST_POL%')"}}''' //define the headers and request body as data in the paramsMap def paramsMap = [ headers: [ "Accept": "application/json", "Content-Type": "application/json" ], data: ["json": strBody] ] //Invoke the API to get the OHI response def response = httpRequest.post(searchPolicies, paramsMap) if (response.status == 200) { def json = response.body // Define what to do with the user response } //Re-use the same request object to get providers //define the providers destination path def genericProviders = "generic/providers/search" //define providers body strBody = '''{"resource": { "q": "code.eq('PROVIDER_CODE')"}}''' //Invoke the API to get the OHI response response = httpRequest.post(genericProviders, paramsMap) if (response.status == 200) { def json = response.body // Define what to do with the user response }
POLICIES_API_GET is the RestDestinationConstant configured for OIG, and this can be replaced with the DynamicLogic Code for OHI.
|
Search Operation Using Pagination
This example demonstrates how to perform a paginated search operation using ohiHttpRequest
. It fetches policy records in chunks and continues to do so until all matching records are retrieved.
import groovy.json.JsonOutput import groovy.json.JsonSlurper // Initialize the request with required target. def httpRequest = ohiHttpRequest(POLICIES_API_GET) //define the search policy destination path def searchPolicies = "generic/policies/search" //Define limits def offset = 0 def limit = 200 def existingPolicies = [] def hasMore = true while (hasMore) { //define search policy body def jsonRequest = [ resource: [ q: "code.like('%POL_TEST_%')", orderBy: "creationDate:asc", offset: $ {offset}, limit: $ {limit}, totalResults: true, resourceRepresentation: [ fields: "code|gid|status" ] ] ] // Convert the map to a JSON string def jsonSearchString = JsonOutput.toJson(jsonRequest) //define the headers and request body as data in the paramsMap def paramsMap = [ headers: [ "Accept": "application/json", "Content-Type": "application/json" ], data: [ "json": jsonSearchString ] ] //Invoke the API to get the OHI response def response = httpRequest.post(searchPolicies, paramsMap) //Check the status, and if sucesses get policies and add them to existing policies list //check hasMore if true, then fetch next set of records. if (response.status == 200) { def policies = new JsonSlurper().parseText(response.body) existingPolicies.addAll(policies.items) hasMore = policies.hasMore } else if (response.status != 200) { throw new Exception("Request not processed " + response.status) } //increment the offset offset = offset + limit }
POLICIES_API_GET is the RestDestinationConstant configured for OIG, and this can be replaced with the DynamicLogic Code for OHI.
|
Fetch Location Header from the Response
This example demonstrates how to extract the Location
header from an HTTP response after sending a POST
request to an API endpoint. The purpose of this code is to retrieve the URL of a newly created resource, typically returned in the Location
header when the server responds with a 201 Created
status code.
// Initialize the request with required target. def httpRequest = ohiHttpRequest(OIG_API_GET) //define the destination path def path = "exchanges/integration/prepareTaxRegister" //define providers body String payload = <payload> //define the headers and request body as data in the paramsMap def paramsMap = [ headers: ["Accept": "application/json"], data: ["json": payload] ] //Invoke the API to get the OHI response def response = httpRequest.post(path, paramsMap) if (response.status == 201) { //Get the header location as "response.stringHeaders.Location" exchangeStep.addLogEntry("Exchange [" + exchangesStarted + "] started : " + response.stringHeaders.Location) } else { exchangeStep.addLogEntry("Not able to invoke prepare Tax Register integration please check : " + response.status + "-" + response.body) }
Using MultiValue Headers
Multi-value headers can be used when a response may contain multiple values for the same header. Unlike stringHeaders
, which returns a single string per header, headers
returns a list of all values, making it the preferred choice for handling multi-value headers.
This example shows how to retrieve multi-value headers like Location
and Date
from an HTTP response.
// Initialize the request with required target. def httpRequest = ohiHttpRequest(POLICIES_API_GET) //define the destination path def path = "generic/brands" //define body def payload = '''{ "code": "A_HOSP_WEST", "descr": "Westside Hosp A" }''' //define the headers and request body as data in the paramsMap def paramsMap = [ headers: ["Accept": "application/json"], data: ["json": payload] ] //Invoke the API to get the OHI response def response = httpRequest.post(path, paramsMap) if (response.status == 201) { //Get the headers print "Location: " + response.headers.Location print "Creation Date: " + response.headers.Date }
Enabling Automatic Redirects in HTTP Requests
This example demonstrates how to enable automatic redirects in HTTP requests using the jersey.config.client.followRedirects
property. By default, this property is set to false, which means that the client will not follow redirects and instead return a 303 See Other
response.
// Initialize the request with required target. def httpRequest = ohiHttpRequest(CLAIMS_API_GET) //define the destination path def path = "claims/" + claimData.id + "/tochange" //define the headers and request body as data in the paramsMap def paramsMap = [ headers: ["Accept": "application/json"], property: ["jersey.config.client.followRedirects": Boolean.TRUE] ] //Invoke the API to get the OHI response def response = httpRequest.post(path, paramsMap) if (response.status != 200) { throw new IllegalStateException("Pend could not be resolved for Claim code: ${claimData.code}\n" + response.status + ":" + response.body) }
Using a Returned Location Header from a WebTarget POST Operation
This example demonstrates how to leverage the Location header returned from a successful POST
operation to fetch the newly created resource, ensuring that the subsequent GET
request targets the correct resource.
// Initialize the request with required target. def httpRequest = ohiHttpRequest(POLICIES_API_GET) //define the destination path def path = "/policies/submit" //define payload to create a policy String payload = <payload> def paramsMap = [ headers: ["Accept": "application/json"], data: ["json": payload] ] //Invoke the API to get the OHI response def response = httpRequest.put(path, paramsMap) if (response.status == 201) { //Get the header location as "response.stringHeaders.Location" String location = response.stringHeaders.Location httpRequest = ohiHttpRequest(POLICIES_API_GET, location) paramsMap = [ headers: ["Accept": "application/json"], ] response = httpRequest.get(paramsMap) if (response.status == 200) { exchangeStep.addLogEntry("Policy created " + response.body) } } else { exchangeStep.addLogEntry("Unable to create policy " + response.body) }
Handling Errors and Logging
It is the responsibility of the developer to properly handle errors to ensure robustness and prevent unexpected failures.
When making an HTTP call, developers should always check the HTTP response code and take appropriate action based on its value.
Example of checking response code
import groovy.json.JsonSlurper def httpRequest = ohiHttpRequest("destination_policies_generic") def searchProperties = "/currentproperties" def paramsMap = [ "queryParams": ["name": "ohi.http.api.path"] ] def response = httpRequest.get(searchProperties, paramsMap) if (response.status == 200) { def resp = new JsonSlurper().parseText(response.body) exchangeStep.addLogEntry(resp.items[0].name) }
Example of adding errors to the exchange logs
import groovy.json.JsonSlurper def serviceProviderCode = <service_provider_code> def serviceProviderFlexCode = <service_provider_flex_code> def frmtdCurrDate = dateFormat.format(currentDate) def httpRequest = ohiHttpRequest("CLAIMS_API_GET") def serviceProviderDetails = getResult( httpRequest, "individualproviders", "code.eq('${serviceProviderCode}').and.flexCodeSystem.code.eq" + "('${serviceProviderFlexCode}')", "providerIdentifierList.identifierType.code|" + "providerIdentifierList.address|" + "providerIdentifierList.address.usedFor.code", "all", 1 ) def serviceProviderIdentifier = serviceProviderDetails.providerIdentifierList.find { it.identifierType.code == serviceProviderFlexCode } def serviceAddressDetails = serviceProviderIdentifier?.address?.find { it.usedFor.value == "MAILING" && it ? startDate <= frmtdCurrDate && (it?.endDate >= frmtdCurrDate || it?.endDate == null) } if (serviceAddressDetails) { exchangeStep.addLogEntry('Service Address details : ' + serviceAddressDetails.toString()) } else { exchangeStep.addLogEntry('Error Fetching Service Address Details') } static def getResult(target, resourceName, queryParam, fields, expand, limit) { def acceptString = "application/json;" + (expand ? "expand=${expand};": "") + (fields ? "fields=${fields}": "") def paramsMap = [ queryParams: ["q", queryParam, "limit": limit] headers: ["Accept": acceptString, "Content-Type": "application/json"] ] def response = target.get("generic/" + resourceName, paramsMap) if (response.status != 200 && response.status != 204) { throw new IllegalStateException("Query failed with http status " +"${response.status}") } else if (queryResponse.status == 200) { return new JsonSlurper().parseText(response.body).items.get(0); } return null }