private ResponseEntity<?> getRegionKeys(String region, String ignoreMissingKey, String[] keys,
      boolean keysInQueryParam) {
    logger.debug("Reading data for keys ({}) in Region ({})", ArrayUtils.toString(keys), region);
    securityService.authorize("READ", region, keys);
    final HttpHeaders headers = new HttpHeaders();
    if (keys.length == 1) {
      /* GET op on single key */
      Object value = getValue(region, keys[0]);
      // if region.get(K) return null (i.e INVLD or TOMBSTONE case) We consider 404, NOT Found case
      if (value == null) {
        throw new ResourceNotFoundException(String
            .format("Key (%1$s) does not exist for region (%2$s) in cache!", keys[0], region));
      }

      final RegionEntryData<Object> data = new RegionEntryData<>(region);
      URI uri;
      if (keysInQueryParam) {
        String[] encodedKeys = encode(keys);
        String encodedRegion = encode(region);
        uri = toUriWithKeys(encodedKeys, encodedRegion);
      } else {
        uri = toUri(region, keys[0]);
      }
      headers.set(HttpHeaders.CONTENT_LOCATION, uri.toASCIIString());
      data.add(value);
      return new ResponseEntity<RegionData<?>>(data, headers, HttpStatus.OK);

    } else {
      // fail fast for the case where ignoreMissingKey param is not specified correctly.
      if (ignoreMissingKey != null && !(ignoreMissingKey.equalsIgnoreCase("true")
          || ignoreMissingKey.equalsIgnoreCase("false"))) {
        String errorMessage = String.format(
            "ignoreMissingKey param (%1$s) is not valid. valid usage is ignoreMissingKey=true!",
            ignoreMissingKey);
        return new ResponseEntity<>(convertErrorAsJson(errorMessage), HttpStatus.BAD_REQUEST);
      }

      final Map<Object, Object> valueObjs = getValues(region, keys);
      // valueObjs will have as its keys all of "keys".
      // valueObjs will have a null value if the key did not exist.
      // So if ignoreMissingKey is false we can use "null" values to detect the missing keys.
      if (!("true".equalsIgnoreCase(ignoreMissingKey))) {
        List<String> unknownKeys = new ArrayList<>();
        // use "keys" to iterate so we get the original key ordering from user.
        for (String key : keys) {
          if (valueObjs.get(key) == null) {
            unknownKeys.add(key);
          }
        }
        if (!unknownKeys.isEmpty()) {
          String unknownKeysAsStr = StringUtils.collectionToCommaDelimitedString(unknownKeys);
          String errorString = String.format("Requested keys (%1$s) do not exist in region (%2$s)",
              unknownKeysAsStr, region);
          return new ResponseEntity<>(convertErrorAsJson(errorString), headers,
              HttpStatus.BAD_REQUEST);
        }
      }

      // The dev rest api was already released with null values being returned
      // for non-existent keys.
      // Order the keys in the result after the array of keys given to this method.
      // Previous code returned them in random order which the result harder to test and use.

      URI uri;
      if (keysInQueryParam) {
        String[] encodedKeys = encode(keys);
        String encodedRegion = encode(region);
        uri = toUriWithKeys(encodedKeys, encodedRegion);
      } else {
        String keyList = StringUtils.arrayToCommaDelimitedString(keys);
        uri = toUri(region, keyList);
      }

      headers.set(HttpHeaders.CONTENT_LOCATION, uri.toASCIIString());
      final RegionData<Object> data = new RegionData<>(region);
      // add the values in the same order as the original keys
      // the code used to use valueObj.values() which used "hash" ordering.
      for (String key : keys) {
        data.add(valueObjs.get(key));
      }
      return new ResponseEntity<RegionData<?>>(data, headers, HttpStatus.OK);
    }
  }
Reading data for set of keys

@param region gemfire region name
@param keys optional list of keys to read
@param ignoreMissingKey if true and reading more than one key then if a key is missing ignore
@return JSON document
geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/PdxBasedCrudController.java