Code Monkey home page Code Monkey logo

apiflask's Introduction

APIFlask

Build status codecov

APIFlask is a lightweight Python web API framework based on Flask and marshmallow-code projects. It's easy to use, highly customizable, ORM/ODM-agnostic, and 100% compatible with the Flask ecosystem.

With APIFlask, you will have:

  • More sugars for view function (@app.input(), @app.output(), @app.get(), @app.post() and more)
  • Automatic request validation and deserialization
  • Automatic response formatting and serialization
  • Automatic OpenAPI Specification (OAS, formerly Swagger Specification) document generation
  • Automatic interactive API documentation
  • API authentication support (with Flask-HTTPAuth)
  • Automatic JSON response for HTTP errors

Requirements

  • Python 3.8+
  • Flask 2.0+

Installation

For Linux and macOS:

$ pip3 install apiflask

For Windows:

> pip install apiflask

Links

Donate

If you find APIFlask useful, please consider donating today. Your donation keeps APIFlask maintained and evolving.

Thank you to all our backers and sponsors!

Backers

Sponsors

Example

from apiflask import APIFlask, Schema, abort
from apiflask.fields import Integer, String
from apiflask.validators import Length, OneOf

app = APIFlask(__name__)

pets = [
    {'id': 0, 'name': 'Kitty', 'category': 'cat'},
    {'id': 1, 'name': 'Coco', 'category': 'dog'}
]


class PetIn(Schema):
    name = String(required=True, validate=Length(0, 10))
    category = String(required=True, validate=OneOf(['dog', 'cat']))


class PetOut(Schema):
    id = Integer()
    name = String()
    category = String()


@app.get('/')
def say_hello():
    # returning a dict or list equals to use jsonify()
    return {'message': 'Hello!'}


@app.get('/pets/<int:pet_id>')
@app.output(PetOut)
def get_pet(pet_id):
    if pet_id > len(pets) - 1:
        abort(404)
    # you can also return an ORM/ODM model class instance directly
    # APIFlask will serialize the object into JSON format
    return pets[pet_id]


@app.patch('/pets/<int:pet_id>')
@app.input(PetIn(partial=True))  # -> json_data
@app.output(PetOut)
def update_pet(pet_id, json_data):
    # the validated and parsed input data will
    # be injected into the view function as a dict
    if pet_id > len(pets) - 1:
        abort(404)
    for attr, value in json_data.items():
        pets[pet_id][attr] = value
    return pets[pet_id]
You can also use class-based views based on MethodView
from apiflask import APIFlask, Schema, abort
from apiflask.fields import Integer, String
from apiflask.validators import Length, OneOf
from flask.views import MethodView

app = APIFlask(__name__)

pets = [
    {'id': 0, 'name': 'Kitty', 'category': 'cat'},
    {'id': 1, 'name': 'Coco', 'category': 'dog'}
]


class PetIn(Schema):
    name = String(required=True, validate=Length(0, 10))
    category = String(required=True, validate=OneOf(['dog', 'cat']))


class PetOut(Schema):
    id = Integer()
    name = String()
    category = String()


class Hello(MethodView):

    # use HTTP method name as class method name
    def get(self):
        return {'message': 'Hello!'}


class Pet(MethodView):

    @app.output(PetOut)
    def get(self, pet_id):
        """Get a pet"""
        if pet_id > len(pets) - 1:
            abort(404)
        return pets[pet_id]

    @app.input(PetIn(partial=True))
    @app.output(PetOut)
    def patch(self, pet_id, json_data):
        """Update a pet"""
        if pet_id > len(pets) - 1:
            abort(404)
        for attr, value in json_data.items():
            pets[pet_id][attr] = value
        return pets[pet_id]


app.add_url_rule('/', view_func=Hello.as_view('hello'))
app.add_url_rule('/pets/<int:pet_id>', view_func=Pet.as_view('pet'))
Or use async def
$ pip install -U "apiflask[async]"
import asyncio

from apiflask import APIFlask

app = APIFlask(__name__)


@app.get('/')
async def say_hello():
    await asyncio.sleep(1)
    return {'message': 'Hello!'}

See Using async and await for the details of the async support in Flask 2.0.

Save this as app.py, then run it with:

$ flask run --reload

Or run in debug mode:

$ flask run --debug

Now visit the interactive API documentation (Swagger UI) at http://localhost:5000/docs:

Or you can change the API documentation UI when creating the APIFlask instance with the docs_ui parameter:

app = APIFlask(__name__, docs_ui='redoc')

Now http://localhost:5000/docs will render the API documentation with Redoc.

Supported docs_ui values (UI libraries) include:

The auto-generated OpenAPI spec file is available at http://localhost:5000/openapi.json. You can also get the spec with the flask spec command:

$ flask spec

For some complete examples, see /examples.

Relationship with Flask

APIFlask is a thin wrapper on top of Flask. You only need to remember the following differences (see Migrating from Flask for more details):

  • When creating an application instance, use APIFlask instead of Flask.
  • When creating a blueprint instance, use APIBlueprint instead of Blueprint.
  • The abort() function from APIFlask (apiflask.abort) returns JSON error response.

For a minimal Flask application:

from flask import Flask, request
from markupsafe import escape

app = Flask(__name__)

@app.route('/')
def hello():
    name = request.args.get('name', 'Human')
    return f'Hello, {escape(name)}'

Now change to APIFlask:

from apiflask import APIFlask  # step one
from flask import request
from markupsafe import escape

app = APIFlask(__name__)  # step two

@app.route('/')
def hello():
    name = request.args.get('name', 'Human')
    return f'Hello, {escape(name)}'

In a word, to make Web API development in Flask more easily, APIFlask provides APIFlask and APIBlueprint to extend Flask's Flask and Blueprint objects and it also ships with some helpful utilities. Other than that, you are actually using Flask.

Relationship with marshmallow

APIFlask accepts marshmallow schema as data schema, uses webargs to validate the request data against the schema, and uses apispec to generate the OpenAPI representation from the schema.

You can build marshmallow schemas just like before, but APIFlask also exposes some marshmallow APIs for convenience:

  • apiflask.Schema: The base marshmallow schema class.
  • apiflask.fields: The marshmallow fields, contain the fields from both marshmallow and Flask-Marshmallow. Beware that the aliases (Url, Str, Int, Bool, etc.) were removed.
  • apiflask.validators: The marshmallow validators.
from apiflask import Schema
from apiflask.fields import Integer, String
from apiflask.validators import Length, OneOf
from marshmallow import pre_load, post_dump, ValidationError

Credits

APIFlask starts as a fork of APIFairy and is inspired by flask-smorest and FastAPI (see Comparison and Motivations for the comparison between these projects).

apiflask's People

Contributors

180909 avatar andyzhouty avatar dependabot[bot] avatar greyli avatar henshalb avatar hjlarry avatar imoyao avatar jiashuchen avatar johntheprime avatar jugmac00 avatar justin-jiajia avatar llt22 avatar miguelgrinberg avatar mmdbalkhi avatar ndawn avatar nekoyue avatar pamelafox avatar pre-commit-ci[bot] avatar ricardogsilva avatar rod7760 avatar sloria avatar sylvain-ri avatar tkzt avatar tridagger avatar tsokalski avatar uncle-lv avatar wlach avatar yuancjun avatar yuxiaoy1 avatar zhoukuncheng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apiflask's Issues

Is it possible to display a documentation for an APIBlueprint?

I'm currently using APIFlask to develop the 3rd version of flog web api and the API is in an APIBlueprint. And I open /api/v3/redoc in my browser but it returns a 404 response.

What I have done:

  1. An APIBlueprint instance with the /api/v3 url prefix
  2. A schema

What's expected:
When I get to /api/v3/redoc, it should display my documentation for the web api.

Support to add custom error classes based on `HTTPError`

Refactor the HTTPError class to support adding custom error classes, for example:

from apiflask import HTTPError

class NotAuthor(HTTPError):
    status_code = 400
    message = 'Only the author can perform this action!'
    extra_data = {
        'error_code': 1234,
        'docs': 'http://example.com'
    }

Raise the error in the view:

@app.get('/')
def hello():
    if not author:
        raise NotAuthor
    return 'Hello!'

RFC: Import fields from Marshmallow selectively and remove some aliases

Marshmallow provides some aliases for one field, for example, Str and String. To keep everything simple and consistent, I imported the fields selectively in apiflask.fields, so the IDE will not prompt Url and URL when you type "U". The following aliases were removed:

  • Str
  • Int
  • Bool
  • Url
  • UrlFor
  • AbsoluteUrlFor

Instead, you will need to use:

  • String
  • Integer
  • Boolean
  • URL
  • URLFor
  • AbsoluteURLFor

Users can still import all the fields from Marshmallow, I will address this change in the docs.

Is it a good or bad idea? Feel free to leave any thoughts.

Documentation progress

  • Introduction
  • Documentation Index
  • Migrating from Flask
  • Basic Usage
  • OpenAPI Generating
  • Swagger UI and Redoc
  • Configuration
  • Error Handling
  • Request Validating
  • Response Formatting
  • Schema, Fields and Validators
  • Authentication
  • Examples
  • API Reference
  • Comparison and Motivations
  • Authors
  • Contributing Guide

Mark `app.get_spec()` method as private and add a `force_update` parameter

Since the generated spec is cached on the app._spec attribute, If the user access this method and attribute just after creating the app instance, when the routes are not registered yet, the subsequent requests to the spec will get the empty spec that has been cached on the first access.

from apiflask import APIFlask

app = APIFlask(__name__)
app.spec  # the spec will be cached at this stage

A solution would be to add a force_update parameter for the get_spec method, then clear the cached spec in app.spec:

    @property
    def spec(self) -> t.Union[dict, str]:
        return self._get_spec(force_update=True)

Then the app.spec is for users, it always returns the latest spec (need to update the openapi docs to mention this attribute); The method app.get_spec() meant to be used internally, it returns the cached spec as default, so we can rename it to app._get_spec().

Consider moving APIFlask back to an extension

See this discussion where Grey says:

Glad to see this finally merged! After I proposed this idea and was declined in the first pallets meeting, I started to make the REST API extension I'm developing to become a framework so that I can inherit the Flask class and add these route shortcuts, now I may consider making it back to an extension...

Motivation

So that we can healthily mix different extensions and not make APIFlask our main point of entry.

Consider removing the `status_code` field in the default error response

In the automatic error response, there are three fields currently:

  • detail: It will be filled when a validation error happened.
  • message: The HTTP reason phrase.
  • status_code: The HTTP status code.

The status_code seems unnecessary since the HTTP header already contains the status info, and some users may want it in the camel case (it can be achieved with the custom error processor though), so maybe we should just remove it. Users who need it can easily add it back via the custom error processor:

@app.error_processor
def handle_error(error):
    return {
        ...
        'status_code': error.status_code
    }

Suggestions and feedback

Hi everyone! So happy to finally public this project on the first day of April. I hope this project will make the web API development with Flask a lot easier.

Welcome to leave any ideas or suggestions for this project. I will try to make a beta release as soon as possible.

You can propose any API changes or default value changes. For example:

  • Change the default validation status code from 400 to 422.
  • Rename the exception HTTPError to HTTPException.
  • A better color for the logo or a better slogan.

If needed, feel free to create a new issue (for bug/feature/advice/change/improvement) or new discussion (for question/discussion/random thoughts).

Thank you! :)

RFC: Import and rename decorators from Marshmallow

I have some doubt about these changes, so I keep it as a undocumentated features so far. Basically, I change the name of the following decorators from Marshamallow:

  • validates -> validate
  • validates_schema -> validate_schema
  • pre_load -> before_load
  • post_load -> after_load
  • pre_dump -> before_dump
  • post_dump -> after_dump

Some ideas behind these changes:

  • validate and validate_schema are short and clear than validates and validates_schema. It also matches the validate keyword in field classes.
  • The change from pre_ to before_ and from post_ to after_ was trying to follow the name convention in Flask (before_request, etc.).

IMO, the new names are easier to understand and intuitive. However, this will definitely introduce "breaking" changes between APIFlask and Marshmallow. I can add a warning in the docs to inform users that they can continue to import everything from marshmallow, but notice the name changes if they want to import from APIFlask.

Is it a good or bad idea? Feel free to leave any thoughts.

Support passing extra fields in error response

The default error response contains three fields: detail, message, and status_code. The user can add more fields or remove existing ones by register a custom error processor with @app.error_processor. However, the abort and HTTPError only accept fixed arguments for the existing three fields.

We could collect additional keyword arguments in abort and HTTPError, store them as HTTPError.addtional_fields, and return them in error response when present.

Final implementation: Added a new keyword argument extra_data to collect the additional error information. See the linked PR for more details.

@app.get('/')
def missing():
    abort(404, message='nothing', extra_data={'code': '123', 'status': 'not_found'})

Improve the class-based view support

Currently, the class-based view support is in a different way from Flask. In Flask, you can register the view classes with the app.add_url_route method, so that you can register all the rules in a central place for maintenance. However, in APIFlask, it forces you to use the app.route decorator on view classes. To improve this, we could:

  • Add a separate decorator for route classes, for example, @cbv, to collect the information for OpenAPI generating.
  • Or add a new method to wrap the add_url_rule for route classes, so it can collect the info then register the rule, for example, app.add_resource().

Final implementation: Overwrite the add_url_rule method and collect the spec information before trigger the actual add_url_rule method. See the linked PR for more details.

validate different location at once

add support for validate different location at once
code example 1:

@app.get('/pets/<int:pet_id>')
@input(PetInSchema, location='json')
@input(PaginationSchema, location='query')
@output(PetOutSchema)
def get_pet(pet_id, data):
    if pet_id > len(pets) - 1:
        abort(404)
    # you can also return an ORM/ODM model class instance directly
    # APIFlask will serialize the object into JSON format
    return pets[pet_id]

or code example 2:

@app.get('/pets/<int:pet_id>')
@input({
    'json': PetInSchema,
    'query': PaginationSchema
})
@output(PetOutSchema)
def get_pet(pet_id, data):
    if pet_id > len(pets) - 1:
        abort(404)
    # you can also return an ORM/ODM model class instance directly
    # APIFlask will serialize the object into JSON format
    return pets[pet_id]

BASE_RESPONSE_SCHEMA not use in APIBlueprint

the BASE_RESPONSE_SCHEMA not use in APIBlueprint

class BaseResponseSchema(Schema):
    message = String()
    status_code = Integer()
    data = Field()  # the data key

app.config['BASE_RESPONSE_SCHEMA'] = BaseResponseSchema
app.config['BASE_RESPONSE_DATA_KEY '] = 'data'

just return the data, like this

{
    "data": {
        "category": "dog",
        "id": 3,
        "name": "admin13"
    }
}

I can’t determine whether it’s a bug or a problem with my settings

Support the Spec/API/Design-first approach

This project currently only supports the Code-first approach, in other words, it generates the OpenAPI spec from your code and keeps the spec in sync with your code afterward. While the Spec-first approach allows you to write the spec first, when every detail of the API is discussed and confirmed, you start to code based on the spec. Both approaches have their own pros and cons. Although Code-first seems quite convenient and popular, I still hope to support the Spec-first approach for APIFlask, and it's the recommended approach by the OpenAPI initiative.

Ideas

A good starting point is to support for a Semi-Spec-first approach:

  • Provide a codegen tool, generates the skeleton code (routes, schemas, models, etc.) from an existing spec.
  • After the generation, turns to the Code-first approach. In this way, the spec can easily keep sync with the code.

After this, we can start to think of supporting the real Spec-first workflow. TBH, I don't quite familiar with the Spec-first approach, especially:

  • How to keep the code and spec in sync? If a user uses the codegen tool, after the code is generated, if we change a field name in the spec, then we have to update the code manually?
  • If the validation is based on the spec and JSON schema, how to add pre/post procession hooks for the input/output data?
  • What's the ideal workflow?
  • What and how much the framework should get involved?

Before these happen, maybe we can recommend the user to use Connexion in the docs since it's now back to the maintenance status (spec-first/connexion#1365).

Resources

See a relevant discussion here.

Learning resources checklist:

Support to customize base response schema

Currently, the response is handled by APIFlask. Althought you can return whatever you want, but you have to return the data match the schema passed in the output decorator to generate the OpenAPI spec correctly. While some user may want to return other information more than just the data:

{
    "data": {},
    "message": "some message",
    "code": "custom code"
}

Or you want to return the same schema for both success response and validation error response:

{
    "data": {},
    "detail": "some detailed info",
    "status_code": "200",
    "message": "some message"
}

Initial plan:

  • Add a config BASE_RESPONSE_SCHEMA = None, accepts the base schema class.
  • Add a config BASE_RESPONSE_DATA_KEY = 'data', accepts a string to indicate the key to get/put the data.
  • On the response handling part, we need to get the data from given key, searilize the data against the input schema, searilize other fields against the base schema.
  • On the OpenAPI handling part, we need to create a spec for the base schema, then insert the data schema into specific key.

Example usage (of imagine):

from apiflask import APIFlask, Schema, input, output
from apiflask.fields import String, Integer, Field

from app.models import Pet


app = APIFlask(__name__)


class BaseResponseSchema(Schema):
    data = Field()
    message = String()
    code = Integer()


class PetOutSchema(Schema):
    ...


app.config['BASE_RESPONSE_SCHEMA'] = BaseResponseSchema


@app.get('/pets/<int:pet_id>')
@output(PetOutSchema)
def get_pet(pet_id):
    pet = Pet.query.get(pet_id)
    return {
        'data': pet,
        'message': 'Get pet successfully.'
        'code': '1000'
    }

Questions:

  • What's the correct Marshmallow field for the data field that accepts both a dict or an object? (fields.Field?)
  • How to generate the OpenAPI spec of a Marshmallow schema and get the result in dict?

Improve the error handling docs

  • Add a custom error class section.
  • Add a validation error section.
  • Merge redundant contents about error response body fields.
  • Clarify the differences between HTTPError and HTTPException, apiflask.abort and flask.abort.
  • Add a section about tips for different app error handling situations.

Also, add an example for the error handling feature.

Incorrect description for data_key in the docs

Discussed in #147

Originally posted by Farmer-chong October 1, 2021
issue

It seems that data_key argument is the output parameter?


Yes, this section should be rewritten, the data_key is the name of the external field (which we load from and dump to).

Improve error handling

  • Pass an HTTPError object instead of separate information to the error processor function.
@app.error_processor
def my_error_processor(error):
    return {
        'status_code': error.status_code,
        'message': error.message,
        'errors': error.detail
    }, error.status_code, error.headers
  • Call the error processor function for authentication errors.
  • Add an error_processor decorator for auth classes.

Remove the auto-detection support of spec format and always use config `SPEC_FORMAT`

The SPEC_FORMAT config was re-added via #66. To keep the inconsistency, the spec route should also use the value of SPEC_FORMAT.

Currently, the format will be decided based on the spec path. For example, if the spec path is foo.json, then the JSON format will be used, while the YAML will be used if the spec path is foo.yaml. This behavior will be removed in 0.7.0, now the format should be set explicitly with the SPEC_FORMAT` config.

when raise a subclass of HTTPError, message field will be a list

when raise a subclass of HTTPError, the message field will be a list, it's different with when you raise a HTTPError directly

this is a demo

I'm not sure it's a bug or feature, but I think it should be consistent
except

{
  "detail": {
    
  },
  "message": "This pet is missing."
}

current

{
  "detail": {
    
  },
  "message": [
    "This pet is missing."
  ]
}

Environment:

  • Python version: 3.9
  • Flask version: 2.0.2
  • APIFlask version: 0.11.0

继承Schema的模板中想排除一些字段,例如:page,pageLimit,发现不支持,是我代码写的有问题么?

from TestFlask.application import db
from TestFlask.module.UserModule import User
from apiflask import Schema
from apiflask.fields import Integer, String

class UserReq(Schema):
id = Integer(required=True, description="ID"), # ID
login_name = Integer(required=True, description="登录名"), # 登录名
real_name = String(required=True, description="所属项目") # 姓名
branch = String(required=True, description="所属模块") # 部门
phone = String(required=True) # 手机号
password = String(required=True) # 密码
page = Integer(required=True, description="page"), # page
pageLimit = Integer(required=True, description="page"), # pageLimit

class Meta:
    model = User
    exclude = ["page", "pageLimit"]  # 排除字段列表

if name == 'main':
userReq = UserReq()
print(userReq)

-------------------------->
ValueError: Invalid fields for <UserReq(many=False)>: {'pageLimit', 'page'}.

VersionConflict: (apispec 4.2.0 (c:\python\python38-64\lib\site-packages), Requirement.parse('apispec[yaml]<4,>=3.3'))

C:\Users\chao\Documents\PROJECTS\python>flask run --reload
Traceback (most recent call last):
File "c:\python\python38-64\lib\runpy.py", line 194, in _run_module_as_main
return run_code(code, main_globals, None,
File "c:\python\python38-64\lib\runpy.py", line 87, in run_code
exec(code, run_globals)
File "C:\Python\Python38-64\Scripts\flask.exe_main
.py", line 7, in
File "c:\python\python38-64\lib\site-packages\flask\cli.py", line 990, in main
cli.main(args=sys.argv[1:])
File "c:\python\python38-64\lib\site-packages\flask\cli.py", line 596, in main
return super().main(*args, **kwargs)
File "c:\python\python38-64\lib\site-packages\click\core.py", line 782, in main
rv = self.invoke(ctx)
File "c:\python\python38-64\lib\site-packages\click\core.py", line 1254, in invoke
cmd_name, cmd, args = self.resolve_command(ctx, args)
File "c:\python\python38-64\lib\site-packages\click\core.py", line 1297, in resolve_command
cmd = self.get_command(ctx, cmd_name)
File "c:\python\python38-64\lib\site-packages\flask\cli.py", line 539, in get_command
self.load_plugin_commands()
File "c:\python\python38-64\lib\site-packages\flask\cli.py", line 535, in load_plugin_commands
self.add_command(ep.load(), ep.name)
File "c:\python\python38-64\lib\site-packages\pkg_resources_init
.py", line 2460, in load
self.require(*args, **kwargs)
File "c:\python\python38-64\lib\site-packages\pkg_resources_init
.py", line 2483, in require
items = working_set.resolve(reqs, env, installer, extras=self.extras)
File "c:\python\python38-64\lib\site-packages\pkg_resources_init.py", line 790, in resolve
raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.VersionConflict: (apispec 4.2.0 (c:\python\python38-64\lib\site-packages), Requirement.parse('apispec[yaml]<4,>=3.3'))

能提供一下requeirments.txt吗,我在3.8上测试不过,包冲突,重新安装apispec,你的程序报得大于4.2.0

Can't get static files work in version 0.6.1

Can't get static files work in version 0.6.1

Example:

from apiflask import APIFlask
app = APIFlask(__name__)

@app.route("/")
def index():
    return ""
h1 { font-size: 16px; }

File Tree:

/app-root
  app.py
  /static
    style.css

And I GET /static/style.css in the browser, I expected to see:

h1 { font-size: 16px; }

But I got

500 Internal Server Error

What I have tried

  1. Change APIFlask to Flask, it works well.
  2. Change to any older version of APIFlask, it doesn't work.

Environment:

  • Python version: 3.8.5
  • Flask version: 2.0.0
  • APIFlask version: 0.6.1

Version 0.7.0 plan

  • Parameter example support
  • Support to customize base response schema
  • Add a flask spec command to generate spec to a local file (also support syncing the file automatically)

Can't upload file in Swagger UI

在apiflask内置的api文档中进行调试时,无法上传文件

demo

from apiflask import APIFlask, input, output, abort
from marshmallow.fields import Raw
app = APIFlask(__name__)

@app.post("/icon")
@input({"icon": Raw(type="file", required=True)}, location="files")
def icon(data):
    print(data.get("icon"))
    return {"ok": 'ok'}

在docs页面有正常的选择文件按钮,但观察curl结果发现并没有将选择的文件上传至后端(network中也并没有),但当我使用Postamn等工具进行请求时,后端是正常(结果正常),因此我只能暂时将问题归结于apispec的bug

Environment:

  • Python version: 3.7.3
  • Flask version: 2.0.1
  • APIFlask version: 0.8.0

Keep the local spec in sync automatically

The flask spec generates local spec. While it will be very useful if we can update the local spec automatically when the spec changes.

We already have a LOCAL_SPEC_PATH config to get the path. Now we need to add a new config as the sync switch:

SYNC_LOCAL_SPEC: t.Optional[bool] = None

Problems:

  • How to make sure the path is relative to the user's project root, and consistent with flask spec --output ....

Add a `flask spec` command to generate spec to a local file

Also support syncing the file automatically.

Output to stdout (if config LOCAL_SPEC_PATH is None):

$ flask spec

Output to a file (default to using config LOCAL_SPEC_PATH):

$ flask spec -o openapi.json

Other names for the option:

  • -o/--output
  • -o/--output-path
  • -p/--path
  • -f/--file

Other names for LOCAL_SPEC_PATH:

  • LOCAL_SPEC
  • LOCAL_SPEC_FILE

Response links support

It can be set with a links parameter in the output decorator:

@output(FooSchema, links=...)

A full example:

@app.post('/pets')
@input(PetInSchema)
@output(
    PetOutSchema,
    201,
    description='The pet you just created',
    links={'getPetById': {
        'operationId': 'getPet',
        'parameters': {
            'pet_id': '$response.body#/id'
        }
    }}
)
@doc(tag='Pet')
def create_pet(data):
    ...

@app.get('/pets/<int:pet_id>')
@output(PetOutSchema, description='The pet with given ID')
@doc(tag='Pet', operation_id='getPet')
def get_pet(pet_id):
    ...

Support setting custom schema name resolver

Add a schema_name_resolver attribute so that user can provide their own resolver. The default schema name resolver is:

def _schema_name_resolver(schema: t.Type[Schema]) -> str:
    """Default schema name resovler."""
    name = schema.__class__.__name__
    if name.endswith('Schema'):
        name = name[:-6] or name
    if schema.partial:
        name += 'Update'
    return name

Automatic OpenAPI 404 response

The idea is, if an endpoint's URL rule contains a variable, then add a 404 response for it:

@app.get('/pets/<id>')
def get_pet(id):
    pass

So user don't need to set a 404 response manually:

@app.get('/pets/<id>')
@doc(responses=[404])
def get_pet(id):
    pass

Also, add a config to control this behavior:

AUTO_404_RESPONSE: bool = True

Add support for Pydantic

Can you join the support of pydantic, so that users can choose more than one, so that people who like different styles can choose freely according to their hobbies, thank you

Add INFO configuration variable

The INFO key accepts a dict that contains the four OpenAPI info fields:

app.info = {
    'description': '...',
    'termsOfService': 'http://example.com',
    'contact': {
        'name': 'API Support',
        'url': 'http://www.example.com/support',
        'email': '[email protected]'
    },
    'license': {
        'name': 'Apache 2.0',
        'url': 'http://www.apache.org/licenses/LICENSE-2.0.html'
    }
}

The dict can be overwritten by other separate config keys.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.