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

Table 1. Contents of paramsMap
Allowed Keys Description Possible Values Example

queryParams

Key to pass query params

key-value pair of the query params

queryParams: ['person': eligibilityCheck.person.code,
'requestDate': requestDate, 'limit': '200']

headers

Key to pass headers

key-value pairs of headers

headers: ['Accept':
'application/xml;
responseDefinitionCode=type1']

data

Key to pass payload data in the request

Possible keys are:

  • json - if the request need to be converted in to JSON body

  • xml - if the request need to be converted in to XML body

  • data: ["json": jsonBuilder.toString()]

  • data: ["xml": xmlBody.toString()]

property

Key to pass properties associated with jersey client

key-value pair of the property params

property: ['jersey.config.client.followRedirects',
Boolean.FALSE]

APIs of OhiHttpResponse

Table 2. 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
(eg. "Created" for 201 HTTP status code )

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
}