Google API 탐색 서비스를 사용하여 Google API와 함께 사용할 다양한 도구를 빌드할 수 있습니다.
하지만 탐색 문서의 주요 목적은 Google에서 다양한 프로그래밍 언어로 클라이언트 라이브러리를 만들 수 있도록 하는 것입니다. 이 문서에서는 Google API용 커스텀 클라이언트 라이브러리를 빌드하는 방법을 설명합니다.
안정적이고 모든 기능을 갖춘 클라이언트 라이브러리는 개발하는 데 몇 개월이 걸릴 수 있는 복잡한 도구입니다. 그러나 간단한 Google API용 클라이언트 라이브러리를 빌드하는 일반적인 지침은 세 가지 간단한 단계로 나눌 수 있습니다.
탐색 문서 가져오기 및 API 노출 영역 생성
요청 작성
호출하고 응답 가져오기
이러한 단계에 대해서는 다음 섹션에서 더 자세히 설명합니다. 예시 섹션의 간단한 API 클라이언트 샘플에서 이러한 안내가 코드에 어떻게 매핑되는지 확인할 수도 있습니다.
탐색 문서 가져오기
클라이언트 라이브러리를 구현하기 전에 개발 경로를 진행하는 방법에 영향을 미치는 몇 가지 기본 요구사항이 있습니다. 예를 들어 원하는 프로그래밍 언어가 입력되거나 입력되지 않을 수 있습니다. 유형이면 정적 또는 동적 유형일 수 있습니다. 컴파일되거나 해석될 수 있습니다. 이러한 요구사항은 탐색 문서를 사용하고 소비하는 방법을 안내합니다.
첫 번째 개발 작업은 탐색 문서를 가져오는 것입니다. 문서를 가져올 정확한 시점은 식별된 요구사항에 따라 결정됩니다. 예를 들어 정적 유형의 언어에서는 프로세스 초기에 탐색 문서를 가져온 후 탐색 문서에 기술된 특정 API를 처리하는 코드를 생성할 수 있습니다. 강력하게 유형화된 언어의 경우 일부 코드를 생성하고 컴파일된 라이브러리를 빌드할 수 있습니다. 동적 유형 언어의 경우 프로그래밍 노출 영역이 사용되는 즉시 API와 상호작용하는 프로그래밍 구조를 느리게 구성할 수 있습니다.
요청 작성
요청 작성에는 두 가지 개별 단계가 포함됩니다.
요청 본문 작성
요청 URL 구성
요청 본문(있는 경우)을 언어에 적합한 표현에서 올바른 전송 형식으로 변환해야 합니다. 예를 들어 Java 클라이언트 라이브러리에는 요청 데이터의 유형 안전 조작을 허용하고 JSON으로 직렬화할 수 있는 각 요청 유형의 클래스가 있을 수 있습니다.
요청 URL 구성은 약간 더 복잡한 프로세스입니다.
API에서 각 메서드의 path 속성은 URI 템플릿 v04 구문을 사용합니다. 이 속성에는 중괄호로 묶인 변수가 포함될 수 있습니다. 다음은 변수가 포함된 path 속성의 예시입니다.
/example/path/var
위 경로에서 var는 변수입니다. 이 변수의 값은 해당 메서드에 대한 탐색 문서의 parameters 섹션에서 가져옵니다. 각 변수 이름에는 parameters 객체의 해당 값이 있습니다. 위 예시에서는 parameters 섹션에 var라는 매개변수가 있습니다. 해당 location 속성은 경로 변수임을 나타내기 위해 path입니다.
요청을 수행할 때 URL에서 var 값을 대체해야 합니다.
예를 들어 라이브러리 사용자가 var를 foo 값으로 설정하도록 선택하면 새 URL은 /example/path/foo가 됩니다.
또한 path 속성은 상대 URI입니다. 절대 URI를 계산하려면 다음 단계를 따르세요.
위치(리전)를 알고 있고 탐색 문서에 endpoints 속성이 있는 경우 위치가 endpoints 목록에 있는지 확인합니다. 그렇다면 location이 내 위치와 일치하는 endpoints 목록에서 endpointUrl을 가져옵니다.
탐색 문서에 endpoints 속성이 없거나 위치가 endpoints 목록에 없거나 전역 엔드포인트를 타겟팅하려면 탐색 문서의 최상위 수준에서 rootUrl 속성을 가져옵니다.
탐색 문서의 최상위 수준에서 servicePath를 가져옵니다. 예를 들어 Service Usage API의 탐색 문서에 있는 servicePath 속성은 비어 있습니다.
이를 함께 연결하여 다음을 얻을 수 있습니다.
https://serviceusage.googleapis.com/
path 속성을 가져와서 URI 템플릿으로 확장하고 확장 결과를 이전 단계의 URI와 결합합니다. 예를 들어 v1 Service Usage API의 serviceusage.services.enable 메서드에서 path 속성 값은 v1/{+name}:enable입니다. 따라서 이 메서드의 전체 URI는 다음과 같습니다.
Service Usage API를 호출하는 데 API 키가 필요하지 않습니다. 그러나 호출하는 API에 API 키가 필요한 경우 다음과 같이 URI의 쿼리 문자열에 API 키를 추가할 수 있습니다.
REQUEST_URI?key=API_KEY
호출하기 및 응답 처리
요청을 보낸 후에는 응답을 적절한 언어 표현으로 역직렬화해야 하며, 기본 HTTP 전송과 API 서비스에서 생성된 오류 메시지 모두에서 발생할 수 있는 오류 조건을 처리해야 합니다. 오류 형식은 Google JSON 스타일 가이드의 일부에 설명되어 있습니다.
예시
다음 섹션에서는 API 클라이언트 라이브러리의 간단한 예시를 보여줍니다.
간단한 API 클라이언트
다음은 Python3로 작성된 매우 간단한 클라이언트 라이브러리의 예시입니다. 클라이언트는 Service Usage API와 상호작용하기 위한 인터페이스를 빌드한 후 이 인터페이스를 사용하여 my-project 프로젝트에서 Compute Engine API(compute.googleapis.com)를 사용 설정합니다.
importhttplib2importjsonimporturitemplateimporturllib# Step 1: Fetch Discovery documentDISCOVERY_URI="https://serviceusage.googleapis.com/$discovery/rest?version=v1"h=httplib2.Http()resp,content=h.request(DISCOVERY_URI)discovery=json.loads(content)location=None# Set this to your location if appropriateuse_global_endpoint=True# Set this to False if you want to target the endpoint for your location# Step 2.a: Construct base URIBASE_URL=Noneifnotuse_global_endpointandlocation:ifdiscovery['endpoints']:BASE_URL=next((item['endpointUrl']foritemindiscovery['endpoints']ifitem['location']==location),None)ifnotBASE_URL:BASE_URL=discovery['rootUrl']BASE_URL+=discovery['servicePath']classCollection(object):passdefcreateNewMethod(name,method):# Step 2.b Compose requestdefnewMethod(**kwargs):body=kwargs.pop('body',None)url=urllib.parse.urljoin(BASE_URL,uritemplate.expand(method['path'],kwargs))forpname,pconfiginmethod.get('parameters',{}).items():ifpconfig['location']=='path'andpnameinkwargs:delkwargs[pname]ifkwargs:url=url+'?'+urllib.parse.urlencode(kwargs)returnh.request(url,method=method['httpMethod'],body=body,headers={'content-type':'application/json'})returnnewMethod# Step 3.a: Build client surfacedefbuild(discovery,collection):forname,resourceindiscovery.get('resources',{}).items():setattr(collection,name,build(resource,Collection()))forname,methodindiscovery.get('methods',{}).items():setattr(collection,name,createNewMethod(name,method))returncollection# Step 3.b: Use the clientservice=build(discovery,Collection())print(serviceusage.services.enable(name='projects/my-project/services/compute.googleapis.com'))
클라이언트의 주요 구성요소는 다음과 같습니다.
1단계: 탐색 문서를 가져옵니다. Service Usage API의 탐색 문서가 검색되어 데이터 구조로 파싱됩니다. Python은 동적 유형이 지정된 언어이므로 런타임 시 탐색 문서를 가져올 수 있습니다.
2.a단계: 기본 URI를 구성합니다.
기본 URI가 계산됩니다.
2.b단계: 요청을 작성합니다. 컬렉션에서 메서드가 호출되면 URI 템플릿이 메서드에 전달된 매개변수로 확장되고 위치가 query인 매개변수는 URL의 쿼리 매개변수에 배치됩니다. 마지막으로 탐색 문서에 지정된 HTTP 메서드를 사용하여 작성된 URL로 요청이 전송됩니다.
3.a단계: 클라이언트 노출 영역을 빌드합니다. 클라이언트 노출 영역은 파싱된 탐색 문서를 재귀적으로 내림차순으로 빌드됩니다. methods 섹션의 각 메서드에 대해 새 메서드가 Collection 객체에 연결됩니다. 컬렉션이 중첩될 수 있으므로 resources를 찾고 리소스가 있으면 모든 멤버에 대해 Collection 객체를 재귀적으로 빌드합니다 각 중첩된 컬렉션은 Collection 객체에 속성으로도 연결됩니다.
3.b단계: 클라이언트를 사용합니다. 이는 빌드된 API 노출 영역이 사용되는 방법을 보여줍니다. 먼저 탐색 문서에서 서비스 객체를 빌드한 후 Service Usage API를 사용하여 my-project 프로젝트에서 Compute Engine API를 사용 설정합니다.
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["이해하기 어려움","hardToUnderstand","thumb-down"],["잘못된 정보 또는 샘플 코드","incorrectInformationOrSampleCode","thumb-down"],["필요한 정보/샘플이 없음","missingTheInformationSamplesINeed","thumb-down"],["번역 문제","translationIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-07-29(UTC)"],[[["\u003cp\u003eThe Google APIs Discovery Service allows developers to build custom client libraries for Google APIs, with the primary purpose of facilitating the creation of client libraries in various programming languages.\u003c/p\u003e\n"],["\u003cp\u003eBuilding a client library involves three main steps: fetching the Discovery document to construct the API surface, composing a request including its body and URL, and making the API call to fetch the response.\u003c/p\u003e\n"],["\u003cp\u003eFetching the Discovery document's timing is influenced by the programming language's type system, whether statically-typed languages benefit from early fetching and code generation, while dynamically typed languages can fetch and adapt at runtime.\u003c/p\u003e\n"],["\u003cp\u003eComposing a request involves creating the request body and constructing the request URL, where the URL's path is built using URI Template v04 syntax, incorporating variables from the Discovery document's parameters section.\u003c/p\u003e\n"],["\u003cp\u003eThe client library, after sending a request, must deserialize the response and handle potential error conditions, including HTTP transport issues and error messages following the Google JSON Style Guide.\u003c/p\u003e\n"]]],[],null,["# Build a client library\n\nYou can use the Google APIs Discovery Service for building a variety of different tools to use with Google APIs.\nHowever, the primary purpose of the Discovery document is to allow Google to create client\nlibraries in various programming languages. This document describes how you could go about\nbuilding a custom client library for Google APIs.\n\n\nA stable and feature-complete client library is a complicated tool that can take months to\ndevelop. However, the general instructions for building a simple client library for Google\nAPIs can be broken down to three simple steps:\n\n1. Fetching the Discovery document and constructing API surface\n2. Composing a request\n3. Making a call and fetching the response\n\n\nThese steps are described in more detail in the following sections. You can also have a look\nat the [Simple APIs client](#simple_apis_client) sample in the Examples section to see how\nthese instructions map to the code.\n\nFetch the Discovery document\n----------------------------\n\n\nBefore you begin implementing a client library, there are some basic requirements that impact\nhow you will proceed down your development path. For example, your programming language of\nchoice may be either typed or untyped; if it is typed it could be either statically or\ndynamically typed. It may be compiled or interpreted. These requirements will guide your\napproach to consuming and using the Discovery document.\n\n\nThe first development task is to fetch the Discovery document. Your strategy for exactly when\nthe document is to be fetched is determined by the requirements you identified. For example,\nin a statically-typed language, you might fetch the Discovery document early in the process\nand then generate code to handle the specific API described by the Discovery document. For a\nstrongly-typed language, you might generate some code and build a compiled library. For a\ndynamically typed language, you can lazily construct the programming structures to interface\nto the API on the fly as the programming surface is used.\n\nCompose a request\n-----------------\n\nComposing a requests involves two separate steps:\n\n1. Composing the request body.\n2. Constructing the request URL.\n\n\nYou need to convert the request body, if any, from a language-appropriate\nrepresentation into the correct wire format. For example, in a Java client\nlibrary, there may be a class for each request type that allows type-safe\nmanipulation of the request data and is serializable into JSON.\n\n\nThe construction of the request URL is a slightly more complicated process.\n\n\nThe `path` property of each method in the API uses [URI Template v04](https://code.google.com/p/uri-templates/) syntax. This property may\ncontain variables, which are surrounded by curly braces. Here is an example of a\n`path` property with variables: \n\n```\n/example/path/var\n```\n\n\nIn the path above, `var` is a variable. The value for this variable comes from the\nDiscovery document's `parameters` section for that method. Each variable name has\na corresponding value in the `parameters` object. In the example above, there is a\nparameter named `var` in the `parameters` section (and its\n`location` property is `path`, to indicate that it is a path\nvariable).\n\n\nWhen making a request, you should substitute the value for `var` into the URL.\nFor example, if the user of the library makes a choice that sets `var` to the\nvalue `foo`, the new URL will be `/example/path/foo`.\n\n\nAlso note that the `path` property is a relative URI. In order to calculate the\nabsolute URI, follow these steps:\n\n1. If you know your location (region), and the Discovery document has the `endpoints` property, check if your location is present in the `endpoints` list. If so, grab the `endpointUrl` from the `endpoints` list whose `location` matches yours.\n2.\n If there is no `endpoints` property in the Discovery document or your location\n is not present in the `endpoints` list or you want to target the global\n endpoint, grab the `rootUrl` property from the top level of the\n Discovery document.\n\n\n For example, the `rootUrl` property in the\n [Discovery document](https://serviceusage.googleapis.com/$discovery/rest?version=v1) for\n [the Service Usage API](https://cloud.google.com/service-usage/docs/reference/rest) is: \n\n ```\n https://serviceusage.googleapis.com/\n ```\n3. Grab the `servicePath` from the top level of the Discovery document. For example, the `servicePath` property in the Discovery document for the Service Usage API is empty.\n4. Concatenate them together to get:\n\n ```\n https://serviceusage.googleapis.com/\n ```\n5.\n Grab the `path` property, expand it as a URI Template, and combine the results\n of that expansion with the URI from the previous step. For example, in the v1 Service\n Usage API's `serviceusage.services.enable` method, the value of the\n `path` property is `v1/{+name}:enable`. So, the full URI for the\n method is:\n\n ```\n https://serviceusage.googleapis.com/v1/{+name}:enable\n ```\n\n\nYou don't need an [API key](https://cloud.google.com/docs/authentication/api-keys)\nto call the Service Usage API. However, if the API you're calling requires an API key, you can\nadd the API key to the URI's query string: \n\n```\nREQUEST_URI?key=API_KEY\n```\n\nMake a call and handle the response\n-----------------------------------\n\n\nAfter you send the request, the you need to deserialize the response into the appropriate\nlanguage representation, taking care to handle error conditions that could occur---both in the\nunderlying HTTP transport and error messages generated from the API service. The format of the\nerrors is documented as part of the [Google JSON Style\nGuide](https://google.github.io/styleguide/jsoncstyleguide.xml#error).\n\nExamples\n--------\n\n\nThe following section gives a simple example of an APIs client library.\n\n### Simple APIs client\n\n\nBelow is an example of a very simple client library written in Python3. The client builds an\ninterface for interacting with the [Service Usage API](https://cloud.google.com/service-usage/docs/reference/rest), then\nuses that interface to enable the Compute Engine API (`compute.googleapis.com`) in\nthe project `my-project`.\n**Warning:** The code below is a significantly simplified version of a typical client library. It is an incomplete implementation that is provided to demonstrate some aspects of building a client library. It is not production-ready code. \n\n```python\nimport httplib2\nimport json\nimport uritemplate\nimport urllib\n\n# Step 1: Fetch Discovery document\nDISCOVERY_URI = \"https://serviceusage.googleapis.com/$discovery/rest?version=v1\"\nh = httplib2.Http()\nresp, content = h.request(DISCOVERY_URI)\ndiscovery = json.loads(content)\nlocation = None # Set this to your location if appropriate\nuse_global_endpoint = True # Set this to False if you want to target the endpoint for your location\n\n# Step 2.a: Construct base URI\nBASE_URL = None\nif not use_global_endpoint and location:\n if discovery['endpoints']:\n BASE_URL = next((item['endpointUrl'] for item in discovery['endpoints'] if item['location'] == location), None)\nif not BASE_URL:\n BASE_URL = discovery['rootUrl']\nBASE_URL += discovery['servicePath']\n\nclass Collection(object): pass\n\ndef createNewMethod(name, method):\n # Step 2.b Compose request\n def newMethod(**kwargs):\n body = kwargs.pop('body', None)\n url = urllib.parse.urljoin(BASE_URL, uritemplate.expand(method['path'], kwargs))\n for pname, pconfig in method.get('parameters', {}).items():\n if pconfig['location'] == 'path' and pname in kwargs:\n del kwargs[pname]\n if kwargs:\n url = url + '?' + urllib.parse.urlencode(kwargs)\n return h.request(url, method=method['httpMethod'], body=body,\n headers={'content-type': 'application/json'})\n\n return newMethod\n\n# Step 3.a: Build client surface\ndef build(discovery, collection):\n for name, resource in discovery.get('resources', {}).items():\n setattr(collection, name, build(resource, Collection()))\n for name, method in discovery.get('methods', {}).items():\n setattr(collection, name, createNewMethod(name, method))\n return collection\n\n# Step 3.b: Use the client\nservice = build(discovery, Collection())\nprint (serviceusage.services.enable(name='projects/my-project/services/compute.googleapis.com'))\n```\n\nThe critical components of the client are:\n\n- **Step 1: Fetch the Discovery document**. The Discovery document for the Service Usage API is retrieved and parsed into a data structure. Since Python is a dynamically typed language, the Discovery document can be fetched at runtime.\n- **Step 2.a: Construct the base URI**. The base URI is calculated.\n- **Step 2.b: Compose the request** . When a method is called on a collection the URI Template is expanded with the parameters passed into the method, and parameters with a location of `query` are put into the query parameters of the URL. Finally a request is sent to the composed URL using the HTTP method specified in the Discovery document.\n- **Step 3.a: Build the client surface** . The client surface is built by recursively descending over the parsed Discovery document. For each method in the `methods` section a new method is attached to the `Collection` object. Because collections can be nested we look for `resources` and recursively build a `Collection` object for all of its members if one is found. Each nested collection is also attached as an attribute to the `Collection` object.\n- **Step 3.b: Use the client** . This demonstrates how the built API surface is used. First a service object is built from the Discovery document, then the Service Usage API is used to enable the Compute Engine API in the project `my-project`."]]