Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

How to pass raw text in requests body #1982

Closed
BrambleXu opened this issue Aug 28, 2020 · 12 comments
Closed

How to pass raw text in requests body #1982

BrambleXu opened this issue Aug 28, 2020 · 12 comments
Labels
question Question or problem question-migrate

Comments

@BrambleXu
Copy link

Reproduce

I want to pass raw text to request body. But it has "422 Error: Unprocessable Entity" due to the \n

from posixpath import join

from fastapi import FastAPI
from pydantic import BaseModel


class Text2kgParams(BaseModel):
    host: str
    dataset: str
    text: str


app = FastAPI()


@app.post("/text2kg")
async def contract(params: Text2kgParams):
    endpoint = join(params.host, params.dataset)
    return {"endpoint": endpoint, "text": params.text}

Description

If there is text contains \n, it will throw the 422 error.

image

image

Environment

  • OS: macOS
  • FastAPI Version : 0.6.1
  • Python: 3.7.6
@BrambleXu BrambleXu added the question Question or problem label Aug 28, 2020
@ArcLightSlavik
Copy link
Contributor

In JSON a literal line break is not allowed inside a string, it needs to be replaced by \n

{
  "host": "www.demo.com",
  "dataset": "ds",
  "text": "This is the first paragph.\nthis is the second"
}
print(params.text)

This is the first paragph.
this is the second

@BrambleXu
Copy link
Author

@ArcLightSlavik
Thanks for the comment. But how to replace the line break with '\n' in the fastapi setting?

@ArcLightSlavik
Copy link
Contributor

@BrambleXu Not sure what you mean. Fastapi settings won't deal with this, it's a json issue.

@BrambleXu
Copy link
Author

@ArcLightSlavik
Thanks. It seems I have to solve it in the front end.

@ryuzakace
Copy link

Same issue I am facing with the double quotes in the request body.

@ycd
Copy link
Contributor

ycd commented Nov 26, 2020

@ryuzakace please share what's inside your request body. As an addition it's not an issue, it is specified in the JSON specification, and all the JSON parser implementations expects that \n.

@ryuzakace
Copy link

@ryuzakace please share what's inside your request body. As an addition it's not an issue, it is specified in the JSON specification, and all the JSON parser implementations expects that \n.

Hi ycd, in my use case, the raw text may contain double quotes. In those cases, JSON parser returns 422.

Sample request body -
{
"text" : "This is a "sample" text"
}

Delimiting the double quotes in the raw-text I cannot control.

@ycd
Copy link
Contributor

ycd commented Nov 26, 2020

Of course, it would fail, you can not use double quotes with the string that you created with double-quotes.

See, even syntax highlighting understands there is an error.

{
"text" : "This is a "sample" text"
}
  • What you can do?

You can use an escape character \

{
"text" : "This is a \"sample\" text"
}

Or you can use single quotes instead of double quotes

{
"text" : "This is a 'sample' text"
}

@ryuzakace
Copy link

Yes.. I know. Actually, I cannot control the input. And the user can put double quotes while making request to the API.
Anyways, thanks @ycd , I believe this wasn't the right forum to post this issue as it is not actually related to the product.

@ycd
Copy link
Contributor

ycd commented Nov 26, 2020

Hmm, well you can create a workaround for it, here is one for inspiration

from fastapi import FastAPI, Body, APIRouter, Request, Response
from typing import Callable
from fastapi.routing import APIRoute
from pydantic import BaseModel
import json
from ast import literal_eval


class CustomRoute(APIRoute):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        async def custom_route_handler(request: Request) -> Response:
            request_body = await request.body()

            request_body = literal_eval(request_body.decode("utf-8"))

            request_body = json.dumps(request_body).encode("utf-8")

            request._body = request_body  # Note that we are overriding the incoming request's body

            response = await original_route_handler(request)
            return response

        return custom_route_handler


app = FastAPI()
router = APIRouter(route_class=CustomRoute)


class TestModel(BaseModel):
    name: str


@router.post("/")
async def dummy(model: TestModel = Body(...)):
    return model


app.include_router(router)

This is actually an invalid body

curl -X POST "http://127.0.0.1:8000/"  -d "{  \"name\": \"st""ring\"}" 

But with a custom route, we can make it work

Out: {"name":"string"}

@ycd
Copy link
Contributor

ycd commented Feb 9, 2021

@BrambleXu if your problem is solved, do you mind closing the issue?

@Alfro
Copy link

Alfro commented Apr 20, 2022

@BrambleXu kindly close the issue, since it was already mentioned that a literal line break inside a string isn't supported by JSON.

As a note, you CAN pass raw text on your body to a fastapi endpoint, in which case you should set your Request Header 'Content-Type: plain/text' instead of using json. And it works after the fixes from #1018. Your endpoint could look something like:

from fastapi import FastAPI, Body

app = FastAPI()

@app.post("/")
def read_root(body: str = Body(..., media_type='text/plain')):
    return {"I received:": body}

Although I don't think this is what you wanted/needed, so most likely the already suggested option to include the \n char where you'd like the string field to have a line break is best.

Repository owner locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #9122 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question Question or problem question-migrate
Projects
None yet
Development

No branches or pull requests

6 participants