# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['apiman']

package_data = \
{'': ['*'], 'apiman': ['static/*']}

install_requires = \
['Jinja2>=3.0.2,<4.0.0', 'PyYAML>=6.0,<7.0', 'jsonschema-rs>=0.13.0,<0.14.0']

setup_kwargs = {
    'name': 'apiman',
    'version': '0.4.0',
    'description': 'Integrate api manual for your web project',
    'long_description': '# APIMAN\n\n[![Build](https://github.com/strongbugman/apiman/workflows/test/badge.svg)](https://github.com/strongbugman/apiman/actions)\n[![codecov](https://codecov.io/gh/strongbugman/apiman/branch/master/graph/badge.svg)](https://codecov.io/gh/strongbugman/apiman)\n\nAPIMAN provide a easy way to integrate api manual/document for your web project\n\n## Features\n\n* Out of the box for Flask and Starlette and Django\n* Whole OpenAPI 2 and 3 specification support\n* Configurable [SwaggerUI](http://swagger.io/swagger-ui/) and [RedocUI](https://rebilly.github.io/ReDoc/)\n* Request(json body、query、header...) validation by API specification\n\n## Install\n\n```shell\npip install -U apiman\n```\n\n## Usage\n\n### create openapi basic file\n\n```yml\nopenapi: "3.0.0"\ninfo:\n  title: \'APIMAN\'\n  version: \'0.1\'\n  description: \'API manual for example\'\n```\n\n### create apiman instance\n\n```python\nfrom starlette.applications import Starlette\nfrom apiman.starlette import Extension \n# from flask import Flask\n# from apiman.flask import Extension\n\napiman = Extension(template="./docs/openapi.yml")\n```\n\n### register apiman\n\n```python\n# app = Flask(__name__)\napp = Starlette()\nopenapi.init_app(app)\n```\n\n### add document for api endpoint\n\nby docstring:\n\n```python\n@app.route("/hello/", methods=["GET"])\nasync def hello(req: Request):\n    """\n    There is normal docstring, Below is OpenAPI specification\n    ---\n    summary: hello api\n    tags:\n    - test\n    parameters:\n    - name: name\n      in: query\n      required: True\n      schema:\n        type: string\n    responses:\n      "200":\n        description: OK\n    """\n    return Response(f"hello")\n```\n\nby yaml content:\n\n```python\n@app.route("/hello/", methods=["GET"])\n@openapi.from_yaml(\n    """\n    summary: hello api\n    tags:\n    - test\n    parameters:\n    - name: name\n      in: query\n      required: True\n      schema:\n        type: string\n    responses:\n      "200":\n        description: OK\n    """\n)\nasync def hello(req: Request):\n    return Response(f"hello")\n```\n\n(why yaml content? for my usage, just for f-string support)\n\nby file:\n\n```python\n@app.route("/hello/", methods=["GET"])\n@openapi.from_file("./docs/hello.yml")\nasync def hello(req: Request):\n    return Response(f"hello")\n\n@app.route("/hello/", methods=["GET"])\n@openapi.from_file("./docs/hello.json")\nasync def hello(req: Request):\n    return Response(f"hello")\n```\n\n\n### run app and browse swagger ui at `server:port/apiman/swagger` or `server:port/apiman/redoc`\n\n## More Usage\n\n### Config apiman\n\nConfig apiman\'s ui url, title and ui html template\n\n```python\napiman = Extension(\n  title="OpenAPI document",\n  specification_url="/apiman/specification/",\n  swagger_url="/apiman/swagger/",\n  redoc_url="/apiman/redoc/",\n  swagger_template="swagger.html",\n  redoc_template="redoc.html",\n  template="template.yaml",\n)\n```\n### reuseable schema\n\nWe can define some OpenAPI schema or parameters for config usage, in openapi.yml:\n\n```yml\nopenapi: "3.0.0"\ninfo:\n  title: \'APIMAN\'\n  version: \'0.1\'\n  description: \'API manual for example\'\ndefinitions:\n  Cat:\n    type: object\n    required:\n    - name\n    properties:\n      name:\n        type: string\n      age:\n        type: integer\n        format: int32\n        minimum: 0\n```\n\nor by code:\n\n```python\nopenapi.add_schema(\n    "Cat",\n    {\n        "properties": {\n            "name": {"type": "string"},\n            "age": {"type": "integer", "minimum": 0},\n        },\n        "type": "object",\n    },\n)\n```\n\n(All specification data store in `apiman.specification`), then use it by OpenAPI way:\n\n```python\n@openapi.from_yaml(\n    """\n    responses:\n      "200":\n        description: OK\n        schema:\n          $ref: \'#definitions/Cat\'\n    """\n)\n```\n\n### request validation\n\nvalide request by `validate_request`\n\n```python\n@app.route("/hello/", methods=["POST"])\n@openapi.from_yaml(\n    """\n    summary: hello api\n    tags:\n    - test\n    parameters:\n    - name: name\n      in: query\n      required: True\n      schema:\n        type: string\n    - name: x-custom-param\n      schema:\n        type: string\n      in: header\n      required: True\n    - name: cookie_param\n      schema:\n        type: string\n      in: cookie\n    requesteBody:\n      required: true\n      content:\n        application/json:\n          schema:\n            type: object\n            properties:\n              key:\n                type: integer\n            required: ["key"]\n    responses:\n      "200":\n        description: OK\n    """\n)\nasync def get(self, req: Request):\n    await req.json()\n    openapi.validate_request(req)\n    # get validated params\n    request.query_params\n    request.cookies\n    request.headers\n    request.json()\n    ...\n```\n\n(for starlette, call `await req.json()` first to load json data)\n\nThis method will find this request\'s OpenAPI specification and request params(query, path, cookie, header, json body) then validate it, we can get validate req params by origin way or raise Exceptoin(by [jsonschema_rs](https://github.com/Stranger6667/jsonschema-rs/tree/master/bindings/python))\n\n\n### limit\n\n#### type limit\n\nAll request params type is **origin type**, so query/header/cookie params is always **string**, we should define this params type to string or we will get Exception(flask\'s path params can be int original).\n\nBut if we want some integer param for string type you can set regex `pattern` in specification, eg:\n\n```yml\nid:\n  type: string\n  pattern: \'^\\d+$\'\n```\n\nor just use json body for rich format\n\n## Examples\n\nLet\'s see a Starlette example app:\n\n```python\n"""OpenAPI2(Swagger) with Starlette\n"""\nfrom starlette.applications import Starlette\nfrom starlette.requests import Request\nfrom starlette.responses import JSONResponse\nfrom starlette.endpoints import HTTPEndpoint\nfrom uvicorn import run\nfrom openapi_spec_validator import validate_v2_spec\nfrom starlette.testclient import TestClient\n\nfrom apiman.starlette import Extension\n\n\napp = Starlette()\nopenapi = Extension(template="./examples/docs/cat_template.yml")\nopenapi.init_app(app)\n\n\n# define data\nCATS = {\n    1: {"id": 1, "name": "DangDang", "age": 2},\n    2: {"id": 2, "name": "DingDing", "age": 1},\n}\n# add schema definition\nopenapi.add_schema(\n    "Cat",\n    {\n        "properties": {\n            "id": {"description": "global unique", "type": "integer"},\n            "name": {"type": "string"},\n            "age": {"type": "integer"},\n        },\n        "type": "object",\n    },\n)\n\n\n# define routes and schema(in doc string)\n@app.route("/cat/")\nclass Cat(HTTPEndpoint):\n    """\n    Declare multi method\n    ---\n    get:\n      summary: Get single cat\n      tags:\n      - cat\n      parameters:\n      - name: id\n        type: string\n        in: path\n        required: True\n      - name: x-client-version\n        type: string\n        in: header\n        required: True\n      responses:\n        "200":\n          description: OK\n          schema:\n            $ref: \'#/definitions/Cat\'\n        "404":\n          description: Not found\n    """\n\n    def get(self, req: Request):\n        # validate params in path query header and cookie by schema (only support string type)\n        openapi.validate_request(req)\n        return JSONResponse(CATS[int(req.path_params["id"])])\n\n    def delete(self, req: Request):\n        """\n        Declare single method\n        ---\n        summary: Delete single cat\n        tags:\n        - cat\n        parameters:\n        - name: id\n          type: integer\n          in: path\n          required: True\n        responses:\n          "204":\n            description: OK\n            schema:\n              $ref: \'#/definitions/Cat\'\n          "404":\n            description: Not found\n        """\n        cat = CATS.pop(int(req.path_params["id"]))\n        return JSONResponse(cat)\n\n\n# define doc by yaml or json file\n@app.route("/cats/", methods=["GET"])\n@openapi.from_file("./examples/docs/cats_get.yml")\ndef list_cats(req: Request):\n    return JSONResponse(list(CATS.values()))\n\n\n@app.route("/cats/", methods=["POST"])\n@openapi.from_file("./examples/docs/cats_post.json")\nasync def list_cats(req: Request):\n    await req.json()\n    # validate json body\n    openapi.validate_request(req)\n    cat = await req.json()\n    CATS[cat["id"]] = cat\n    return JSONResponse(cat)\n\n\nif __name__ == "__main__":\n    run(app)\n```\n\nThen we get swagger web page at [http://localhost:8000/apiman/swagger/](http://localhost:8000/apiman/swagger/):\n![WebPage](docs/SwaggerUI.jpg)\n\nSee **examples/** for more examples\n\n## How it works\n\n* Provide a base class("OpenApi") to handle api specification\'s collection\n* Provide extensions to extract api specification and register http endpoints to show UI web page and specification ',
    'author': 'strongbugman',
    'author_email': 'strongbugman@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/strongbugman/apiman',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.6.2,<4.0.0',
}


setup(**setup_kwargs)
