What does the PUT /d2l/api/le/(version)/(orgUnitId)/content/topics/(topicId)/file want? If a wor

Options
I am building an app using react and the "superagent-d2l-session-auth" npm library the route method looks like this (feel free to take it) ----- (Typescript)    callPutRoute = (apiData:any, orgUnitId:string, topicId:string, fileString:string) => {    return new Promise((resolve, reject) => {       var request = require('superagent'),       auth = require('superagent-d2l-session-auth')();       let route = this.routeTemplate.replace("[API_VER]", apiData.LE_version)      route = route.replace("[ORG_UNIT_ID]", orgUnitId)      route = route.replace("[TOPIC_ID]", topicId)       let reqData = fileString // lets assume this is a bunch of html      // is it like widget data where I need this format "{Data:fileString}"?      // do I use on the the templates here? https://docs.valence.desire2learn.com/basic/fileupload.html#simple-uploads            request        .put(route)        .use(auth)        .set('Content-Type', 'multipart/mixed;boundary=xxBOUNDARYxx')  // is this required?        .send(reqData)        .end((err:any, response:any) => {          if (err !== null) {            console.error("PUT replaceTopicFile call failed");            console.log(err);            return reject(err);          }           console.log("PUT replaceTopicFile call success");          console.log(response.body);          resolve(response.body);              });    });  } ---------
Tagged:

Answers

  • Viktor.Haag77
    Viktor.Haag77 Posts: 10
    edited November 2022

    This route uses the simple file upload process (https://docs.valence.desire2learn.com/basic/fileupload.html#simple-uploads); there are a number of examples in the docs in the linked topic above and while none of them exactly use the API route you indicate, they can all act as a guide for what the request should look like.

     

    A good example of providing a binary file data to Brightspace this way is the "updating the profile image" example. In the Content-Disposition part header, the API you're indicating wants you to provide "file" for the value of the name parameter (where the profile image route uses the value "profileImage").

     

    Note that the simple file upload pattern does not use an overall "multipart/mixed" payload; it uses the "multipart/form-data" content type.

  • C.J..Morrison83
    C.J..Morrison83 Posts: 9
    edited November 2022

    perhaps I need more details in this question. I've tried several of the templates mentioned in the documentation.

    what I am usually getting is a 400 error indicating I am missing a detail in the request.

     

    (side note, the error is linking me here http://docs.valence.desire2learn.com/res/apiprop.html#invalid-parameters, where the "invalid-parameters" anchor doesn't seem exist)

     

    Here's a full example of the request as it appear in chrome.

     

    --- REQUEST HEADER DATA ---

     

    :method: PUT

    :path: /d2l/api/le/1.41/308299/content/topics/12025662/file

    [.....]

    content-length: 124

    content-type: multipart/form-data; boundary=xxBOUNDARYxx

    [.....]

    x-csrf-token: (let's just assume this is right)

     

    ---- PAYLOAD ----

     

    --xxBOUNDARYxx

    Content-Disposition: form-data; name='file' 

    Content-Type: text/html

     

    this is some html

    --xxBOUNDARYxx--

     

    ---- RESPONSE ----

     

    {

      "type":"http://docs.valence.desire2learn.com/res/apiprop.html#invalid-parameters",

      "title":"Invalid Parameters",

      "status":400,

      "detail":"Request has missing or invalid parameters."

    }

     

  • Viktor.Haag77
    Viktor.Haag77 Posts: 10
    edited November 2022

    Hmmm. It's possible that your part content disposition header also requires a "filename" parameter, which you're not providing, but I'm unsure that's the problem.

  • Bill.Chatzidakis81
    Bill.Chatzidakis81 Posts: 2
    edited November 2022

    Below is a working example of a PowerShell snippet I use to upload files.

     

     

    param ( $instance, $token, $Course, $FilePath )

     

    $fileName = Split-Path -Path $($FilePath) -Leaf

    $fileBin = [IO.File]::ReadAllBytes($FilePath)

    $enc = [System.Text.Encoding]::GetEncoding("iso-8859-1")

    $fileEnc = $enc.GetString($fileBin)

     

    $LF = "`r`n"

     

    $Pbody = ( 

    "Content-Type: multipart/form-data; boundary=xxBOUNDARYxx",

    "Content-Length: $($fileEnc.Length)$LF",

     

    "--xxBOUNDARYxx",

    "Content-Disposition: form-data; name=`"Image`"; filename=`"$fileName`"",

    "Content-Type: application/octet-stream$LF",

    $fileEnc,

    "--xxBOUNDARYxx--$LF" 

    ) -join $LF

     

    $header = @{Accept = "*/*"; 'Content-Type' = "multipart/form-data; boundary=xxBOUNDARYxx"; Authorization = "Bearer $($token.access_token)"}

    # Note: File is uploaded to "Course Offering Files" location

     

    $endPoint = "/courses/$($Course.Identifier)/image" 

    $uri = "https://" + $instance.uri + "/d2l/api/lp/" + $API_ver_lp + $endPoint

     

    Invoke-RestMethod -Method PUT -Uri $uri -Headers $header -Body $Pbody

     

     

    Hope this helps,

    Good luck

  • C.J..Morrison83
    C.J..Morrison83 Posts: 9
    edited November 2022

    Hello,

    When I originally changed header to "multipart/form-data" as Viktor suggested, I had apparently also tossed a ";" after the boundary causing the 400 errors.

     

    for posterity this worked (at least for txt and html)

     

        var xhr = new XMLHttpRequest();

        xhr.open("PUT", route, true);

        xhr.setRequestHeader("X-Csrf-Token", localStorage["XSRF.Token"]);

        xhr.setRequestHeader(

          "Content-Type",

          "multipart/form-data;boundary=xxBOUNDARYxx"

        );

     

        var body = `--xxBOUNDARYxx`;

        body += `Content-Disposition:form-data;name="file";filename="${fileName}"`;

        body += `Content-Type:text/html; charset="UTF-8"`;

        body += `${htmlBody}`;

        body += `--xxBOUNDARYxx--`;

     

     

    Thanks for you help.

  • Bill.Chatzidakis81
    Bill.Chatzidakis81 Posts: 2
    edited November 2022