Search code examples
react-nativeexpocloudinary

Document (pdf) upload with react native expo and Cloudinary


I have the following code where I can pick a document (pdf files) using expo-document-picker, and now I'd like to upload to cloudinary. However, I'm getting an error [SyntaxError: JSON Parse error: Unexpected token: <]. My assumption is that I'm sending the formData incorrectly to the Cloudinary API, but I'm not sure what exactly I'm doing wrong. I did go to the Cloudinary settings and make sure that I enabled pdf and zip files to be uploaded.

Here is my code:

import * as React from "react";
import * as DocumentPicker from "expo-document-picker";

const cloudName = "example";
const apiKey = "example";

export default function MyUploadScreen({ navigation }) {
const [pickedFile, setPickedFile] = React.useState(null);
const [uploadedFile, setUploadedFile] = React.useState(null);

  const pickFile = async () => {
    try {
      const filePickResponse = await DocumentPicker.getDocumentAsync({
        type: "*/*",
      });

      if (filePickResponse.type === "success") {
        setPickedFile({
          name: filePickResponse.name,
          type: filePickResponse.mimeType,
          uri: filePickResponse.uri,
        });
      }
    } catch (error) {
      console.log(error);
    }
  };

const uploadFile = async () => {

    //Add your cloud name
    let apiUrl = "https://api.cloudinary.com/v1_1/${cloudName}/document/upload";

    const formData = new FormData();
    formData.append("document", pickedFile);
    formData.append("file", pickedFile);
    formData.append("api_key", apiKey);
    formData.append("upload_preset", "example");

    const options = {
      method: "POST",
      body: formData,
      headers: {
        Accept: "application/json",
        "Content-Type": "multipart/form-data",
      },
    };

    try {
      const fileUploadResponse = await fetch(cloudinaryBaseUrl, {
        body: formData,
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "multipart/form-data",
        },
      });

      const jsonResponse = await fileUploadResponse.json();

      console.log(jsonResponse); // This will be the success response with id, secure_url, public_id, asset_id etc..
      setUploadedFile(jsonResponse);
    } catch (error) {
      console.log(error);
    }
};

The document is able to be picked correctly. What is going wrong here, that is causing the error with uploading the document?


Solution

  • The error [SyntaxError: JSON Parse error: Unexpected token: <] is returned since you're getting in response HTML and not JSON hence the unexpected token: <.

    The first thing that could lead to this is the URL you are trying to send the upload request to - i.e. https://api.cloudinary.com/v1_1/${cloudName}/document/upload. You're using document as the resource_type and document is not a valid value. You could use image or raw for PDF files, or use auto to let Cloudinary assign the resource_type automatically - which for PDFs it'll be "image". PDFs are considered "image" resource_types since you can apply transformations to them. https://cloudinary.com/documentation/paged_and_layered_media#deliver_a_selected_pdf_page_as_an_image

    Secondly, the value of apiUrl is a string but you're trying to interpolate the cloudName variable there. You'll want to replace the double quotes with backticks.

    With those changes made your code could look like this:

    let apiUrl = `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload`;
    

    I see you're also not using apiUrl but you're sending the request to cloudinaryBaseUrl - worth double checking to make sure this URL is correct in the above format - or you could replace cloudinaryBaseUrl with apiUrl.

    Separate from this, you'll want to make the following changes to your FormData:

    • api_key can be removed since it's not required when using unsigned upload
    • document is not a valid Upload API parameter and should therefore be removed

    FormData can just be:

    const formData = new FormData();
    formData.append("file", pickedFile);
    formData.append("upload_preset", "example");