flask-restplus icon indicating copy to clipboard operation
flask-restplus copied to clipboard

api.header decorator of flask-restplus does not work for swagger documentation

Open sanfx opened this issue 6 years ago • 15 comments

I posted this on SO but did not got any reply: https://stackoverflow.com/q/48972880/3311276 maybe this is an issue. Can you please look at this ?

I have a simple API GET method that returns list of IP's in terminal the implementation works fine and and I can use JWT token to get list of IP. However when I try the same using TRY-OUT button on Swagger documentation page it hangs for ever.

Here is the implementation:

@url_api.route("/getallips")
@url_api.header('Authorization: Bearer', 'JWT TOKEN', required=True)
class IpList(Resource):

    @jwt_required
    def get(self):
        """
           this function handles request to provide all ip's.
        :return: List of registered ip address metadata mapped to url's.
        """
        return jsonify(get_all_publicIp())

sanfx avatar Feb 26 '18 02:02 sanfx

@sanfx hi my question like this, Has this problem been solved?

guomaoqiu avatar Aug 19 '18 08:08 guomaoqiu

Yes, same here. The headers decorator is recognised, but does not create an input prompt (like it used to in the previous version of Flask-restplus)

Name Description Type
Authorization Access Token string

garrywilliams avatar Aug 22 '18 08:08 garrywilliams

if like this, it's ok.... image image

guomaoqiu avatar Aug 22 '18 08:08 guomaoqiu

Thanks @guomaoqiu - that works in some of my cases. However, I'm mainly using the api.model approach for my arguments instead of the requestparser, so using api.doc(parser=parser) doesn't quite fit.

I just noticed a note in the docs that says:

Using RequestParser is prefered over the api.param() decorator to document form fields as it also perform validation.

Any thoughts? Should I rewrite, or is there another way to do this?

garrywilliams avatar Aug 22 '18 09:08 garrywilliams

After some experimentation, I can't get swagger documentation for an auth header and additional json parameters. 'form' works for the parameters. This used to work in the previous version.

garrywilliams avatar Aug 22 '18 10:08 garrywilliams

I don't know if my answer is what you want. Now, you can document response headers (not request headers) with the @api.header() decorator. https://flask-restplus.readthedocs.io/en/stable/swagger.html#headers

nhjeon avatar Oct 08 '18 12:10 nhjeon

Fought with this for a few hours this evening.

I was able to get it working via the security / authorization mechanism. This makes it required for all endpoints, you can override a specific endpoint by putting the decoratos @api.doc(security=None) to make it not require auth. I can now login and copy the token and click the authorize button and put in Bearer <paste> and the other calls succeed as I would expect.

authorizations = {
    'Bearer Auth': {
        'type': 'apiKey',
        'in': 'header',
        'name': 'Authorization'
    },
}
api = Api(app, security='Bearer Auth', authorizations=authorizations)

brontide avatar Dec 05 '18 02:12 brontide

Still not able to document request header. Is there any alternative solution available for custom headers ? I am using api.model approach for api.expect decorator. As @garrywilliams said, model and request header both don't play together. any idea ?

agpt avatar May 07 '19 08:05 agpt

I was able to get it with the first example using the request parser... however I don't like that way because I was unable to mask the password with *****.

I also got the second solution working for Basic Auth. If anyone needs that instead of the api key authorization... this worked for me:

authorizations = {
    'Basic Auth': {
        'type': 'basic',
        'in': 'header',
        'name': 'Authorization'
    },
}
api = Api(
    blueprint,
    doc='/',
    version='1.0',
    title=title,
    description=desc,
    security='Basic Auth',
    authorizations=authorizations
)

And then in my endpoint just get the header from the request like normal and extract the base64 encoded string:

        try:
            encoded_auth_header = request.headers['Authorization'].split()[1]
            username, password = b64decode(encoded_auth_header).split(':')
        except Exception:
            resp = app.response_class(
                response=json.dumps({"error": "bad username/password"}),
                status=401,
                content_type='application/json'
            )
            return resp


In my opinion the header decorator has nothing to do with this and this issue should be closed but I may be mistaken. I think the header decorator is for the response header that gets returned?

I think that the second method of Authorization should really be put in the documentation.

@agpt if you use the second solution (not request parser), you don't even need the api.model or api.expect etc... unless you are trying to pass in additional parameters other than Basic Auth in the header

rootVIII avatar May 11 '19 19:05 rootVIII

Now, you can document response headers (not request headers) with the @api.header() decorator.

It seems the requests headers are treated as parameters. So they can be documented and used in "Try it out" mode by means of @api.doc decorator having 'in': 'header':

@api.route('/some-endpoint')
@api.doc(params={'Authorization': {'in': 'header', 'description': 'An authorization token'}})

It gives: image

Chunosov avatar Jan 28 '20 08:01 Chunosov

try auth = request.authorization this will return dict with decoded username and password keys and values from basic authorization

kuderr avatar Feb 05 '20 14:02 kuderr

@api.doc(params={'Authorization': {'in': 'header', 'description': 'An authorization token'}})

That's what I looked so long. But it still demand a "Bearer" word before the token, can we get rid of it somehow?

Eretick avatar Jun 08 '22 13:06 Eretick

But it still demand a "Bearer" word before the token, can we get rid of it somehow?

Did you every figure this out?

nickshanks347 avatar Jun 17 '22 16:06 nickshanks347

Did you every figure this out? No, If I've got you right. Even did'nt have time for it. I understand the "Bearer" word is necessary, but I want to find a way to hide it from user in swagger so he can would put only the token in the field and "Bearer" word should be added automatically somehow. Do we have this opportunity? Maybe some parameter in doc decorator or something else?

Eretick avatar Jun 17 '22 21:06 Eretick

Did you every figure this out? No, If I've got you right. Even did'nt have time for it. I understand the "Bearer" word is necessary, but I want to find a way to hide it from user in swagger so he can would put only the token in the field and "Bearer" word should be added automatically somehow. Do we have this opportunity? Maybe some parameter in doc decorator or something else?

That's what I'd like to know too

nickshanks347 avatar Jun 18 '22 18:06 nickshanks347