def generate(package): doc = [] with mock_import.mock_import([package]): for resource_class, parents in packages.iter_resource_classes(package): resource_path = common.url_join( *([parent.path for parent in parents] + [resource_class.path()])) for route in resource_class.iter_route_methods(): arguments = [] for name, arg in six.iteritems(route.spec.args_info): argument = { 'name': route.keyword_map.get(name, name), 'type': arg.type_name, 'doc': arg.doc, } if isinstance(arg, (_args.KeywordArg, _args.OptionalArg)): argument['default'] = arg.default arguments.append(argument) doc.append({ 'name': route.__name__, 'arguments': arguments, 'method': route.method, 'path': common.url_join(resource_path, route.path), 'success_status': route.success_code, 'doc': route.spec.doc, 'cli_command': _build_cli_command(parents, resource_class, route) }) return doc
def proxy(req, dest, redirection_url=None): redirection_url = common.url_join( dest, req.relative_uri) if redirection_url is None else redirection_url LOG.debug('[Proxy %s] to %s', req.uid, redirection_url) inner_request = requests.Request( req.method, url=redirection_url, data=req.content if req.method not in common.URL_PARAMS_METHODS else None, headers={ k: v if k.lower() != "host" else six.moves.urllib.parse.urlparse(dest).netloc for k, v in six.iteritems(req.headers) if v != "" }, ) session = requests.Session() try: prepared = session.prepare_request(inner_request) if req.headers.get(common.CONTENT_LENGTH): prepared.headers[common.CONTENT_LENGTH] = req.headers.get( common.CONTENT_LENGTH) if prepared.headers.get('TRANSFER-ENCODING'): del prepared.headers['TRANSFER-ENCODING'] inner_response = session.send(prepared, stream=True) return response.Response(inner_response.raw, inner_response.headers, inner_response.status_code) finally: session.close()
def _add_sink_methods(self, resource, base_path): """Add sink methods of a resource. :param resource: a Resource class :param base_path: path of resource mounting """ for sink_path, responder in resource.sinks: path = '/' + common.url_join(base_path, sink_path) self.add_sink(path, responder)
def _add_route_methods(self, resource, base_path): """Add route methods of a resource :param resource: a Resource class :param base_path: path of resource mounting """ for route_path, methods_map in six.iteritems(resource.routes): path = '/' + common.url_join(base_path, route_path) self.add_route(path, methods_map)
def routes(self): """ :return: A dict representing routes in a resource: { url: {method: responder} } """ routes = collections.defaultdict(dict) errors = [] for route_method in self.iter_route_methods(): try: route_method.set_resource(self) routes[common.url_join(self.path(), route_method.path)][route_method.method] = route_method.call except exceptions.BadResourceDefinition as exc: errors.append(exc) if errors: for error in errors: logging.error(error) raise exceptions.BadResourceDefinition('Bad definition of resource, see log for errors.') return routes
def sinks(self): """ :return: A list representing sinks in a resource: ( url, responder ) The list is sorted by url size, largest first. """ sinks = [] errors = [] for sink_method in self.iter_sink_methods(): try: sink_method.set_resource(self) sinks.append((common.url_join(self.path(), sink_method.path), sink_method.call)) except exceptions.BadResourceDefinition as exc: errors.append(exc) if errors: for error in errors: logging.error(error) raise exceptions.BadResourceDefinition('Bad definition of resource, see log for errors.') return sinks
def generate_swagger(package): doc = OrderedDict( swagger='2.0', info={ 'title': package, 'version': '1.0.0', } ) paths = defaultdict(dict) definitions = {} with mock_import.mock_import([package]): for resource_class, parents in packages.iter_resource_classes(package): resource_path = common.url_join(*([parent.path for parent in parents] + [resource_class.path()])) for route in resource_class.iter_route_methods(): path = '/' + common.url_join(resource_path, route.path) path_vars = PATH_VARIABLE.findall(path) method = route.method.lower() # classify params by source: path, query or body params = defaultdict(dict) for name, arg in six.iteritems(route.spec.args_info): if name.startswith('_'): continue if name in path_vars: params['path'][name] = arg elif method in ['get']: params['query'][name] = arg elif method in ['post', 'put', 'patch']: params['body'][name] = arg parameters = [] # add all path params for name, arg in six.iteritems(params['path']): parameters.append(_generate_param_dict(route, name, arg, 'path', True)) # add all query params for name, arg in six.iteritems(params['query']): required = not isinstance(arg, (_args.KeywordArg, _args.OptionalArg)) parameters.append(_generate_param_dict(route, name, arg, 'query', required)) # add body param if needed properties = {} required = [] for name, arg in six.iteritems(params['body']): prop_name = route.keyword_map.get(name, name) properties[prop_name] = { 'type': SWAGGER_TYPES.get(arg.type_name, "string"), 'description': arg.doc or "", } if not isinstance(arg, (_args.KeywordArg, _args.OptionalArg)): required.append(prop_name) operation_id = _build_operation_id(parents, resource_class, route) if len(properties) > 0: param_name = operation_id + '_object' param = { 'name': param_name, 'in': 'body', 'schema': { '$ref': '#/definitions/' + param_name, } } parameters.append(param) definitions[param_name] = dict(type='object', properties=properties) if len(required) > 1: definitions[param_name]['required'] = required operation = { 'description': route.spec.doc or '', 'parameters': parameters, 'responses': { route.success_code: { 'description': 'default response' } } } paths[path][method] = operation doc['paths'] = paths doc['definitions'] = definitions return doc