getsling / flask-swagger

A swagger 2.0 spec extractor for flask
MIT License
457 stars 91 forks source link

Parser adding extra routes? #28

Open tommyjcarpenter opened 8 years ago

tommyjcarpenter commented 8 years ago

I have a class as follows:

class Docker(Resource):
    def post(self) -> "http response":
        """
        valid swagger docstring here
        """
        ...

    def get(self, session_id : str) -> "http response":
        ...

    def delete(self, session_id : str) -> "http response":
        ...

However, using your flask-swagger, TWO paths show up in resources:

Paths
/Docker
POST /Docker
/Docker/{session_id}
POST /Docker/{session_id}

The second path does not exist. What is happening?

atlithorn commented 8 years ago

Weird, could you provide me with a test case. Eg. zip of a barebones flask app where this behaviour is displayed?

tommyjcarpenter commented 8 years ago

@atlithorn Here is a working example.

It happens when you want one resource to handle multiple routes. Note that if you try to curl -X POST localhost:5002/HelloWorld/ASDF you will get an error but curl -X POST localhost:5002/HelloWorld will succeed

from flask import Flask, jsonify
from flask_restful import Resource, Api
from flask_swagger import swagger

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

class HelloWorld(Resource):
    def post(self):
        """
        Create a new user
        ---
        tags:
          - users
        definitions:
          - schema:
              id: Group
              properties:
                name:
                 type: string
                 description: the group's name
        parameters:
          - in: body
            name: body
            schema:
              id: User
              required:
                - email
                - name
              properties:
                email:
                  type: string
                  description: email for user
                name:
                  type: string
                  description: name for user
                address:
                  description: address for user
                  schema:
                    id: Address
                    properties:
                      street:
                        type: string
                      state:
                        type: string
                      country:
                        type: string
                      postalcode:
                        type: string
                groups:
                  type: array
                  description: list of groups
                  items:
                    $ref: "#/definitions/Group"
        responses:
          201:
            description: User created
        """
        return {'hello': 'world'}
    def get(self, session_id : str) -> "http response":
        return session_id

@app.route("/spec")
def spec():
    return jsonify(swagger(app))

api.add_resource(HelloWorld, '/HelloWorld', '/HelloWorld/<session_id>')

if __name__ == '__main__':
    app.run(debug=True, port = 5002)
dmertl commented 8 years ago

Running into this same issue in my app where we have one resource handling multiple routes. It's adding an operation per route rather than per resource. I'm not sure if there's a good solution though. How would you determine what route tied to what method?

atlithorn commented 8 years ago

Finally had a look at it and @dmertl is right there is no easy solution without refactoring how flask_swagger discovers resources. It's probably doable but unfortunately not something I need or have time for at the moment. More than willing to review suggestions as always.