Package: iknl-flasgger
FlasggerEasy Swagger UI for your Flask APIFlasgger is a Flask extension toextractOpenAPI=Specificationfrom all Flask views registered in your API.Flasgger also comes withSwaggerUIembeddedso you can accesshttp://localhost:5000/apidocsand visualize and interact with your API resources.Flasgger alsoprovides validationof the incoming data, using the same specification it can validates if the data received as as a POST, PUT, PATCH is valid against the schema defined usingYAML,Python dictionariesorMarshmallow Schemas.Flasgger can work with simple function views or MethodViews using docstring as specification, or using@swag_fromdecorator to get specification fromYAMLordictand also providesSwaggerViewwhich can useMarshmallow Schemasas specification.Flasgger is compatible withFlask-RESTfulso you can useResourcesandswagspecifications together, take a look atrestful example.Flasgger also supportsMarshmallow APISpecas base template for specification, if you are using APISPec from Marshmallow take a look atapispec example.Examples and demo appThere are someexample applicationsand you can also play with examples inFlasgger demo appNOTE: all the examples apps are also test cases and run automatically in Travis CI to ensure quality and coverage.DockerThe examples and demo app can also be built and run as a Docker image/container:docker build -t flasgger .
docker run -it --rm -p 5000:5000 --name flasgger flasggerThen access the Flasgger demo app athttp://localhost:5000.Installationunder your virtualenv do:Ensure you have latest setuptoolspip install -U setuptoolsthenpip install flasggeror (dev version)pip install https://github.com/rochacbruno/flasgger/tarball/masterNOTE: If you want to useMarshmallow Schemasyou also need to runpip install marshmallow apispecGetting startedUsing docstrings as specificationCreate a file called for examplecolors.pyfromflaskimportFlask,jsonifyfromflasggerimportSwaggerapp=Flask(__name__)swagger=Swagger(app)@app.route('/colors/<palette>/')defcolors(palette):"""Example endpoint returning a list of colors by paletteThis is using docstrings for specifications.---parameters:- name: palettein: pathtype: stringenum: ['all', 'rgb', 'cmyk']required: truedefault: alldefinitions:Palette:type: objectproperties:palette_name:type: arrayitems:$ref: '#/definitions/Color'Color:type: stringresponses:200:description: A list of colors (may be filtered by palette)schema:$ref: '#/definitions/Palette'examples:rgb: ['red', 'green', 'blue']"""all_colors={'cmyk':['cian','magenta','yellow','black'],'rgb':['red','green','blue']}ifpalette=='all':result=all_colorselse:result={palette:all_colors.get(palette)}returnjsonify(result)app.run(debug=True)Now run:python colors.pyAnd go to:http://localhost:5000/apidocs/You should get:Using external YAML filesSave a new filecolors.ymlExample endpoint returning a list of colors by paletteIn this example the specification is taken from external YAML file---parameters:-name:palettein:pathtype:stringenum:['all','rgb','cmyk']required:truedefault:alldefinitions:Palette:type:objectproperties:palette_name:type:arrayitems:$ref:'#/definitions/Color'Color:type:stringresponses:200:description:A list of colors (may be filtered by palette)schema:$ref:'#/definitions/Palette'examples:rgb:['red','green','blue']lets use the same example changing only the view function.fromflasggerimportswag_from@app.route('/colors/<palette>/')@swag_from('colors.yml')defcolors(palette):...If you do not want to use the decorator you can use the docstringfile:shortcut.@app.route('/colors/<palette>/')defcolors(palette):"""file: colors.yml"""...Using dictionaries as raw specsCreate a Python dictionary as:specs_dict={"parameters":[{"name":"palette","in":"path","type":"string","enum":["all","rgb","cmyk"],"required":"true","default":"all"}],"definitions":{"Palette":{"type":"object","properties":{"palette_name":{"type":"array","items":{"$ref":"#/definitions/Color"}}}},"Color":{"type":"string"}},"responses":{"200":{"description":"A list of colors (may be filtered by palette)","schema":{"$ref":"#/definitions/Palette"},"examples":{"rgb":["red","green","blue"]}}}}Now take the same function and use the dict in the place of YAML file.@app.route('/colors/<palette>/')@swag_from(specs_dict)defcolors(palette):"""Example endpoint returning a list of colors by paletteIn this example the specification is taken from specs_dict"""...Using Marshmallow SchemasFIRST:pip install marshmallow apispecfromflaskimportFlask,jsonifyfromflasggerimportSwagger,SwaggerView,Schema,fieldsclassColor(Schema):name=fields.Str()classPalette(Schema):pallete_name=fields.Str()colors=fields.Nested(Color,many=True)classPaletteView(SwaggerView):parameters=[{"name":"palette","in":"path","type":"string","enum":["all","rgb","cmyk"],"required":True,"default":"all"}]responses={200:{"description":"A list of colors (may be filtered by palette)","schema":Palette}}defget(self,palette):"""Colors API using schemaThis example is using marshmallow schemas"""all_colors={'cmyk':['cian','magenta','yellow','black'],'rgb':['red','green','blue']}ifpalette=='all':result=all_colorselse:result={palette:all_colors.get(palette)}returnjsonify(result)app=Flask(__name__)swagger=Swagger(app)app.add_url_rule('/colors/<palette>',view_func=PaletteView.as_view('colors'),methods=['GET'])app.run(debug=True)NOTE: take a look atexamples/validation.pyfor a more complete example.NOTE: when catching arguments in path rule always use explicit types, bad:/api/<username>good:/api/<string:username>UsingFlask RESTfulResourcesFlasgger is compatible with Flask-RESTful you only need to installpip install flask-restfuland then:fromflaskimportFlaskfromflasggerimportSwaggerfromflask_restfulimportApi,Resourceapp=Flask(__name__)api=Api(app)swagger=Swagger(app)classUsername(Resource):defget(self,username):"""This examples uses FlaskRESTful ResourceIt works also with swag_from, schemas and spec_dict---parameters:- in: pathname: usernametype: stringrequired: trueresponses:200:description: A single user itemschema:id: Userproperties:username:type: stringdescription: The name of the userdefault: Steven Wilson"""return{'username':username},200api.add_resource(Username,'/username/<username>')app.run(debug=True)Auto-parsing external YAML docs andMethodViewsFlasgger can be configured to auto-parse external YAM API docs.Set adoc_dirin yourapp.config['SWAGGER']and Swagger will load API docs by looking indoc_dirfor YAML files stored by endpoint-name and method-name.  For example,'doc_dir': './examples/docs/'and a file./examples/docs/items/get.ymlwill provide a Swagger doc forItemsViewmethodget.Additionally, when usingFlask RESTfulper above, by passingparse=Truewhen constructingSwagger, Flasgger will useflask_restful.reqparse.RequestParser, locate allMethodViews and parsed and validated data will be stored inflask.request.parsed_data.Handling multiple http methods and routes for a single functionYou can separate specifications by endpoint or methodsfromflasgger.utilsimportswag_from@app.route('/api/<string:username>',endpoint='with_user_name',methods=['PUT','GET'])@app.route('/api/',endpoint='without_user_name')@swag_from('path/to/external_file.yml',endpoint='with_user_name')@swag_from('path/to/external_file_no_user_get.yml',endpoint='without_user_name',methods=['GET'])@swag_from('path/to/external_file_no_user_put.yml',endpoint='without_user_name',methods=['PUT'])deffromfile_decorated(username=None):ifnotusername:return"No user!"returnjsonify({'username':username})And the same can be achieved with multiple methods in aMethodVieworSwaggerViewby
registering theurl_rulemany times. Take a look atexamples/example_appUse the same data to validate your API POST body.Settingswag_from'svalidationparameter toTruewill validate incoming data automatically:fromflasggerimportswag_from@swag_from('defs.yml',validation=True)defpost():# if not validate returns ValidationError response with status 400# also returns the validation message.Usingswagger.validateannotation is also possible:fromflasggerimportSwaggerswagger=Swagger(app)@swagger.validate('UserSchema')defpost():'''file: defs.yml'''# if not validate returns ValidationError response with status 400# also returns the validation message.Yet you can callvalidatemanually:fromflasggerimportswag_from,validate@swag_from('defs.yml')defpost():validate(request.json,'UserSchema','defs.yml')# if not validate returns ValidationError response with status 400# also returns the validation message.It is also possible to definevalidation=TrueinSwaggerViewand also usespecs_dictfor validation.Take a look atexamples/validation.pyfor more information.All validation options can be found athttp://json-schema.org/latest/json-schema-validation.htmlCustom validationBy default Flasgger will usepython-jsonschemato perform validation.Custom validation functions are supported as long as they meet the requirements:take two, and only two, positional arguments:the data to be validated as the first; andthe schema to validate against as the second argumentraise any kind of exception when validation fails.Any return value is discarded.Providing the function to the Swagger instance will make it the default:fromflasggerimportSwaggerswagger=Swagger(app,validation_function=my_validation_function)Providing the function as parameter ofswag_fromorswagger.validateannotations or directly to thevalidatefunction will force it's use
over the default validation function for Swagger:fromflasggerimportswag_from@swag_from('spec.yml',validation=True,validation_function=my_function)...fromflasggerimportSwaggerswagger=Swagger(app)@swagger.validate('Pet',validation_function=my_function)...fromflasggerimportvalidate...validate(request.json,'Pet','defs.yml',validation_function=my_function)Validation Error handlingBy default Flasgger will handle validation errors by aborting the
request with a 400 BAD REQUEST response with the error message.A custom validation error handling function can be provided to
supersede default behavior as long as it meets the requirements:take three, and only three, positional arguments:the error raised as the first;the data which failed validation as the second; andthe schema used in to validate as the third argumentProviding the function to the Swagger instance will make it the default:fromflasggerimportSwaggerswagger=Swagger(app,validation_error_handler=my_handler)Providing the function as parameter ofswag_fromorswagger.validateannotations or directly to thevalidatefunction will force it's use
over the default validation function for Swagger:fromflasggerimportswag_from@swag_from('spec.yml',validation=True,validation_error_handler=my_handler)...fromflasggerimportSwaggerswagger=Swagger(app)@swagger.validate('Pet',validation_error_handler=my_handler)...fromflasggerimportvalidate...validate(request.json,'Pet','defs.yml',validation_error_handler=my_handler)Examples of use of a custom validation error handler function can be
found atexample validation_error_handler.pyGet defined schemas as python dictionariesYou may wish to use schemas you defined in your Swagger specs as dictionaries
without replicating the specification. For that you can use theget_schemamethod:fromflaskimportFlask,jsonifyfromflasggerimportSwagger,swag_fromapp=Flask(__name__)swagger=Swagger(app)@swagger.validate('Product')defpost():"""post endpoint---tags:- productsparameters:- name: bodyin: bodyrequired: trueschema:id: Productrequired:- nameproperties:name:type: stringdescription: The product's name.default: "Guarana"responses:200:description: The product inserted in the databaseschema:$ref: '#/definitions/Product'"""rv=db.insert(request.json)returnjsonify(rv)...product_schema=swagger.get_schema('product')This method returns a dictionary which contains the Flasgger schema id,
all defined parameters and a list of required parameters.HTML sanitizerBy default Flasgger will try to sanitize the content in YAML definitions
replacing every\nwith<br>but you can change this behaviour
setting another kind of sanitizer.fromflasggerimportSwagger,NO_SANITIZERapp=Flask()swagger=Swagger(app,sanitizer=NO_SANITIZER)You can write your own sanitizerswagger=Swagger(app,sanitizer=lambdatext:do_anything_with(text))There is also a Markdown parser available, if you want to be able to render
Markdown in your specs description useMK_SANITIZERSwagger UI and templatesYou can override thetemplates/flasgger/index.htmlin your application and
this template will be theindex.htmlfor SwaggerUI. Useflasgger/ui2/templates/index.htmlas base for your customization.Flasgger supports Swagger UI versions 2 and 3, The version 3 is still experimental but you
can try settingapp.config['SWAGGER']['uiversion'].app=Flask(__name__)app.config['SWAGGER']={'title':'My API','uiversion':3}swagger=Swagger(app)Externally loading Swagger UI and jQuery JS/CSSStarting with Flasgger 0.9.2 you can specify external URL locations for loading the JavaScript and CSS for the Swagger and jQuery libraries loaded in the Flasgger default templates.  If the configuration properties below are omitted, Flasgger will serve static versions it includes - these versions may be older than the current Swagger UI v2 or v3 releases.The following example loads Swagger UI and jQuery versions from unpkg.com:swagger_config = Swagger.DEFAULT_CONFIG
swagger_config['swagger_ui_bundle_js'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js'
swagger_config['swagger_ui_standalone_preset_js'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui-standalone-preset.js'
swagger_config['jquery_js'] = '//unpkg.com/jquery@2.2.4/dist/jquery.min.js'
swagger_config['swagger_ui_css'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui.css'
Swagger(app, config=swagger_config)Initializing Flasgger with default data.You can start your Swagger spec with any default data providing a template:template={"swagger":"2.0","info":{"title":"My API","description":"API for my data","contact":{"responsibleOrganization":"ME","responsibleDeveloper":"Me","email":"me@me.com","url":"www.me.com",},"termsOfService":"http://me.com/terms","version":"0.0.1"},"host":"mysite.com",# overrides localhost:500"basePath":"/api",# base bash for blueprint registration"schemes":["http","https"],"operationId":"getmyData"}swagger=Swagger(app,template=template)And then the template is the default data unless some view changes it. You
can also provide all your specs as template and have no views. Or views in
external APP.Getting default data at runtimeSometimes you need to get some data at runtime depending on dynamic values ex: you want to checkrequest.is_secureto decide ifschemeswill behttpsyou can do that by usingLazyString.fromflaskimportFlaskfromflasggerimport,Swagger,LazyString,LazyJSONEncoderapp=Flask(__init__)# Set the custom Encoder (Inherit it if you need to customize)app.json_encoder=LazyJSONEncodertemplate=dict(info={'title':LazyString(lambda:'Lazy Title'),'version':LazyString(lambda:'99.9.9'),'description':LazyString(lambda:'Hello Lazy World'),'termsOfService':LazyString(lambda:'/there_is_no_tos')},host=LazyString(lambda:request.host),schemes=[LazyString(lambda:'https'ifrequest.is_secureelse'http')],foo=LazyString(lambda:"Bar"))Swagger(app,template=template)TheLazyStringvalues will be evaluated only whenjsonifyencodes the value at runtime, so you have access to Flaskrequest, session, g, etc..and also may want to access a database.Behind a reverse proxySometimes you're serving your swagger docs behind an reverse proxy (e.g. NGINX).  When following theFlask guidance,
the swagger docs will load correctly, but the "Try it Out" button points to the wrong place.  This can be fixed with the following code:fromflaskimportFlask,requestfromflasggerimportSwagger,LazyString,LazyJSONEncoderapp=Flask(__name__)app.json_encoder=LazyJSONEncodertemplate=dict(swaggerUiPrefix=LazyString(lambda:request.environ.get('HTTP_X_SCRIPT_NAME','')))swagger=Swagger(app,template=template)Customize default configurationsCustom configurations such as a different specs route or disabling Swagger UI can be provided to Flasgger:swagger_config={"headers":[],"specs":[{"endpoint":'apispec_1',"route":'/apispec_1.json',"rule_filter":lambdarule:True,# all in"model_filter":lambdatag:True,# all in}],"static_url_path":"/flasgger_static",# "static_folder": "static",  # must be set by user"swagger_ui":True,"specs_route":"/apidocs/"}swagger=Swagger(app,config=swagger_config)Extracting DefinitionsDefinitions can be extracted whenidis found in spec, example:fromflaskimportFlask,jsonifyfromflasggerimportSwaggerapp=Flask(__name__)swagger=Swagger(app)@app.route('/colors/<palette>/')defcolors(palette):"""Example endpoint returning a list of colors by palette---parameters:- name: palettein: pathtype: stringenum: ['all', 'rgb', 'cmyk']required: truedefault: allresponses:200:description: A list of colors (may be filtered by palette)schema:id: Palettetype: objectproperties:palette_name:type: arrayitems:schema:id: Colortype: stringexamples:rgb: ['red', 'green', 'blue']"""all_colors={'cmyk':['cian','magenta','yellow','black'],'rgb':['red','green','blue']}ifpalette=='all':result=all_colorselse:result={palette:all_colors.get(palette)}returnjsonify(result)app.run(debug=True)In this example you do not have to passdefinitionsbut need to addidto
your schemas.