call method

Future<PlanningCenterApiResponse<PlanningCenterApiData>> call(
  1. String endpoint, {
  2. String verb = 'get',
  3. Object? data,
  4. PlanningCenterApiQuery? query,
  5. String apiVersion = '',
})

Planning Center publishes their API documentation here: https://developer.planning.center/docs/#/overview/

Some relevant points from the documentation: resources (sent and received) are wrapped in an object like this { "data": { "type": "Thing", "id": "1", "attributes": { ... } } }

dates are YYYY-MM-DD date and time is YYYY-MM-DDTHH:MM:SSZ and always UTC to query for an item related to date use this format ?wheredate_field_name=2018-02-22 or ?whereoperator=2018-02-22 the optional operator can be one of gt,gte,lt,lte for greater than, etc. The PlanningCenterApiQuery object provides abstractions for this.

related resources can be included with ?include=something

This function executes an api request with appropriate authentication.

Returns a PlanningCenterApiResponse object that decodes response data into various mappings, but does not create objects.

Real objects can be created with PcoResponse.fromJson()

endpoint should begin with a slash, because 'https://api.planningcenteronline.com' will be prepended automatically

Implementation

Future<PlanningCenterApiResponse> call(
  String endpoint, {
  String verb = 'get',
  Object? data,
  PlanningCenterApiQuery? query,
  String apiVersion = '',
}) async {
  if (endpoint.startsWith(mainEndpoint))
    endpoint = endpoint.replaceFirst(mainEndpoint, '');

  var application = endpoint.split('/')[1];

  // ensure query defaults
  query ??= PlanningCenterApiQuery();

  // fix params to be the correct type
  var params = <String, String>{};
  query.asApiMap.forEach((k, v) => params[k.toString()] = v.toString());

  // if we are using app secret authentication, it will be embedded in the _baseUri.authority
  var uri = Uri.https(_baseUri.authority, _baseUri.path + endpoint, params);
  var headers = <String, String>{};
  if (apiVersion.isNotEmpty) headers['X-PCO-API-Version'] = apiVersion;

  String jsonString = '';
  if (data != null && verb != 'get') {
    headers['Content-Type'] = 'application/json';
    if (data is String) {
      jsonString = data;
    } else if (data is PlanningCenterApiData) {
      jsonString = json.encode(data.asMapWithData);
    } else {
      jsonString = json.encode(data);
    }
  }

  await apiCanCall;
  apiCanCall = Future.delayed(Duration(milliseconds: apiInterval));

  var authFailure = await _checkCredentials();
  if (authFailure != null) return authFailure;

  headers.addAll(_authHeaders);

  late http.Response res;
  switch (verb.toLowerCase()) {
    case 'get':
      res = await _client.get(uri, headers: headers);
      break;
    case 'post':
      res = await _client.post(uri, headers: headers, body: jsonString);
      break;
    case 'patch':
      res = await _client.patch(uri, headers: headers, body: jsonString);
      break;
    case 'put':
      res = await _client.put(uri, headers: headers);
      break;
    case 'delete':
      res = await _client.delete(uri, headers: headers);
      break;
    default:
      return PlanningCenterApiError('Unsupported http verb', application, uri,
          jsonString, query, 400, '');
  }
  if (res.statusCode >= 200 && res.statusCode < 300) {
    var retval = PlanningCenterApiResponse.fromResponse(
      application,
      query,
      jsonString,
      res,
    );
    return retval;
  }
  return PlanningCenterApiError(
    'API Request Failed',
    application,
    uri,
    jsonString,
    query,
    res.statusCode,
    res.body,
  );
}