Google APIs Client Library for C++ | A C++ library for client applications to access Google APIs. |
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
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.