How does Connexion set the response content type?

2.1k views Asked by At

Below is an API *.yml section. I want to set the response header for the data to be Content-type: text/plain, but it always returns application/json now.

  /order:
    post:
      tags:
        - order
      summary: order
      operationId: PostOrder
      parameters:
      requestBody:
        description: Order result
        content:
          application/json:
            schema:
              type: object
              properties:
                openReq:
                  type: string
                  example: 'test'

      responses:
        200:
          description: Customer order receive successed
          headers: {}
          content:
            application/json:
              schema:
                type: string
            text/plain:
              schema:
                type: string

The response is returned by this python code:

def post_order(platform, open_req=None):  # noqa: E501
    """order

    """
    return 'do some magic!'

The response header is always content-type: application/json

      responses:
        200:
          description: Customer order receive successed
          headers: {}
          content:
            application/json:
              schema:
                type: string
            text/plain:
              schema:
                type: string

This response header for this snippet is always content-type: text/plain; charset=utf-8

      responses:
        200:
          description: Customer order receive successed
          headers: {}
          content:
#            application/json:
#              schema:
#                type: string
            text/plain:
              schema:
                type: string

Can I set the response header content type in function post_order?

3

There are 3 answers

1
Sami Akkawi On

Maybe you are confusing the API Swagger Docs with the actual implementation, your documentation is correct, it means the response 200 OK, can return as application/json or text/plain. Which one is returned depends solely on your implementation of the endpoint. If your endpoint only returns application/json, then you will never receive text/plain, that is not Swagger/OpenApi's Job.

3
Chr1s On

If you want your function to decide dynamically which content-type to return, you have to set the header explicitly as explained in the documentation.

One of the two methods is to return a tuple of the content, the return code and a dictionary of headers like this:

def post_order(platform, open_req=None): 
    """order

    """
    return 'do some magic!', 200, {'content-type': 'text/plain'}

The second method is to create a response object explicitly and return that:

from connexion.lifecycle import ConnexionResponse

def post_order(platform, open_req=None): 
    """order

    """
    return ConnexionResponse(
        status_code=200,
        content_type='text/plain',
        body='do some magic!'
    )

This gives you more control for other adjustments. But it is not necessary if the simple tuple solution works in your case.

0
Matthias On

If you are sending something with a specific mimetype the accepted answer will not work, I was trying to send text/csv and the only thing that worked (to not get /r/n in the response as chars and not producing newlines, using Connexion/flask/swagger-ui) is this

from connexion.lifecycle import ConnexionResponse

def post_order(platform, open_req=None): 
    """order"""
    return ConnexionResponse(
        status_code=200,
        content_type='text/csv',
        mimetype='text/csv',  # <----
        body='do some magic!'
    )

Explanation:

The first method from the previous answer did simply not work for me

def post_order(platform, open_req=None): 
   """order"""
    return 'do some magic!', 200, {'content-type': 'text/plain'}

some other step in my setup changed the content-type back to application/json when I was trying to send text/csv.

However, the second method

from connexion.lifecycle import ConnexionResponse

def post_order(platform, open_req=None): 
    """order"""
    return ConnexionResponse(
        status_code=200,
        content_type='text/plain',
        body='do some magic!'
    )

did change the content-type correctly when set to text/csv, BUT did not set the mimetype correctly and it took me a while to figure out why I was getting the string with /r/n in it without producing newlines. That was probably because Connexion was STILL trying to render the response as JSON instead of the intended text/csv.

The solution I posted was the only thing that worked, except using a flask response directly, which I will include here as well, that tipped me to the solution

from flask import Response

def post_order(platform, open_req=None): 
   """order"""
    return Response('do some magic!', mimetype='text/csv')

ConnexionResponse "docs" (it's the source code): https://github.com/spec-first/connexion/blob/9be473d5eabebde3df8d50e69f46513a66bba497/connexion/lifecycle.py