Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass headers parameters as keyword arguments to handler function #788

Closed
dutradda opened this issue Nov 19, 2018 · 8 comments
Closed

Pass headers parameters as keyword arguments to handler function #788

dutradda opened this issue Nov 19, 2018 · 8 comments

Comments

@dutradda
Copy link
Contributor

Description

For now there's no way to get the headers parameters from aiohttp. We need to do a custom middleware or use the aiohttp-request to get the headers. But in flask we have the global request variable.

My proposal is to pass headers parameters as keyword arguments to handler function on parameter_to_arg decorator function.

There's an any architectural problem or something like that blocks the implementation of the headers on handler parameters?

Expected behaviour

Headers parameters passed to handler **kwargs

Actual behaviour

The headers parameters are not passed to handler **kwargs

@dtkav
Copy link
Collaborator

dtkav commented Nov 19, 2018

I'd personally want the interface to work the same with Flask and aiohttp.

I don't yet have a strong enough understanding of the aiohttp internals to offer an informed opinion on how to do this, but unless we do a major revision bump (to change the interface) I'd probably lean towards trying to bring a request-like object into scope for the aiohttp handler.

@dutradda
Copy link
Contributor Author

I was thinking about doing this change for flask and aiohttp

@dtkav
Copy link
Collaborator

dtkav commented Nov 28, 2018

Ok that seems reasonable to me.
You'll probably only want to add it if headers already exists in args or has_kwargs is true so that it is backwards compatible.
@jmcs anything to add?

@Jyhess
Copy link
Contributor

Jyhess commented Jan 9, 2019

It's possible to retrieve aiohttp request object in your handlers.
For that, when adding api, you need to specify which name to use in your functions with pass_context_arg_name:

api = app.add_api('openapi.yaml', pass_context_arg_name='request')

And to add a parameter with this name in your handlers, which give you access to all request information, including headers:

async def hello(request: web.Request) -> web.Response:
    headers = request.headers
    #...

@patrickppp
Copy link

@Jyhess can you also provide an example for Flask please?

@dtkav
Copy link
Collaborator

dtkav commented Jan 14, 2019

@patrickppp you can use the request object in flask.

from flask import request

def my_handler(...):
    headers = request.headers

@adrpp
Copy link

adrpp commented Jan 31, 2019

Hello,

for now we have patched connexion/decorators/parameter.py accordingly. Feels like there is a need for sync oas-generator with connexion behavior. My point is, if there are pre-generated controllers by oas-code-genarator that expects header params as function argument, then it should be passed down into that callable.
For now, the code you generate, you cannot use out of the box because connexion does not pass this further down.

Rgds,
Adrian

@vishnuagbly
Copy link

I found a way to fix this issue.

Replace the controller.mustache file with following content:

import connexion
from typing import Dict
from typing import Tuple
from typing import Union
from flask import request

{{#imports}}{{import}}  # noqa: E501
{{/imports}}
from {{packageName}} import util
{{#operations}}
{{#operation}}


def {{operationId}}({{#allParams}}{{^isHeaderParam}}{{paramName}}{{^required}}=None{{/required}}{{^-last}}, {{/-last}}{{/isHeaderParam}}{{/allParams}}):  # noqa: E501
    """{{summary}}{{^summary}}{{operationId}}{{/summary}}

    {{notes}} # noqa: E501

    {{#allParams}}
    :param {{paramName}}: {{description}}
        {{^isContainer}}
            {{#isPrimitiveType}}
    :type {{paramName}}: {{>param_type}}
            {{/isPrimitiveType}}
            {{#isUuid}}
    :type {{paramName}}: {{>param_type}}
            {{/isUuid}}
            {{^isPrimitiveType}}
                {{#isFile}}
    :type {{paramName}}: werkzeug.datastructures.FileStorage
                {{/isFile}}
                {{^isFile}}
                    {{^isUuid}}
    :type {{paramName}}: dict | bytes
                    {{/isUuid}}
                {{/isFile}}
            {{/isPrimitiveType}}
        {{/isContainer}}
        {{#isArray}}
            {{#items}}
                {{#isPrimitiveType}}
    :type {{paramName}}: List[{{>param_type}}]
                {{/isPrimitiveType}}
                {{^isPrimitiveType}}
    :type {{paramName}}: list | bytes
                {{/isPrimitiveType}}
            {{/items}}
        {{/isArray}}
        {{#isMap}}
            {{#items}}
                {{#isPrimitiveType}}
    :type {{paramName}}: Dict[str, {{>param_type}}]
                {{/isPrimitiveType}}
                {{^isPrimitiveType}}
    :type {{paramName}}: dict | bytes
                {{/isPrimitiveType}}
            {{/items}}
        {{/isMap}}
    {{/allParams}}

    :rtype: Union[{{returnType}}{{^returnType}}None{{/returnType}}, Tuple[{{returnType}}{{^returnType}}None{{/returnType}}, int], Tuple[{{returnType}}{{^returnType}}None{{/returnType}}, int, Dict[str, str]]
    """

    {{#allParams}}
        {{#isHeaderParam}}
    {{paramName}} = request.headers.get('{{paramName}}')
        {{/isHeaderParam}}
    {{/allParams}}

    {{#allParams}}
        {{^isContainer}}
            {{#isDate}}
    {{paramName}} = util.deserialize_date({{paramName}})
            {{/isDate}}
            {{#isDateTime}}
    {{paramName}} = util.deserialize_datetime({{paramName}})
            {{/isDateTime}}
            {{^isPrimitiveType}}
                {{^isFile}}
                    {{^isUuid}}
    if connexion.request.is_json:
        {{paramName}} = {{baseType}}{{^baseType}}{{#dataType}} {{.}}{{/dataType}}{{/baseType}}.from_dict(connexion.request.get_json())  # noqa: E501
                    {{/isUuid}}
                {{/isFile}}
            {{/isPrimitiveType}}
        {{/isContainer}}
        {{#isArray}}
            {{#items}}
                {{#isDate}}
    if connexion.request.is_json:
        {{paramName}} = [util.deserialize_date(s) for s in connexion.request.get_json()]  # noqa: E501
                {{/isDate}}
                {{#isDateTime}}
    if connexion.request.is_json:
        {{paramName}} = [util.deserialize_datetime(s) for s in connexion.request.get_json()]  # noqa: E501
                {{/isDateTime}}
                {{#complexType}}
    if connexion.request.is_json:
        {{paramName}} = [{{complexType}}.from_dict(d) for d in connexion.request.get_json()]  # noqa: E501
                {{/complexType}}
            {{/items}}
        {{/isArray}}
        {{#isMap}}
            {{#items}}
                {{#isDate}}
    if connexion.request.is_json:
        {{paramName}} = {k: util.deserialize_date(v) for k, v in connexion.request.get_json().items()}  # noqa: E501
                {{/isDate}}
                {{#isDateTime}}
    if connexion.request.is_json:
        {{paramName}} = {k: util.deserialize_datetime(v) for k, v in connexion.request.get_json().items()}  # noqa: E501
                {{/isDateTime}}
                {{#complexType}}
    if connexion.request.is_json:
        {{paramName}} = {k: {{baseType}}.from_dict(v) for k, v in connexion.request.get_json().items()}  # noqa: E501
                {{/complexType}}
            {{/items}}
        {{/isMap}}
    {{/allParams}}
    return 'Magic'
{{/operation}}
{{/operations}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants