pdfrustnext.jsaxiosactix-web

How to send a PDF over Axios and receive over in Actix Web


I've been trying to do this multiple ways and it doesn't seem to work. I'm using NextJS so first I call my Next API:

...
      mutateUser(
        await fetchJson("/path/to/api", {
          method: "POST",
          headers: { "Content-Type": "application/pdf" },
          body: file, // const [file, setFile] = useState<File | null>(null);
        })
      );
...

Then I call my Actix Web server using Axios in the API

...
  const { token } = req.session.user;
  const body = req.body;
  const api_url = `${process.env.SERVER_API_URL}/path/to/api` as string;
  console.log(body.length);

  try {
    const response = await axios.post(api_url, body, {
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/pdf",
      },
    });
    res.json({ ...response.data, isLoggedIn: true });
  }
...

Then this is how I handle it in Actix:

pub async fn route_function(db: Data<DatabaseRepository>, mut payload: Payload, auth: AuthorizationService) -> HttpResponse {
    let id = auth.id;
    let mut bytes = BytesMut::new();
    while let Some(item) = payload.next().await {
        bytes.extend_from_slice(&item.unwrap());
    }

    //bytes to string
    log::debug!("bytes: {:?}", bytes);
    // length of bytes
    log::debug!("bytes length: {:?}", bytes.len());

    let pdf_text = match pdf_extract::extract_text_from_mem(&bytes) {
        Ok(text) => text,
        Err(e) => { // PDF parsing error only with Axios
            log::error!("Error: {:#?}", e);
            return HttpResponse::BadRequest().json(ErrorResponse::new("error parsing pdf".to_string(), e.to_string()));
        }
    };
...

So basically, what's going wrong is this: When I use Postman or cURL the Rust route works perfectly. Here is my cURL command for reference:

# This works
curl -X POST -H "Content-Type: application/pdf" -H "Authorization: Bearer <TOKEN>" --data-binary "@/path/to/file.pdf" http://localhost:8080/path/to/api

However, when I use Axios, I get a PDF Parsing error. The PDF parser library returns an error when parsing the PDF Trailer. Additionally, I was checking the bytes length of the requests and when I call using Axios it is around 101k bytes but when I call using Postman or cURL it is 58k bytes. Not sure why but I think this has something to do with why it's not working. This also makes me think that I am doing something wrong with either Axios, Next, or Fetch but I can't find where. I also tried using FormData() but that didn't work either.

If someone has a workaround by changing my Actix route so that it works generally, this is also appreciated. I only found how to read a pdf using the Payload extractor.

Any help is appreciated. Thanks in advance.


Solution

  • It seems like you have to do this in next

    export const config = {
      api: {
        bodyParser: false,
      },
    };
    

    to then use req as a readable stream.

    Refer to: https://github.com/vercel/next.js/issues/37735 or https://www.reddit.com/r/nextjs/comments/tt4qbf/getting_the_raw_request_body_according_to_next_is/

    Then you can post this using axios. When you encounter further problems, you might want to consider setting the Content-Length Header.

    https://github.com/axios/axios/issues/5223#issuecomment-1690233615