4

I have a simple API written with the help of flask-restplus:

from flask import Flask
from flask_restplus import Resource, Api

app = Flask(__name__)                  #  Create a Flask WSGI application
api = Api(app)                         #  Create a Flask-RESTPlus API

@api.route('/hello')                   #  Create a URL route to this resource
class HelloWorld(Resource):            #  Create a RESTful resource
    def get(self):                     #  Create GET endpoint
        return {'hello': 'world'}

if __name__ == '__main__':
    app.run(debug=True) 

When I navigate to loacalhost:5000/ in the browser I get a basic Swagger documentation, but I can't find where do I get a machine readable plain yaml representation of the API, should't it be also generated automatically?

Riko
  • 155
  • 1
  • 3
  • 10

2 Answers2

6

I could not find any information around "Swagger Yaml documentation generation" in the official flask-restplus docs. So, I decided to examine the source code and found that the Swagger class implements the Swagger documentation generation for the API instance.

The Swagger class in the flask-restplus source-code is the Swagger documentation wrapper for an API instance. All methods in this class suggest that the API data is serialized as a JSON dictionary. For instance, consider the as_dict() function of this class which serializes the full Swagger specification as a serializable dict. Take a look at the docstring for this function:

from flask import Flask
from flask_restplus import Resource, Api
from flask_restplus.api import Swagger

app = Flask(__name__)                  
api = Api(app)

swag = Swagger(api)
print(swag.as_dict.__doc__) 

#Output:
Output the specification as a serializable ``dict``.

    :returns: the full Swagger specification in a serializable format
    :rtype: dict

I maybe wrong but the source code suggests that the API documentation is only returned as JSON which is available at http://localhost:5000/swagger.json by default. I could not find anything for YAML.

But there is a workaround to generate YAML documentation for your API. I used the json and yaml libraries to dump the json response from /swagger.json into YAML and save it to yamldoc.yml. You can invoke this by going to http://localhost:5000/swagger.yml. The full code:

from flask import Flask
from flask_restplus import Resource, Api
from flask_restplus.api import Swagger
import requests
import json, yaml

app = Flask(__name__)                  #  Create a Flask WSGI application
api = Api(app)                         #  Create a Flask-RESTPlus API

@api.route('/hello')                   #  Create a URL route to this resource
class HelloWorld(Resource):            #  Create a RESTful resource
    def get(self):                  
        return {'hello': 'world'}

@api.route('/swagger.yml')
class HelloWorld(Resource):    
    def get(self):
       url = 'http://localhost:5000/swagger.json'       
       resp = requests.get(url)
       data = json.loads(resp.content)    
       with open('yamldoc.yml', 'w') as yamlf:
           yaml.dump(data, yamlf, allow_unicode=True)
       return {"message":"Yaml document generated!"}


if __name__ == '__main__':
    app.run(debug=True) 

I hope this helps.

amanb
  • 5,276
  • 3
  • 19
  • 38
1

From @amanb answer I made my api return a yaml file, without making any requests. According to documentation of flask restplus (or, the most recent fork, flask restx) it is possible to export the Swagger specififcations corresponding to your API using:

from flask import json

from myapp import api

print(json.dumps(api.__schema__))

So, instead of using requests I preferred to use api.__schema__.

As my goal is to provide the file for download at the time of the request, it is necessary to use the send_file function of Flask. In addition, this file can be later deleted from the directory so we can use the after_this_request decorator of Flask to invoke the annotated function that will delete the file. The full code:

import os
import json
import yaml

from flask import Flask, after_this_request, send_file, safe_join, abort
from flask_restplus import Resource, Api
from flask_restplus.api import Swagger


app = Flask(__name__)                  #  Create a Flask WSGI application
api = Api(app)                         #  Create a Flask-RESTPlus API

@api.route('/hello')                   #  Create a URL route to this resource
class HelloWorld(Resource):            #  Create a RESTful resource
    def get(self):                  
        return {'hello': 'world'}

@api.route('/swagger.yml')
class HelloWorld(Resource):    
    def get(self):
       data = json.loads(json.dumps(api.__schema__))
       with open('yamldoc.yml', 'w') as yamlf:
           yaml.dump(data, yamlf, allow_unicode=True, default_flow_style=False)
           file = os.path.abspath(os.getcwd())
           try:
               @after_this_request
               def remove_file(resp):
                   try:
                       os.remove(safe_join(file, 'yamldoc.yml'))
                   except Exception as error:
                       log.error("Error removing or closing downloaded file handle", error)
                   return resp

               return send_file(safe_join(file, 'yamldoc.yml'), as_attachment=True, attachment_filename='yamldoc.yml', mimetype='application/x-yaml')
           except FileExistsError:
               abort(404)


if __name__ == '__main__':
    app.run(debug=True) 

Marcelo Machado
  • 1,179
  • 2
  • 13
  • 33