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