Got feedback or spotted a mistake?
Leave a comment at the end of this page or email contact@krishagni.com
Forms API
The following example program demonstrates forms API by
- retrieving form metadata
- saving form data
- retrieving record ID of form data
- retrieving form data
- updating form data
- deleting the form data
The program is written using Java and Spring REST framework. OpenSpecimen integration developers are free to choose language and tools of their choice.
public class TestFormApis { // // this can be a configuration setting. For illustration purpose, API base URL is hardcoded // private static final String API_BASE_URL = "http://myopenspecimenserver.com/openspecimen/rest/ng"; private static RestTemplate template = new RestTemplate(); // // Input specimen ID and this program will add destruction date and remove it. // public static void main(String[] args) throws Exception { if (args.length == 0) { return; } // // Step 0: Input specimen ID could come from any source. // In this example, specimen ID is picked from command line arguments // Long specimenId = Long.parseLong(args[0]); // // Step 1: Login and get an authentication token for use in subsequent API calls // String token = login(); // // Step 2: Retrieve form metadata // Map<String, Object> formMetadata = getFormMetadata(token, "Specimen", specimenId, "Specimen Destruction Details"); if (formMetadata == null) { // No form with name "Specimen Destruction Details" attached at Specimen level return; } // // Step 3: Save form data // Long recordId = saveFormData(token, specimenId, formMetadata); System.out.println("Successfully saved form record: " + recordId); // // recordId can be used to maintain a mapping between your data and OpenSpecimen form record // this mapping can be subsequently used for updating form record without resorting to step 4. // // // Step 4: Retrieve form record ID // recordId = getRecordId(token, "Specimen", specimenId, formMetadata); // // Step 5: Retrieve form data // Map<String, Object> formData = getFormData(token, recordId, formMetadata); System.out.println(formData.get("destructionDate")); // use the form data fields for processing System.out.println(formData.get("destructionMethod")); // // Step 6: Update form data // updateFormData(token, recordId, formData); // // Step 7: Delete form data // deleteFormData(token, recordId, formMetadata); // // Step 8: logout // logout(token); } private static String login() { // // username and password could be fetched from your client configuration database // Map<String, Object> payload = new HashMap<>(); payload.put("loginName", "admin@admin.com"); payload.put("password", "Login420"); Map<String, Object> resp = template.postForObject(getUrl("/sessions"), payload, Map.class); return (String) resp.get("token"); } private static void logout(String token) { invokeApi(HttpMethod.DELETE, "/sessions", token, null, Map.class); template.exchange(getUrl("/sessions"), HttpMethod.DELETE, getHttpEntity(token), Map.class); } private static Map<String, Object> getFormMetadata(String token, String entityType, Long objectId, String formName) throws Exception { String uri = null; if (entityType.equals("Specimen")) { uri = "/specimens/" + objectId + "/forms"; } else if (entityType.equals("Visit")) { uri = "/visits/" + objectId + "/forms"; } else if (entityType.equals("CollectionProtocolRegistration")) { uri = "/collection-protocol-registrations/" + objectId + "/forms"; } else { throw new IllegalArgumentException("Invalid entity type: " + entityType); } Map[] forms = invokeApi(HttpMethod.GET, uri, token, null, Map[].class); for (Map form : forms) { if (Objects.equals(form.get("formCaption"), formName)) { return form; } } return null; } private static Long saveFormData(String token, Long specimenId, Map<String, Object> formMetadata) { Map<String, Object> appData = new HashMap<>(); appData.put("useUdn", true); // to let API know we use human readable field names instead of cryptic ones appData.put("formCtxtId", formMetadata.get("formCtxtId")); appData.put("objectId", specimenId); Calendar cal = Calendar.getInstance(); cal.set(2020, 12, 31); long destructionDate = cal.getTimeInMillis(); Map<String, Object> formData = new HashMap<>(); formData.put("appData", appData); // // form field values // formData.put("destructionDate", destructionDate); formData.put("destructionMethod", "Cremation"); Number formId = (Number)formMetadata.get("formId"); String uri = "/forms/" + formId + "/data"; Map savedData = invokeApi(HttpMethod.POST, uri, token, formData, Map.class); // // return record ID on saving form data // return ((Number)savedData.get("id")).longValue(); } private static Long updateFormData(String token, Long recordId, Map<String, Object> formData) { formData.put("recordId", recordId); formData.put("destructionMethod", "Not Specified"); Number formId = (Long)formData.get("containerId"); String uri = "/forms/" + formId + "/data/" + recordId; Map savedData = invokeApi(HttpMethod.PUT, uri, token, formData, Map.class); return ((Number)savedData.get("id")).longValue(); } private static Long getRecordId(String token, String entityType, Long objectId, Map<String, Object> formMetadata) { String uri = ""; if (entityType.equals("Specimen")) { uri = "/specimens/"; } else if (entityType.equals("Visit")) { uri = "/visits/"; } else if (entityType.equals("CollectionProtocolRegistration")) { uri = "/collection-protocol-registrations/"; } else { throw new IllegalArgumentException("Invalid entity type: " + entityType); } Long formCtxtId = (Long) formMetadata.get("formCtxtId"); uri = String.format(uri + "%d/forms/%d/records", objectId, formCtxtId); Map<String, Object> entityRecs = invokeApi(HttpMethod.GET, uri, token, null, Map.class); Map<String, Object>[] records = (Map<String, Object>[])entityRecs.get("records"); if (records == null || records.length == 0) { return null; } return (Long)records[0].get("recordId"); } private static Map<String, Object> getFormData(String token, Long recordId, Map<String, Object> formMetadata) { Number formId = (Number)formMetadata.get("formId"); String uri = "/forms/" + formId + "/data/" + recordId; return (Map<String, Object>)invokeApi(HttpMethod.GET, uri, token, null, Map.class); } private static void deleteFormData(String token, Long recordId, Map<String, Object> formMetadata) { Number formId = (Number)formMetadata.get("formId"); String uri = "/forms/" + formId + "/data/" + recordId; invokeApi(HttpMethod.DELETE, uri, token, null, Long.class); } private static <T> T invokeApi(HttpMethod httpMethod, String uri, String token, Object body, Class<T> returnType) { ResponseEntity<T> resp = template.exchange(getUrl(uri), httpMethod, getHttpEntity(token, body), returnType); if (resp.getStatusCode() == HttpStatus.OK) { return resp.getBody(); } // // Handle API failures // throw new RuntimeException("Error invoking API: " + uri); } private static HttpEntity<?> getHttpEntity(String token) { return getHttpEntity(token, null); } private static HttpEntity<?> getHttpEntity(String token, Object body) { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); headers.set("X-OS-API-TOKEN", token); // API auth token header return new HttpEntity<>(body, headers); } private static String getUrl(String uri) { return API_BASE_URL + uri; } }
Got feedback or spotted a mistake?
Leave a comment at the end of this page or email contact@krishagni.com