def swagger_doc_gen(func): """ decorator """ method = getattr(cls, method_name, None) method_doc = parse_object_doc(method) class_name = cls.__name__ if tags is None: doc_tags = [cls._s_collection_name] else: doc_tags = tags responses = method_doc.get( "responses", {HTTPStatus.OK.value: { "description": HTTPStatus.OK.description }}) if is_debug(): responses.update(debug_responses) summary = method_doc.get( "summary", "Invoke {}.{}".format(class_name, method_name)) description = method_doc.get("description", summary) doc = { "tags": doc_tags, "description": description, "summary": summary, "responses": responses } model_name = "{}_{}_{}".format("Invoke ", class_name, method_name) param_model = SchemaClassFactory(model_name, {}) parameters, fields, description, method = get_swagger_doc_arguments( cls, method_name, http_method=func.__name__) if func.__name__ == "get": if not parameters: parameters = [{ "name": "varargs", "in": "query", "description": "{} arguments".format(method_name), "required": False, "type": "string", }] else: # Retrieve the swagger schemas for the jsonapi_rpc methods from the docstring parameters, fields, description, method = get_swagger_doc_arguments( cls, method_name, http_method=func.__name__) model_name = "{}_{}_{}".format(func.__name__, cls.__name__, method_name) param_model = SchemaClassFactory(model_name, fields) parameters.append({ "name": model_name, "in": "body", "description": description, "schema": param_model, "required": True }) # URL Path Parameter default_id = cls._s_sample_id() parameters.append({ "name": cls._s_object_id, "in": "path", "type": "string", "default": default_id, "required": True }) # parameter id, e.g. UserId doc["parameters"] = parameters doc["produces"] = ["application/vnd.api+json"] apply_fstring(doc, locals()) return swagger.doc(doc)(func)
def swagger_doc_gen(func, instance=False): """ Decorator used to document SAFRSRestAPI HTTP methods exposed in the API """ default_id = cls._s_sample_id() class_name = cls.__name__ collection_name = cls._s_collection_name http_method = func.__name__.lower() parameters = [ { "name": cls._s_object_id, "in": "path", "type": "string", "default": default_id, "required": True, }, # parameter id, e.g. UserId { "name": "Content-Type", # parameter id, e.g. UserId "in": "header", "type": "string", "default": "application/vnd.api+json", "enum": ["application/vnd.api+json", "application/json"], "required": True, }, ] if tags is None: doc_tags = [collection_name] else: doc_tags = tags doc = {"tags": doc_tags} responses = {} # adhere to open api # the model_name will hold the OAS "$ref" schema reference coll_model_name = "{}_coll".format(class_name) # collection model name inst_model_name = "{}_inst".format(class_name) # instance model name sample_dict = cls._s_sample_dict() # Samples with "id" are used for GET and PATCH sample_instance = { "attributes": sample_dict, "type": cls._s_type, "id": cls._s_sample_id() } if http_method == "get": sample_rels = {} for rel_name, val in cls._s_relationships.items(): sample_rels[rel_name] = { "data": None if val.direction is MANYTOONE else [], "links": { "self": None } } sample_instance["relationships"] = sample_rels coll_sample_data = schema_from_object(coll_model_name, {"data": [sample_instance]}) coll_sample_data.description += "{} {};".format( class_name, http_method) inst_sample_data = schema_from_object(inst_model_name, {"data": sample_instance}) inst_sample_data.description += "{} {};".format( class_name, http_method) cls.swagger_models["instance"] = inst_sample_data cls.swagger_models["collection"] = coll_sample_data if http_method == "get": doc["summary"] = "Retrieve a {} object".format(class_name) doc["collection_summary"] = "Retrieve a collection of {} objects".format( class_name) body, responses = cls._s_get_swagger_doc(http_method) responses[HTTPStatus.OK.value] = { "schema": coll_sample_data, "description": HTTPStatus.OK.description } elif http_method == "patch": post_model, responses = cls._s_get_swagger_doc(http_method) parameters.append({ "name": "PATCH body", "in": "body", "description": "{} attributes".format(class_name), "schema": inst_sample_data, "required": True, }) responses[HTTPStatus.OK.value] = { "schema": inst_sample_data, "description": HTTPStatus.OK.description } elif http_method == "post": _, responses = cls._s_get_swagger_doc(http_method) doc["summary"] = "Create a {} object".format(class_name) # Create the default POST body schema sample_dict = cls._s_sample_dict() # The POST sample doesn't contain an "id", unless cls.allow_client_generated_ids is True if cls.allow_client_generated_ids: sample_data = schema_from_object( inst_model_name, { "data": { "attributes": sample_dict, "type": cls._s_type, "id": "client_generated" } }) else: sample_data = schema_from_object( inst_model_name, {"data": { "attributes": sample_dict, "type": cls._s_type }}) sample_data.description += "{} {};".format(class_name, http_method) parameters.append({ "name": "POST body", "in": "body", "description": "{} attributes".format(class_name), "schema": sample_data, "required": True, }) responses[HTTPStatus.CREATED.value] = { "schema": inst_sample_data, "description": HTTPStatus.CREATED.description } elif http_method == "delete": _, responses = cls._s_get_swagger_doc(http_method) elif http_method != "options": # one of 'options', 'head', 'delete' safrs.log.debug( 'no additional documentation for "{}" '.format(func)) if is_debug(): responses.update(debug_responses) doc["parameters"] = parameters doc["responses"] = responses doc["produces"] = ["application/vnd.api+json"] method_doc = parse_object_doc(func) safrs.dict_merge(doc, method_doc) apply_fstring(doc, locals()) update_response_schema(doc["responses"]) return swagger.doc(doc)(func)
def swagger_doc_gen(func): """ Decorator used to document relationship methods exposed in the API """ parent_class = cls.relationship.parent.class_ child_class = cls.relationship.mapper.class_ class_name = cls.__name__ http_method = func.__name__.lower() ####################################################################### # Following will only happen when exposing an exisiting DB # if not getattr(parent_class, "object_id", None): parent_class._s_object_id = parent_class.__name__ + "Id" if not getattr(child_class, "object_id", None): child_class._s_object_id = child_class.__name__ + "Id" if not getattr(parent_class, "sample_id", None): setattr(parent_class, "sample_id", lambda: "") if not getattr(child_class, "sample_id", None): setattr(child_class, "sample_id", lambda: "") if not getattr(child_class, "get_swagger_doc", None): setattr(child_class, "get_swagger_doc", lambda x: (None, {})) # ####################################################################### parameters = [ { "name": parent_class._s_object_id, "in": "path", "type": "string", "default": parent_class._s_sample_id(), "description": "{} item".format(parent_class.__name__), "required": True, }, { "name": child_class._s_object_id, "in": "path", "type": "string", "default": child_class._s_sample_id(), "description": "{} item".format(class_name), "required": True, }, ] if tags is None: doc_tags = [cls._s_collection_name] else: doc_tags = tags doc = {"tags": doc_tags} doc.update(parse_object_doc(func)) responses = {} # Shema names (for the swagger "references") model_name = "{}_rel_inst".format(class_name) # instance model name if cls.relationship.direction in (ONETOMANY, MANYTOMANY): model_name = "{}_rel_coll".format( class_name) # collection model name if http_method == "get": _, responses = cls._s_get_swagger_doc(http_method) elif http_method in ("post", "patch"): _, responses = cls._s_get_swagger_doc(http_method) child_sample_id = child_class._s_sample_id() _, responses = child_class._s_get_swagger_doc("patch") data = {"type": child_class._s_type, "id": child_sample_id} if cls.relationship.direction in (ONETOMANY, MANYTOMANY): # tomany relationships only return a 204 accepted data = [data] responses.pop(HTTPStatus.OK.value, None) rel_post_schema = schema_from_object(model_name, {"data": data}) rel_post_schema.description += "{} {} relationship;".format( class_name, http_method) cls.swagger_models["instance"] = rel_post_schema cls.swagger_models["collection"] = rel_post_schema parameters.append({ "name": "{} body".format(class_name), "in": "body", "description": "{} POST model".format(class_name), "schema": rel_post_schema, "required": True, }) if cls.relationship.direction is MANYTOONE: # toone relationships return 200 OK responses[HTTPStatus.OK.value] = { "schema": rel_post_schema, "description": HTTPStatus.OK.description } elif http_method == "delete": child_sample_id = child_class._s_sample_id() _, responses = child_class._s_get_swagger_doc("patch") data = {"type": child_class._s_type, "id": child_sample_id} if cls.relationship.direction in (ONETOMANY, MANYTOMANY): data = [data] rel_del_schema = schema_from_object(model_name, {"data": data}) parameters.append({ "name": "{} body".format(class_name), "in": "body", "description": "{} POST model".format(class_name), "schema": rel_del_schema, "required": True, }) elif http_method != "options": # one of 'options', 'head', 'patch' safrs.log.info('no documentation for "{}" '.format(http_method)) doc["parameters"] = parameters if doc.get("responses"): responses.update( {str(val): desc for val, desc in doc["responses"].items()}) if is_debug(): responses.update(debug_responses) doc["responses"] = responses direction = "to-many" if cls.relationship.direction in ( ONETOMANY, MANYTOMANY) else "to-one" parent_name = parent_class.__name__ # referenced by f-string in the jsonapi.py method docstring child_name = child_class.__name__ # referenced by f-string apply_fstring(doc, locals()) update_response_schema(doc["responses"]) return swagger.doc(doc)(func)
def swagger_doc_gen(func): """ Decorator used to document relationship methods exposed in the API """ parent_class = cls.relationship.parent.class_ child_class = cls.relationship.mapper.class_ class_name = cls.__name__ http_method = func.__name__.lower() ####################################################################### # Following will only happen when exposing an exisiting DB # if not getattr(parent_class, "object_id", None): parent_class._s_object_id = parent_class.__name__ + "Id" if not getattr(child_class, "object_id", None): child_class._s_object_id = child_class.__name__ + "Id" if not getattr(parent_class, "sample_id", None): setattr(parent_class, "sample_id", lambda: "") if not getattr(child_class, "sample_id", None): setattr(child_class, "sample_id", lambda: "") if not getattr(child_class, "get_swagger_doc", None): setattr(child_class, "get_swagger_doc", lambda x: (None, {})) # ####################################################################### parameters = [ { "name": parent_class._s_object_id, "in": "path", "type": "string", "default": parent_class._s_sample_id(), "description": "{} item".format(parent_class.__name__), "required": True, }, { "name": child_class._s_object_id, "in": "path", "type": "string", "default": child_class._s_sample_id(), "description": "{} item".format(class_name), "required": True, }, ] if tags is None: doc_tags = [cls._s_collection_name] else: doc_tags = tags doc = {"tags": doc_tags} doc.update(parse_object_doc(func)) responses = {} if http_method == "get": _, responses = cls._s_get_swagger_doc(http_method) elif http_method in ("post", "patch"): _, responses = cls._s_get_swagger_doc(http_method) child_sample_id = child_class._s_sample_id() _, responses = child_class._s_get_swagger_doc("patch") data = {"type": child_class._s_type, "id": child_sample_id} if cls.relationship.direction in (ONETOMANY, MANYTOMANY): data = [data] rel_post_schema = schema_from_object( "{}_Relationship".format(class_name), {"data": data}) parameters.append({ "name": "{} body".format(class_name), "in": "body", "description": "{} POST model".format(class_name), "schema": rel_post_schema, "required": True, }) elif http_method == "delete": child_sample_id = child_class._s_sample_id() _, responses = child_class._s_get_swagger_doc("patch") data = {"type": child_class._s_type, "id": child_sample_id} if cls.relationship.direction in (ONETOMANY, MANYTOMANY): data = [data] rel_del_schema = schema_from_object( "{}_Relationship".format(class_name), {"data": data}) parameters.append({ "name": "{} body".format(class_name), "in": "body", "description": "{} POST model".format(class_name), "schema": rel_del_schema, "required": True, }) else: # one of 'options', 'head', 'patch' safrs.log.info('no documentation for "{}" '.format(http_method)) doc["parameters"] = parameters if doc.get("responses"): responses.update( {str(val): desc for val, desc in doc["responses"].items()}) if is_debug(): responses.update(debug_responses) doc["responses"] = responses direction = "to-many" if cls.relationship.direction in ( ONETOMANY, MANYTOMANY) else "to-one" parent_name = parent_class.__name__ # to be used by f-string child_name = child_class.__name__ # to be used by f-string apply_fstring(doc, locals()) return swagger.doc(doc)(func)