Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
0
    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)
Exemple #4
0
    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)