blob: e8b67d767ac62193afb6e526a1f4637cad673bf6 [file] [log] [blame] [view]
Grant Timmerman5c11b0a2019-06-26 07:39:48 -07001# Getting Started
2
3This document provides all the basic information you need to start using the library. It covers important library concepts, shows examples for various use cases, and gives links to more information.
4
5## Setup
6
7There are a few setup steps you need to complete before you can use this library:
8
91. If you don't already have a Google account, [sign up](https://www.google.com/accounts).
102. If you have never created a Google APIs Console project, read the [Managing Projects page](http://developers.google.com/console/help/managing-projects) and create a project in the [Google API Console](https://console.developers.google.com/).
113. [Install](http://developers.google.com/api-client-library/python/start/installation) the library.
12
13## Authentication and authorization
14
15It is important to understand the basics of how API authentication and authorization are handled. All API calls must use either simple or authorized access (defined below). Many API methods require authorized access, but some can use either. Some API methods that can use either behave differently, depending on whether you use simple or authorized access. See the API's method documentation to determine the appropriate access type.
16
17### 1. Simple API access (API keys)
18
19These API calls do not access any private user data. Your application must authenticate itself as an application belonging to your Google Cloud project. This is needed to measure project usage for accounting purposes.
20
21**API key**: To authenticate your application, use an [API key](https://cloud.google.com/docs/authentication/api-keys) for your Google Cloud Console project. Every simple access call your application makes must include this key.
22
23> **Warning**: Keep your API key private. If someone obtains your key, they could use it to consume your quota or incur charges against your Google Cloud project.
24
25### 2. Authorized API access (OAuth 2.0)
26
27These API calls access private user data. Before you can call them, the user that has access to the private data must grant your application access. Therefore, your application must be authenticated, the user must grant access for your application, and the user must be authenticated in order to grant that access. All of this is accomplished with [OAuth 2.0](https://developers.google.com/identity/protocols/OAuth2) and libraries written for it.
28
29* **Scope**: Each API defines one or more scopes that declare a set of operations permitted. For example, an API might have read-only and read-write scopes. When your application requests access to user data, the request must include one or more scopes. The user needs to approve the scope of access your application is requesting.
30* **Refresh and access tokens**: When a user grants your application access, the OAuth 2.0 authorization server provides your application with refresh and access tokens. These tokens are only valid for the scope requested. Your application uses access tokens to authorize API calls. Access tokens expire, but refresh tokens do not. Your application can use a refresh token to acquire a new access token.
31
32 > **Warning**: Keep refresh and access tokens private. If someone obtains your tokens, they could use them to access private user data.
33
34* **Client ID and client secret**: These strings uniquely identify your application and are used to acquire tokens. They are created for your Google Cloud project on the [API Access pane](https://code.google.com/apis/console#:access) of the Google Cloud. There are three types of client IDs, so be sure to get the correct type for your application:
35
36 * Web application client IDs
37 * Installed application client IDs
38 * [Service Account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount) client IDs
39
40 > **Warning**: Keep your client secret private. If someone obtains your client secret, they could use it to consume your quota, incur charges against your Google Cloud project, and request access to user data.
41
42## Building and calling a service
43
44This section describes how to build an API-specific service object, make calls to the service, and process the response.
45
46### Build the service object
47
48Whether you are using simple or authorized API access, you use the [build()](http://google.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build) function to create a service object. It takes an API name and API version as arguments. You can see the list of all API versions on the [Supported APIs](http://developers.google.com/api-client-library/python/apis/) page. The service object is constructed with methods specific to the given API. To create it, do the following:
49
50```py
51from apiclient.discovery import build
52service = build('api_name', 'api_version', ...)
53```
54
55### Collections
56
57Each API service provides access to one or more resources. A set of resources of the same type is called a collection. The names of these collections are specific to the API. The service object is constructed with a function for every collection defined by the API. If the given API has a collection named `stamps`, you create the collection object like this:
58
59```py
60collection = service.stamps()
61```
62
63It is also possible for collections to be nested:
64
65```py
66nested_collection = service.featured().stamps()
67```
68
69### Methods and requests
70
71Every collection has a list of methods defined by the API. Calling a collection's method returns an [HttpRequest](http://google.github.io/google-api-python-client/docs/epy/googleapiclient.http.HttpRequest-class.html) object. If the given API collection has a method named `list` that takes an argument called `cents`, you create a request object for that method like this:
72
73```py
74request = collection.list(cents=5)
75```
76
77### Execution and response
78
79Creating a request does not actually call the API. To execute the request and get a response, call the `execute()` function:
80
81```py
82response = request.execute()
83```
84
85Alternatively, you can combine previous steps on a single line:
86
87```py
88response = service.stamps().list(cents=5).execute()
89```
90
91### Working with the response
92
93The response is a Python object built from the JSON response sent by the API server. The JSON structure is specific to the API; for details, see the API's reference documentation. You can also simply print the JSON to see the structure:
94
95```py
96import json
97...
98print json.dumps(response, sort_keys=True, indent=4)
99```
100
101For example, if the printed JSON is the following:
102
103```json
104{
105 "count": 2,
106 "items": [
107 {
108 "cents": 5,
109 "name": "#586 1923-26 5-cent blue Theodore Roosevelt MLH perf 10"
110 },
111 {
112 "cents": 5,
113 "name": "#628 1926 5-cent Ericsson Memorial MLH"
114 }
115 ]
116}
117```
118
119You can access the data like this:
120
121```py
122print 'Num 5 cent stamps: %d' % response['count']
123print 'First stamp name: %s' % response['items'][0]['name']
124```
125
126## Examples
127
128In this section, we provide examples of each access type and application type.
129
130### Authorized API for web application example
131
132For this example, we use authorized API access for a simple web server. It calls the [Google Calendar API](http://developers.google.com/google-apps/calendar/) to list a user's calendar events. Python's built-in [BaseHTTPServer](http://docs.python.org/2/library/basehttpserver.html) is used to create the server. Actual production code would normally use a more sophisticated web server framework, but the simplicity of `BaseHTTPServer` allows the example to focus on using this library.
133
134#### Setup for example
135
1361. **Activate the Calendar API**: [Read about API activation](http://developers.google.com/console/help/activating-apis) and activate the Calendar API.
1372. **Get your client ID and client secret**: Get a client ID and secret for _web applications_. Use `http://localhost` as your domain. After creating the client ID, edit the _Redirect URIs_ field to contain only `http://localhost:8080/`.
1383. **Create calendar events**: In this example, user calendar events will be read. You can use any Google account you own, including the account associated with the application's Google APIs Console project. For the target user, create a few calendar events if none exist already.
139
140#### Code for example
141
142This script is well commented to explain each step.
143
144```py
145#!/usr/bin/python
146import BaseHTTPServer
147import Cookie
148import httplib2
149import StringIO
150import urlparse
151import sys
152
153from apiclient.discovery import build
154from oauth2client.client import AccessTokenRefreshError
155from oauth2client.client import OAuth2WebServerFlow
156from oauth2client.file import Storage
157
158class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
159 """Child class of BaseHTTPRequestHandler that only handles GET request."""
160
161 # Create a flow object. This object holds the client_id, client_secret, and
162 # scope. It assists with OAuth 2.0 steps to get user authorization and
163 # credentials. For this example, the client ID and secret are command-line
164 # arguments.
165 flow = OAuth2WebServerFlow(sys.argv[1],
166 sys.argv[2],
167 'https://www.googleapis.com/auth/calendar',
168 redirect_uri='http://localhost:8080/')
169
170 def do_GET(self):
171 """Handler for GET request."""
172 print '\nNEW REQUEST, Path: %s' % (self.path)
173 print 'Headers: %s' % self.headers
174
175 # To use this server, you first visit
176 # http://localhost:8080/?fake_user=<some_user_name>. You can use any name you
177 # like for the fake_user. It's only used as a key to store credentials,
178 # and has no relationship with real user names. In a real system, you would
179 # only use logged-in users for your system.
180 if self.path.startswith('/?fake_user='):
181 # Initial page entered by user
182 self.handle_initial_url()
183
184 # When you redirect to the authorization server below, it redirects back
185 # to to http://localhost:8080/?code=<some_code> after the user grants access
186 # permission for your application.
187 elif self.path.startswith('/?code='):
188 # Page redirected back from auth server
189 self.handle_redirected_url()
190 # Only the two URL patterns above are accepted by this server.
191 else:
192 # Either an error from auth server or bad user entered URL.
193 self.respond_ignore()
194
195 def handle_initial_url(self):
196 """Handles the initial path."""
197 # The fake user name should be in the URL query parameters.
198 fake_user = self.get_fake_user_from_url_param()
199
200 # Call a helper function defined below to get the credentials for this user.
201 credentials = self.get_credentials(fake_user)
202
203 # If there are no credentials for this fake user or they are invalid,
204 # we need to get new credentials.
205 if credentials is None or credentials.invalid:
206 # Call a helper function defined below to respond to this GET request
207 # with a response that redirects the browser to the authorization server.
208 self.respond_redirect_to_auth_server(fake_user)
209 else:
210 try:
211 # Call a helper function defined below to get calendar data for this
212 # user.
213 calendar_output = self.get_calendar_data(credentials)
214
215 # Call a helper function defined below which responds to this
216 # GET request with data from the calendar.
217 self.respond_calendar_data(calendar_output)
218 except AccessTokenRefreshError:
219 # This may happen when access tokens expire. Redirect the browser to
220 # the authorization server
221 self.respond_redirect_to_auth_server(fake_user)
222
223 def handle_redirected_url(self):
224 """Handles the redirection back from the authorization server."""
225 # The server should have responded with a "code" URL query parameter. This
226 # is needed to acquire credentials.
227 code = self.get_code_from_url_param()
228
229 # Before we redirected to the authorization server, we set a cookie to save
230 # the fake user for retrieval when handling the redirection back to this
231 # server. This is only needed because we are using this fake user
232 # name as a key to access credentials.
233 fake_user = self.get_fake_user_from_cookie()
234
235 #
236 # This is an important step.
237 #
238 # We take the code provided by the authorization server and pass it to the
239 # flow.step2_exchange() function. This function contacts the authorization
240 # server and exchanges the "code" for credentials.
241 credentials = RequestHandler.flow.step2_exchange(code)
242
243 # Call a helper function defined below to save these credentials.
244 self.save_credentials(fake_user, credentials)
245
246 # Call a helper function defined below to get calendar data for this user.
247 calendar_output = self.get_calendar_data(credentials)
248
249 # Call a helper function defined below which responds to this GET request
250 # with data from the calendar.
251 self.respond_calendar_data(calendar_output)
252
253 def respond_redirect_to_auth_server(self, fake_user):
254 """Respond to the current request by redirecting to the auth server."""
255 #
256 # This is an important step.
257 #
258 # We use the flow object to get an authorization server URL that we should
259 # redirect the browser to. We also supply the function with a redirect_uri.
260 # When the auth server has finished requesting access, it redirects
261 # back to this address. Here is pseudocode describing what the auth server
262 # does:
263 # if (user has already granted access):
264 # Do not ask the user again.
265 # Redirect back to redirect_uri with an authorization code.
266 # else:
267 # Ask the user to grant your app access to the scope and service.
268 # if (the user accepts):
269 # Redirect back to redirect_uri with an authorization code.
270 # else:
271 # Redirect back to redirect_uri with an error code.
272 uri = RequestHandler.flow.step1_get_authorize_url()
273
274 # Set the necessary headers to respond with the redirect. Also set a cookie
275 # to store our fake_user name. We will need this when the auth server
276 # redirects back to this server.
277 print 'Redirecting %s to %s' % (fake_user, uri)
278 self.send_response(301)
279 self.send_header('Cache-Control', 'no-cache')
280 self.send_header('Location', uri)
281 self.send_header('Set-Cookie', 'fake_user=%s' % fake_user)
282 self.end_headers()
283
284 def respond_ignore(self):
285 """Responds to the current request that has an unknown path."""
286 self.send_response(200)
287 self.send_header('Content-type', 'text/plain')
288 self.send_header('Cache-Control', 'no-cache')
289 self.end_headers()
290 self.wfile.write(
291 'This path is invalid or user denied access:\n%s\n\n' % self.path)
292 self.wfile.write(
293 'User entered URL should look like: http://localhost:8080/?fake_user=johndoe')
294
295 def respond_calendar_data(self, calendar_output):
296 """Responds to the current request by writing calendar data to stream."""
297 self.send_response(200)
298 self.send_header('Content-type', 'text/plain')
299 self.send_header('Cache-Control', 'no-cache')
300 self.end_headers()
301 self.wfile.write(calendar_output)
302
303 def get_calendar_data(self, credentials):
304 """Given the credentials, returns calendar data."""
305 output = StringIO.StringIO()
306
307 # Now that we have credentials, calling the API is very similar to
308 # other authorized access examples.
309
310 # Create an httplib2.Http object to handle our HTTP requests, and authorize
311 # it using the credentials.authorize() function.
312 http = httplib2.Http()
313 http = credentials.authorize(http)
314
315 # The apiclient.discovery.build() function returns an instance of an API
316 # service object that can be used to make API calls.
317 # The object is constructed with methods specific to the calendar API.
318 # The arguments provided are:
319 # name of the API ('calendar')
320 # version of the API you are using ('v3')
321 # authorized httplib2.Http() object that can be used for API calls
322 service = build('calendar', 'v3', http=http)
323
324 # The Calendar API's events().list method returns paginated results, so we
325 # have to execute the request in a paging loop. First, build the request
326 # object. The arguments provided are:
327 # primary calendar for user
328 request = service.events().list(calendarId='primary')
329 # Loop until all pages have been processed.
330 while request != None:
331 # Get the next page.
332 response = request.execute()
333 # Accessing the response like a dict object with an 'items' key
334 # returns a list of item objects (events).
335 for event in response.get('items', []):
336 # The event object is a dict object with a 'summary' key.
337 output.write(repr(event.get('summary', 'NO SUMMARY')) + '\n')
338 # Get the next request object by passing the previous request object to
339 # the list_next method.
340 request = service.events().list_next(request, response)
341
342 # Return the string of calendar data.
343 return output.getvalue()
344
345 def get_credentials(self, fake_user):
346 """Using the fake user name as a key, retrieve the credentials."""
347 storage = Storage('credentials-%s.dat' % (fake_user))
348 return storage.get()
349
350 def save_credentials(self, fake_user, credentials):
351 """Using the fake user name as a key, save the credentials."""
352 storage = Storage('credentials-%s.dat' % (fake_user))
353 storage.put(credentials)
354
355 def get_fake_user_from_url_param(self):
356 """Get the fake_user query parameter from the current request."""
357 parsed = urlparse.urlparse(self.path)
358 fake_user = urlparse.parse_qs(parsed.query)['fake_user'][0]
359 print 'Fake user from URL: %s' % fake_user
360 return fake_user
361
362 def get_fake_user_from_cookie(self):
363 """Get the fake_user from cookies."""
364 cookies = Cookie.SimpleCookie()
365 cookies.load(self.headers.get('Cookie'))
366 fake_user = cookies['fake_user'].value
367 print 'Fake user from cookie: %s' % fake_user
368 return fake_user
369
370 def get_code_from_url_param(self):
371 """Get the code query parameter from the current request."""
372 parsed = urlparse.urlparse(self.path)
373 code = urlparse.parse_qs(parsed.query)['code'][0]
374 print 'Code from URL: %s' % code
375 return code
376
377def main():
378 try:
379 server = BaseHTTPServer.HTTPServer(('', 8080), RequestHandler)
380 print 'Starting server. Use Control+C to stop.'
381 server.serve_forever()
382 except KeyboardInterrupt:
383 print 'Shutting down server.'
384 server.socket.close()
385
386if __name__ == '__main__':
387 main()
388```
389
390Note how the Storage object is used to to retrieve and store credentials. If no credentials are found, the `flow.step1_get_authorize_url()` function is used to redirect the user to the authorization server. Once the user has granted access, the authorization server redirects back to the local server with a `code` query parameter. This code is passed to the `flow.step2_exchange()` function, which returns credentials. From that point forward, this script is very similar to the command-line access example above.
391
392#### Run the example
393
3941. Copy the script to an **empty** directory on your computer.
3952. Open a terminal and go to the directory.
3963. Execute the following command to run the local server:
397
398 python authorized_api_web_server_calendar.py your_client_id your_client_secret
399
4004. Open a web browser and log in to your Google account as the target user.
4015. Go to this URL: `http://localhost:8080/?fake_user=target_user_name` replacing `target_user_name` with the user name for the target user.
4026. If this is the first time the target user has accessed this local server, the target user is redirected to the authorization server. The authorization server asks the target user to grant the application access to calendar data. Click the button that allows access.
4037. The authorization server redirects the browser back to the local server.
4048. Calendar events for the target user are listed on the page.
405
406## Django support
407
408This library includes helper classes that simplify use in a [Django](https://www.djangoproject.com/) application. See the [Using Django](http://developers.google.com/api-client-library/python/guide/django) page for details.
409
410## Google App Engine support
411
412This library includes helper classes that simplify use in a [Google App Engine](http://developers.google.com/appengine/) application. See the [Using Google App Engine](http://developers.google.com/api-client-library/python/guide/google_app_engine) page for details.
413
414## Finding information about the APIs
415
416Use the [APIs Explorer](http://developers.google.com/api-client-library/python/reference/apis_explorer) to browse APIs, list available methods, and even try API calls from your browser.
417
418## Library reference documentation
419
420[PyDoc generated documentation](http://developers.google.com/api-client-library/python/reference/pydoc) is available for all modules in this library.
421
422You can get [interactive help](http://developers.google.com/api-client-library/python/reference/interactive_help) on library classes and functions using an interactive Python shell.