Google APIs Client Library for C++ A C++ library for client applications to access Google APIs.
Making Service Requests

This document describes how to make high level requests to cloud services using the core components of the library's service layer. It also discusses the key components related to service-level interaction. Requests and responses use the same HttpTransport and HttpResponse objects described in Making HTTP Requests.

Google Service APIs and other cloud service APIs are often designed using a Representational State Transfer (REST) architectural style. The Wikipedia page on REST offers some introduction to the style. For purposes of understanding the Google APIs Client Library for C++, the important takeaways are that services tend to be organized around the concept of one or more types of resources and those resources define stateless operations on them heavily decoupled from one another. These web-oriented services typically define the operations as URLs where the URL defines a specific resource (or part of a resource) along with additional parameters or qualifiers. Simple modification operations may encode the modification in the URL itself (such as query parameters) or may attach them in the payload of the HTTP request (such as a POST). The results of the operation are returned in the HTTP responses.

The Google APIs Client Library for C++'s service layer provides higher level C++ abstractions and programmer support for these types of APIs and interactions. Rather than dealing with low level HTTP models and syntax, it adds application-level objects, models, and support. APIs tailored to C++ programmers for inidividual services can be found in the document Available Sepciailized Service APIs.

Client applications typically download additional service-specific APIs rather than directly use the googleapis::client::ClientServiceRequest documented below. However, understanding ClientServiceRequest will make it easier to understand the service-specific API specializations.

Contents

  1. Typical use case examples
    1. Listing a small resource
    2. Paging through a large resource
    3. Getting a resource element
    4. Adding a typical resource element
    5. Adding a large resource element
  2. Core service layer components
    1. ClientService
    2. Resources
    3. ClientServiceRequest

Typical use case examples

These examples show how to use the core components to issue various types of requests. The examples below are for specific generated APIs, but the general idea and flavor is commonly applicable to all APIs.

The following snippet applies to all the examples in this section.

#include "google/calendar_api/calendar_api.h"
#include "googleapis/client/service/client_service.h"
#include "googleapis/client/transport/http_response.h"
#include "googleapis/client/transport/http_transport.h"

using google_calendar_api::Calendar;
using google_calendar_api::CalendarList;
using google_calendar_api::CalendarListEntry;
using google_calendar_api::CalendarsResource_DeleteMethod;
using google_calendar_api::CalendarsResource_InsertMethod;
using google_calendar_api::CalendarListResource_ListMethod;
using google_calendar_api::CalendarService;
using google_calendar_api::Event;
using google_calendar_api::Events;
using google_calendar_api::EventsResource_GetMethod;
using google_calendar_api::EventsResource_InsertMethod;
using google_calendar_api::EventsResource_ListMethod;
using google_calendar_api::EventsResource_ListMethodPager;
using google_calendar_api::EventsResource_PatchMethod;
using google_calendar_api::EventsResource_UpdateMethod;

Listing a small resource

It is common for resources have some sort of List operation that can be used to enumerate its elements, perhaps with some sort of filter.

void CalendarSample::ShowCalendars() {
  scoped_ptr<CalendarListResource_ListMethod> method(
      service_->get_calendarList().NewListMethod(&credential_));

  scoped_ptr<CalendarList> calendar_list(CalendarList::New());
  if (!method->ExecuteAndParseResponse(calendar_list.get()).ok()) {
    DisplayError(method.get());
    return;
  }
  DisplayList<CalendarList, CalendarListEntry>(
      "", "CalendarList", *calendar_list);
  cout << endl;
}

Paging through a large resource

Services that define resources that can contain a large number of elements will often offer a means to page through the results over multiple queries rather than receiving an enormous response from a single request. A common model used by these services is to have a page_token parameter in the List request and a next_page_token value in the response. The intent being that you iterate over the pages by issuing successive requests using the different page_token values.

You can use the ServiceRequestPager to facilitate these paging iterations. The C++ code generator will add support directly to the APIs it provides as illustrated below.

void CalendarSample::PageThroughAllEvents(
    const string& calendar_id, int num_per_page) {
  cout << "All Events" << endl;
  scoped_ptr<EventsResource_ListMethodPager> pager(
      service_->get_events().NewListMethodPager(&credential_, calendar_id));
  pager->request()->set_max_results(num_per_page);
  while (pager->NextPage()) {
    DisplayList<Events, Event>("  ", "EventList", *pager->data());
  }
}

Getting a resource element

Get operations are typically straight forward but have a catch. Typically you need to know the ID of the resource you wish to get. If you do not already know this (such as from the result of the Insert which added it earlier) then you may first need to issue a List and figure out the ID you want.

Elements are typically data objects serialized into the response payload. The generated APIs know how to deserialize these responses into the expected C++ objects so that you can treat the responses as type-safe C++ objects rather than having to parse low level JSON or whatever encoding is being used for the response data.

util::Status CalendarSample::GetEvent(
    const string& calendar_id, const StringPiece& event_id, Event* event) {
  scoped_ptr<EventsResource_GetMethod> method(
      service_->get_events().NewGetMethod(
          &credential_, calendar_id, event_id));

  return method->ExecuteAndParseResponse(event);
}

Adding a typical resource element

Many resource elements are simple data objects, such as a calendar event. There are usually added either by composing their individual attributes or by giving it an actual data object. Which way depends on how the service API is defined.

The following function is an example of an API that inserts a new resource element by taking a data object specifying the element to be added.

void CalendarSample::AddEvent(const string& calendar_id, Event* event) {
  scoped_ptr<EventsResource_InsertMethod> method(
      service_->get_events().NewInsertMethod(
          &credential_, calendar_id, *event));

  if (!method->ExecuteAndParseResponse(event).ok()) {
    DisplayError(method.get());
    return;
  }

  cout << "Added new event ID=" << event->get_id() << ":" << endl;
  Display("  ", *event);
  cout << endl;
}

Adding a large resource element

Sometimes Service APIs offer a media upload capability for inserting larger data objects, such as files. The Google APIs Client Library for C++ code generator will add a media_uploader() getter to these operations. The snippet below gives a basic example for using media upload-style method. For more information on using MediaUploader, see the document Media Upload.

using googleapis::client::MediaUploader;

scoped_ptr<FilesResource_InsertMethod> insert
    (drive_service->get_files().NewInsertMethod(credential));

scoped_ptr<google_drive_api::File> file(google_drive_api::File::New());
file->set_title(StrCat("Uploaded from ", googleapis::File::Basename(path)));
file->set_originalFilename(googleapis::File::Basename(path));

DataReader* reader = NewUnmanagedFileDataReader(path);
MediaUploader* uploader = insert->media_uploader();
uploader->set_metadata(*file);
uploader->set_media_content_reader(mime_type, reader);

insert->Execute();

Core service layer components

Client Service

A ClientService denotes a particular service (such as a Google API or Cloud Endpoint) that you will be accessing as a client. It is identified by its URL and has a HttpTransport bound to it. The Google APIs Client Library for C++ was designed assuming that ClientService instances would be long-lived over the lifetime of your application rather than created and destroyed to make individual operations. It is permissible for these instances to be short-lived however there may be performance implications as the library implementations evolve.

The primary purpose of a ClientService is to act as a request factory (via the Resources described below), creating requests for the various capabilities offered by the service's API. The base class does not offer much since the requests are specific to individual services. Even the specialized classes will have a small amount of state acting primarily as ClientServiceRequest factories.

Resources

A resource denotes a particular REST-style resource that the service has defined within its API. In the Google APIs Client Library for C++, a resource is purely a ClientServiceRequest factory for the available API that the service defines on that particular resource type.

ClientServiceRequest

A ClientServiceRequest is an object that makes a request to a specific operation in a service's API. It knows the endpoint URL and parameters being passed. A ClientServiceRequest owns a HttpRequest which it uses internally to perform the transport layer messaging to the actual service in the cloud. The responses are conveyed back up to the service layer using the same HttpResponse object described in the Making HTTP Requests document.

The request methods generated by the code generator have constructors that take a credential and all the required parameters as specified by the service. Optional parameters are set using setter methods. Required (and only required) parameters are always set in the constructor. Optional (and only optional) parameters are set by attribute setters on the method. To make unauthorized (anonymous) calls, construct the method with a NULL credential.

If an operation returns a result object, the code generator will create a method ExecuteAndParseResponse with a type-safe out parameter that will return the object in the response. If you are not interested in the response data, you can just call the plain Execute method and parse the response later should you decide that you care about the details.