Skip to content

Http Callout Local Example

kevinn-veeva edited this page Mar 22, 2019 · 2 revisions

This sample uses the Vault Java SDK HttpService and JsonService interfaces to implement this functionality. These services are available for making HTTP Callouts from within the Vault Java SDK.

For full details on the interfaces and methods used, please review the Javadocs.

Code Logic

This example only operates on the vSDK Http Doctype document in the draft state.

The vSDKLocalHttpCalloutAction document action and vSDKHttpCallouts user-defined class demonstrate how to use an HTTP Callout to make Vault API call within a single local vault.

The example prompts the user for a new owner, viewer, and editor and those roles are updated. Once updated, an HTTP Callout is made to retrieve document actions and then initiate the document's workflow.

Key Concepts

  • The vSDKLocalHttpCalloutAction - takes user input from the vSDK User Input Object and sets new roles on a document. Once the roles have been modified, an HTTP Callout is made to initiate a workflow against the new owner.
    • A User Action Prompt is utilized to allow the user to input new data.
    • This new data is used to assign the new users to relevant roles on the document.
    • Once assigned, the HTTP Callout functionality starts a document workflow.
  • The vSDKHttpCallouts contains the localGetLifecycleActions and localStartDocWorkflow methods to start a local HTTP Callout.

Change User Roles

The vSDKLocalHttpCalloutAction Document Action prompts the user for input of new users that should be assigned to various roles on the document.

After DocumentRoleService#batchUpdateDocumentRolesruns successfully (the new roles have been assigned), then the local HTTP Callout vSDKHttpCallouts.localGetLifecycleActions is made to retrieve the document's lifecycle actions and then initiate a workflow.

@DocumentActionInfo(label="SDK: Local Http Callout", user_input_object="vsdk_user_input_object__c", user_input_object_type="")
public class vSDKLocalHttpCalloutAction implements DocumentAction {
	
    public void execute(DocumentActionContext documentActionContext) {

...
        
        if (documentRoleUpdates.size() > 0) {
	        docRoleService.batchUpdateDocumentRoles(documentRoleUpdates)
	        .rollbackOnErrors()
	        .execute();
	        
	        logService.info("Document Role update successful.");
	        
	        //Delete temporary user input record
	        recordService.batchDeleteRecords(VaultCollections.asList(inputRecord)).rollbackOnErrors().execute();
	        
	        //Loop through all documents and initiate the APR Document workflow for the new owner (manager) of the record.
    		for (DocumentVersion docVersion : docVersionList) {
            	String version_id = docVersion.getValue("id", ValueType.STRING) + "_" + 
        				docVersion.getValue("major_version_number__v", ValueType.NUMBER).toString() + "_" + 
        				docVersion.getValue("minor_version_number__v", ValueType.NUMBER).toString();
            	
            	vSDKHttpCallouts.localGetLifecycleActions(version_id, userToRoleMap.get(OWNER), params);
    		}
        }
    }

Local HTTP Callout - Retrieve the Document Lifecycle Actions

Now that user roles have been updated and a new owner exists, the vSDKHttpCallouts.localGetLifecycleActions directly initiates an HttpService callout against the local target vault.

This is done with httpService.newLocalHttpRequest(). The method creates a connection using the user that runs the Vault API call.

HttpRequest request = httpService.newLocalHttpRequest()

Alternatively, you can create a local Connection record that will always use the specificed Authorized Connection User to make the local callout.

The method makes a Vault API call against https://developer.veevavault.com/api/19.1/#retrieve-user-actions to determine the name of the required Document Lifecycle Action.

The HttpRequest object works similar to other Java based HTTP request libraries. We can set the method, path, header, and body.

Here we use the current document's ID, major version, and minor version to initiate the Vault API call.

For our path, we only have to append the API portion after the DNS - e.g., /api/v19.1/objects/documents/{docId}/versions/{major_version}/{minor_version}/lifecycle_actions. The full DNS name is included by default when you create the request against the Connection record.

/** 
 * Runs against a local API connection to locate and verify the correct document workflow.
 * This is necessary so that the proper workflow is started when this method is used.
 * See https://developer.veevavault.com/api/19.1/#retrieve-user-actions for details
 * 
 * @param versionId of the document
 * @param userId of the document owner
 * @param params for API input
 */

public static void localGetLifecycleActions(String versionId, String userId, Map<String,String> params) {
   
	LogService logService = ServiceLocator.locate(LogService.class);
	HttpService httpService = ServiceLocator.locate(HttpService.class);
	
	String[] version_id = StringUtils.split(versionId, "_");
	
	//A `newLocalHttpRequest` is an Http Callout against the same vault (local) using the user that initiated the SDK code.
	//The user must have access to the action being performed or the Vault API will return an access error.
	HttpRequest request = httpService.newLocalHttpRequest()
			.setMethod(HttpMethod.GET)
			.appendPath("/api/v19.1/objects/documents/" + version_id[0] + "/versions/" + version_id[1] + "/" + version_id[2] + "/lifecycle_actions");

...
	
}

The HttpRequest is now setup and ready to be sent to the source vault. With the /api/v19.1/objects/documents/{docId}/versions/{major_version}/{minor_version}/lifecycle_actions endpoint, we want to receive JSON data back so you send the request with the HttpResponseBodyValueType.JSONDATA parameter value.

When the HttpRequest response from the local vault is received, it can be parsed through using the JsonService class.

The response values are used to determine if the required Document Lifecycle Action was located on the current document state and if it was, then initiate the workflow.

  • First, the response is parsed into a JsonData object
  • From the response, the getJsonObject() will get the response as a parseable JsonObject
    • Here the getValue method can be used to retrieve responseStatus, responseDetails, and lifecycleActions
  • The lifecycleActions element is an array of JSON data. This is parsed into a JsonArray object.
    • Each lifecycle action is returned as an element of the array and must be parsed into a JsonObject.
    • Individual fields can then be retrieved from each JsonObject that is in the JsonArray.
public static void localGetLifecycleActions(String versionId, String userId, Map<String,String> params) {
   
...

	httpService.send(request, HttpResponseBodyValueType.JSONDATA)
		.onSuccess(httpResponse -> {
			int responseCode = httpResponse.getHttpStatusCode();
			logService.info("RESPONSE: " + responseCode);
			logService.info("RESPONSE: " + httpResponse.getResponseBody());
			
			JsonData response = httpResponse.getResponseBody();
			
			if (response.isValidJson()) {
				String responseStatus = response.getJsonObject().getValue("responseStatus", JsonValueType.STRING);
				
				if (responseStatus.equals("SUCCESS")) {
					logService.info("Verifying Lifecycle Actions for document - " + String.join("_", version_id));
					
					JsonArray lifecycleActions = response.getJsonObject().getValue("lifecycle_actions__v", JsonValueType.ARRAY);
					
					for (int count = 0; count < lifecycleActions.getSize(); count++) {
						JsonObject action = lifecycleActions.getValue(count, JsonValueType.OBJECT);
						String actionLabel = action.getValue("label__v", JsonValueType.STRING);
						
						//If the correct action label is located, initiate `localStartDocWorkflow` to start the document workflow.
						if (actionLabel.contains("Start HTTP Workflow")) {
							logService.info("Located the workflow action '{}'", actionLabel);
							String actionName = action.getValue("name__v", JsonValueType.STRING);
							
							vSDKHttpCallouts.localStartDocWorkflow(versionId, userId, params, actionName);
						}
					}
				}
				
...

			}
		})
		.onError(httpOperationError -> {
			int responseCode = httpOperationError.getHttpResponse().getHttpStatusCode();
			logService.info("RESPONSE: " + responseCode);
			logService.info(httpOperationError.getMessage());
			logService.info(httpOperationError.getHttpResponse().getResponseBody());
		})
		.execute();
}

Local HTTP Callout - Initiate the Document Lifecycle Workflow

If the vSDKHttpCallouts.localGetLifecycleActions determines that the current document state has an action called Start HTTP Workflow, then we can initiate the workflow with vSDKHttpCallouts.localStartDocWorkflow

public static void localGetLifecycleActions(String versionId, String userId, Map<String,String> params) {

...

JsonArray lifecycleActions = response.getJsonObject().getValue("lifecycle_actions__v", JsonValueType.ARRAY);

for (int count = 0; count < lifecycleActions.getSize(); count++) {
	JsonObject action = lifecycleActions.getValue(count, JsonValueType.OBJECT);
	String actionLabel = action.getValue("label__v", JsonValueType.STRING);
	
	//If the correct action label is located, initiate `localStartDocWorkflow` to start the document workflow.
	if (actionLabel.contains("Start HTTP Workflow")) {
		logService.info("Located the workflow action '{}'", actionLabel);
		String actionName = action.getValue("name__v", JsonValueType.STRING);
		
		vSDKHttpCallouts.localStartDocWorkflow(versionId, userId, params, actionName);
	}
}	
...

The vSDKHttpCallouts.localStartDocWorkflow uses the https://developer.veevavault.com/api/19.1/#initiate-user-action API to start the workflow.

As with the previous HTTP Callout, this uses the current document's ID, major version, and minor version to initiate the Vault API call against a HttpService.newLocalHttpRequest() connection. The code then uses the new owner from the role change as the workflows Approver and appends any additional body parameters.

/**
 * Runs against a local API connection to initiate a document workflow
 * The workflow is initiated for the "userId" which is the owner of the document.
 * See https://developer.veevavault.com/api/19.1/#initiate-user-action for details.
 * 
 * @param versionId of the document
 * @param userId of the document owner
 * @param params for API input
 * @param action starts the document workflow
*/

public static void localStartDocWorkflow(String versionId, String userId, Map<String,String> params, String action) {
   
	LogService logService = ServiceLocator.locate(LogService.class);
	HttpService httpService = ServiceLocator.locate(HttpService.class);
	
	String[] version_id = StringUtils.split(versionId, "_");
   
	//A `newLocalHttpRequest` is an Http Callout against the same vault (local) using the user that initiated the SDK code.
	//The user must have access to the action being performed or the Vault API will return an access error.
	HttpRequest request = httpService.newLocalHttpRequest()
			.setMethod(HttpMethod.PUT)
			.appendPath("/api/v19.1/objects/documents/" + version_id[0] + "/versions/" + version_id[1] + "/" + version_id[2] + "/lifecycle_actions/" + action)
			.setBodyParam("Approver", "user:" + userId);	

	for (String key : params.keySet()) {
		request.setBodyParam(key,params.get(key));
	}

...

As with the previous method, a Json Data response is received and then processed for the JsonData, JsonObject, and JsonArray classes.

public static void localStartDocWorkflow(String versionId, String userId, Map<String,String> params, String action) {
   
...

   httpService.send(request, HttpResponseBodyValueType.JSONDATA)
            .onSuccess(httpResponse -> {
                int responseCode = httpResponse.getHttpStatusCode();
                logService.info("RESPONSE: " + responseCode);
                logService.info("RESPONSE: " + httpResponse.getResponseBody());
                
				JsonData response = httpResponse.getResponseBody();
				
				//This API call just initiates a workflow. Log success or errors messages depending on the results of the call.
				if (response.isValidJson()) {
					String responseStatus = response.getJsonObject().getValue("responseStatus", JsonValueType.STRING);
					
					if (responseStatus.equals("SUCCESS")) {
						logService.info("Starting HTTP  Workflow for document - " + String.join("_", version_id));
					}

...

				}
            })
            .onError(httpOperationError -> {
                int responseCode = httpOperationError.getHttpResponse().getHttpStatusCode();
                logService.info("RESPONSE: " + responseCode);
                logService.info(httpOperationError.getMessage());
                logService.info(httpOperationError.getHttpResponse().getResponseBody());
            })
            .execute();
...

}

Clone this wiki locally