1

enter image description here

What am I supposed to send as the request body. I keep getting 400 Bad request. I have tried it on Postman as well as in a html file with javascript code in the script tag.

What does it mean by the file's bytes? A file as a byte array?

I also tried using postman with a key (type: file) and a file. Got BAD_REQUEST

I tried creating Blobs and converted them into byte array, append those arrays into formdata and then provide them as request body using JSON.stringify().

The current code however takes a file input from a form html tag.

Nothing seems to be working.

Also how do I write a curl command for this POST method. And how to get a document's metadata.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

</head>
<body>
    <form action="" enctype="multipart/form-data" id="FORM">
        <div>
            <label for="">File Name:</label>
            <input type="text" id="FileName">
            <label for="">File:</label>
            <input type="file" id="File">
            
            <button type="submit" style="" id="submitB">Submit</button>
        </div>
    </form>
</body>
<script>
const formData = new FormData();
        const formDataTwo = new FormData();
        const formDataThree = new FormData();

        const fileOne = new Blob(["John","117"],{type:'text/html'});
        const fileTwo = new Blob(["Commander", "Zavala"], { type: 'text/html' });
        const fileThree = new Blob(["Ikora", "Rey"], { type: 'text/html' });


        var reader = new FileReader();
        reader.readAsArrayBuffer(fileOne);
        var byteOne = [];
        reader.onloadend = function(e){
            if(e.target.readyState == FileReader.DONE){
                var arrayBuffer = e.target.result;
                array = new Uint8Array(arrayBuffer);

            }
            for(var i=0; i<array.length;i++){
                byteOne.push(array[i]);
            }
        }

        var readerOne = new FileReader();
        readerOne.readAsArrayBuffer(fileTwo)
        var byteTwo = [];
            readerOne.onloadend = function (e) {
                if (e.target.readyState == FileReader.DONE) {
                    var arrayBuffer = e.target.result;
                    array = new Uint8Array(arrayBuffer);

                }
                for (var i = 0; i < array.length; i++) {
                    byteTwo.push(array[i]);
                }
            }

        




        var form = document.getElementById('FORM') 

        form.onsubmit = async (e) =>{
            e.preventDefault()
            const form = e.currentTarget;

            var readerTwo = new FileReader();
            readerTwo.readAsArrayBuffer(document.getElementById('File').files[0]);
            let byteThree = [];
            const formDataNew = new FormData();

            readerTwo.onloadend = function (e) {
                if (e.target.readyState == FileReader.DONE) {
                    var arrayBuffer = e.target.result;
                    array = new Uint8Array(arrayBuffer);

                }
                for (var i = 0; i < array.length; i++) {
                    byteThree.push(array[i]);
                }
                formDataNew.append('additionalProp1', byteThree)
            }

            const obj = {
                additionalProp1: formDataNew
            }
            
            

            fetch('http://localhost:8080/o/headless-delivery/v1.0/sites/20121/documents', {
                method: "POST",
                headers: {
                    
                    "Content-Type": "multipart/form-data",
                    "Authorization": `Basic ${btoa('test@oscorp.com:learn')}`
                },
                body: JSON.stringify(obj)
            })
                .then(Response => Response.json())
                .then(json => console.log(json));

        }
        
        

        // formData.append('fileOne', byteOne);
        // formDataTwo.append('fileTwo', byteTwo);
        // formDataThree.append('fileThree', byteThree);
</script>
</html>

The Postman api request worked after I modified the key name as instructed. But the html page still won't work. I keep getting Error code 400. My current js code is below. Also find the working Postman request screenshots below.

enter image description here

enter image description here

enter image description here

 var form = document.getElementById('FORM') 

        form.onsubmit = async (e) =>{
            e.preventDefault()
           
            const file = document.querySelector("input[type=file]").files[0];
            const metadata = {additionalProp1: "string" };

            const body = new FormData();
            body.append("file", file);
            body.append("document", JSON.stringify(metadata));

            fetch("http://localhost:8080/o/headless-delivery/v1.0/sites/20121/documents", {
                method: "POST",
                headers: {
                    
                    "Content-Type": "multipart/form-data",
                    "Authorization": `Basic ${btoa('test@oscorp.com:learn')}`
                },
                body

            })
                .then(Response => Response.json())
                .then(json => console.log(json))

            }
John117
  • 31
  • 5
  • _"tried using postman with a key (type: file) and a file"_... according to your screenshot you used field name `NewDoc`. Have you tried `file` instead? – Phil Feb 08 '23 at 03:47

1 Answers1

2

Bad API documentation, especially examples can be a real hindrance.

From reading just the description...

The request body must be multipart/form-data with two parts, the file's bytes (file), and an optional JSON string (document) with the metadata.

Update: from comments below it seems that document should also be a file

I would assume you'd need something like this...

document.getElementById("FORM").addEventListener("submit", async (e) => {
  e.preventDefault();

  const file = document.getElementById("File").files[0];

  // this is just an example
  const metadata = { additionalProp1: "string" };

  // create a File object for the JSON document
  const doc = new File([JSON.stringify(metadata)], "metadata.json", {
    type: "application/json",
  });

  const body = new FormData();
  body.append("file", file);
  body.append("document", doc);

  const res = await fetch("http://localhost:8080/o/headless-delivery/v1.0/sites/20121/documents", {
    method: "POST",
    headers: {
      authorization: `Basic ${btoa('test@oscorp.com:learn')}`,
    },
    body,
  });

  if (!res.ok) {
    throw new Error(`${res.status} ${res.statusText}: ${await res.text()}`);
  }

  console.log("Success!", await res.json());
});

Note that there is no content-type header added. The browser is able to provide the correct value automatically when using a FormData body. See this answer for more details.

I think you can ignore any examples they offer. They don't appear to match the description at all.


In Postman, you'd use form-data like this

Key Value Description
file NewDoc.txt A file
document metadata.json A JSON file

It would be up to you to ensure document is properly formatted JSON.

Phil
  • 157,677
  • 23
  • 242
  • 245
  • FIrst of all I would like to thank you good sir for your guidance. Postman worked out! But I am still getting error code 400 with the html page. I would post my current code as an answer below. Please help. – John117 Feb 08 '23 at 04:58
  • @John117 I see what you've done wrong. Remove the content-type header. I've updated my answer – Phil Feb 08 '23 at 05:31
  • Yes, the code worked. I stored a .json file in the matadata variable and appended it to formdata. However, if metadata contains that object that you provided in the code above and I append that variable then it returned error code 400 even after JSON.stringify(). Why is it that content-type isn't required for this post request? – John117 Feb 08 '23 at 05:48
  • Ok, just saw your response for content-type header. Thanks for the clarification and all your help. – John117 Feb 08 '23 at 05:52
  • @John117 so you're saying that `document` needs to be a file too? That API really is poorly documented – Phil Feb 08 '23 at 05:55
  • @John117 I've updated my answer to show how to create a JSON file – Phil Feb 08 '23 at 05:59
  • Yes, that code works like a charm. But cannot upload a file with the same filename twice. Error code 409 CONFLICT. However, when there was an additional parameter in body.append("file", file, fileName) which I was getting from input type="text" tag, whenever I changed the input even if the file was same, I was getting success. – John117 Feb 08 '23 at 06:09
  • 1
    @John117 Nice, sounds like you've got it sorted then – Phil Feb 08 '23 at 06:38