/**
   * Creates an object. Equivalent to a POST to a certain endpoint.
   *
   * @param endpoint The endpoint to be accessed. Example: "products", "scripts"
   * @param object The entity to create
   * @return {@link ObjectResponse} with the created object
   */
  public ObjectResponse create(String endpoint, JSONObject object) throws ApiException {
    try {
      InternalApiResponse response = client.post(endpoint, object);
      validateResponse(response);

      return new ObjectResponse(new JSONObject(response.getResponse()), response.getHeaders());

    } catch (JSONException e) {
      throw new ApiException("Invalid JSON responded by API", e);
    }
  }
  /**
   * Updates an object. Equivalent to a PUT to a certain endpoint + "/" + the object id.
   *
   * @param endpoint The endpoint to be accessed. Example: "products", "scripts"
   * @param id The id of the object to update
   * @param object The entity to update
   * @return {@link ObjectResponse} with the updated object
   */
  public ObjectResponse update(String endpoint, int id, JSONObject object) throws ApiException {
    if (id < 1) {
      throw new IllegalArgumentException("Invalid id: " + id);
    }
    try {
      InternalApiResponse response = client.put(endpoint + "/" + id, object);
      validateResponse(response);

      return new ObjectResponse(new JSONObject(response.getResponse()), response.getHeaders());
    } catch (JSONException e) {
      throw new ApiException("Invalid JSON responded by API", e);
    }
  }
 private void validateResponse(InternalApiResponse response) throws ApiException {
   if (response.getStatusCode() >= 500) {
     // Internal server error
     throw new ApiException("Internal server error returned by API.");
   }
   switch (response.getStatusCode()) {
     case HttpStatus.SC_BAD_REQUEST:
     case HttpStatus.SC_UNPROCESSABLE_ENTITY:
     case HttpStatus.SC_FORBIDDEN:
     case HttpStatus.SC_UNAUTHORIZED:
       throw new ApiDetailedException(response);
     case HttpStatus.SC_NOT_FOUND:
       throw new ApiNotFoundException(response);
     case 429: // Too many requests
       throw new ApiException("Too many requests");
   }
 }
  /**
   * Accesses an endpoint that lists objects.
   *
   * @param endpoint The endpoint to be accessed. Examples: "products", "scripts"
   * @param additionalParams Additional parameters to send with the request.
   * @return A {@link ListResponse} with the results.
   */
  public ListResponse list(String endpoint, Map<String, String> additionalParams)
      throws ApiException {

    try {
      if (additionalParams == null) {
        additionalParams = Maps.newHashMap();
      }
      if (!additionalParams.containsKey("page")) {
        additionalParams.put("page", "1");
      }
      if (!additionalParams.containsKey("per_page")) {
        additionalParams.put("per_page", "30");
      }

      InternalApiResponse response = client.get(endpoint, additionalParams);

      validateResponse(response);

      int page = Integer.valueOf(additionalParams.get("page"));
      int perPage = Integer.valueOf(additionalParams.get("per_page"));

      List<String> xTotalCount = response.getHeader("X-Total-Count");
      // Fix for Google App Engine, otherwise, X Total Count would be null
      // and then we would have null point exception ---> TODO: make getHeader case insensitive
      if (xTotalCount == null) {
        xTotalCount = response.getHeader("x-total-count");
      }

      int totalCount = Integer.valueOf(xTotalCount.get(0));

      return new ListResponse(
          new JSONArray(response.getResponse()),
          page,
          totalCount,
          page * perPage >= totalCount,
          endpoint,
          additionalParams,
          response.getHeaders());

    } catch (JSONException e) {
      throw new ApiException("Invalid JSON responded by API", e);
    }
  }
  private ObjectResponse internalGet(String url, Map<String, String> additionalParams)
      throws ApiException {
    try {
      if (additionalParams == null) {
        additionalParams = Maps.newHashMap();
      }

      InternalApiResponse response = client.get(url, additionalParams);

      try {
        validateResponse(response);
      } catch (ApiNotFoundException e) {
        // If not found, return null
        return null;
      }

      return new ObjectResponse(new JSONObject(response.getResponse()), response.getHeaders());
    } catch (JSONException e) {
      throw new ApiException("Invalid JSON responded by API", e);
    }
  }