blob: 40f26b637ef51c6bb88cfc282fc93b83a87d7cfd [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2017 Google Inc. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""A library for converting service configs to discovery directory lists."""
16
17from __future__ import absolute_import
18
19import collections
20import json
21import re
22from six.moves import urllib
23
24from . import util
25
26
27class DirectoryListGenerator(object):
28 """Generates a discovery directory list from a ProtoRPC service.
29
30 Example:
31
32 class HelloRequest(messages.Message):
33 my_name = messages.StringField(1, required=True)
34
35 class HelloResponse(messages.Message):
36 hello = messages.StringField(1, required=True)
37
38 class HelloService(remote.Service):
39
40 @remote.method(HelloRequest, HelloResponse)
41 def hello(self, request):
42 return HelloResponse(hello='Hello there, %s!' %
43 request.my_name)
44
45 api_config = DirectoryListGenerator().pretty_print_config_to_json(
46 HelloService)
47
48 The resulting document will be a JSON directory list describing the APIs
49 implemented by HelloService.
50 """
51
52 def __init__(self, request=None):
53 # The ApiRequest that called this generator
54 self.__request = request
55
56 def __item_descriptor(self, config):
57 """Builds an item descriptor for a service configuration.
58
59 Args:
60 config: A dictionary containing the service configuration to describe.
61
62 Returns:
63 A dictionary that describes the service configuration.
64 """
65 descriptor = {
66 'kind': 'discovery#directoryItem',
67 'icons': {
68 'x16': 'https://www.gstatic.com/images/branding/product/1x/'
69 'googleg_16dp.png',
70 'x32': 'https://www.gstatic.com/images/branding/product/1x/'
71 'googleg_32dp.png',
72 },
73 'preferred': True,
74 }
75
76 description = config.get('description')
77 root_url = config.get('root')
78 name = config.get('name')
79 version = config.get('api_version')
80 relative_path = '/apis/{0}/{1}/rest'.format(name, version)
81
82 if description:
83 descriptor['description'] = description
84
85 descriptor['name'] = name
86 descriptor['version'] = version
87 descriptor['discoveryLink'] = '.{0}'.format(relative_path)
88
89 root_url_port = urllib.parse.urlparse(root_url).port
90
91 original_path = self.__request.reconstruct_full_url(
92 port_override=root_url_port)
93 descriptor['discoveryRestUrl'] = '{0}/{1}/{2}/rest'.format(
94 original_path, name, version)
95
96 if name and version:
97 descriptor['id'] = '{0}:{1}'.format(name, version)
98
99 return descriptor
100
101 def __directory_list_descriptor(self, configs):
102 """Builds a directory list for an API.
103
104 Args:
105 configs: List of dicts containing the service configurations to list.
106
107 Returns:
108 A dictionary that can be deserialized into JSON in discovery list format.
109
110 Raises:
111 ApiConfigurationError: If there's something wrong with the API
112 configuration, such as a multiclass API decorated with different API
113 descriptors (see the docstring for api()), or a repeated method
114 signature.
115 """
116 descriptor = {
117 'kind': 'discovery#directoryList',
118 'discoveryVersion': 'v1',
119 }
120
121 items = []
122 for config in configs:
123 item_descriptor = self.__item_descriptor(config)
124 if item_descriptor:
125 items.append(item_descriptor)
126
127 if items:
128 descriptor['items'] = items
129
130 return descriptor
131
132 def get_directory_list_doc(self, configs):
133 """JSON dict description of a protorpc.remote.Service in list format.
134
135 Args:
136 configs: Either a single dict or a list of dicts containing the service
137 configurations to list.
138
139 Returns:
140 dict, The directory list document as a JSON dict.
141 """
142
143 if not isinstance(configs, (tuple, list)):
144 configs = [configs]
145
146 util.check_list_type(configs, dict, 'configs', allow_none=False)
147
148 return self.__directory_list_descriptor(configs)
149
150 def pretty_print_config_to_json(self, configs):
151 """JSON string description of a protorpc.remote.Service in a discovery doc.
152
153 Args:
154 configs: Either a single dict or a list of dicts containing the service
155 configurations to list.
156
157 Returns:
158 string, The directory list document as a JSON string.
159 """
160 descriptor = self.get_directory_list_doc(configs)
161 return json.dumps(descriptor, sort_keys=True, indent=2,
162 separators=(',', ': '))