Sample code for 30+ languages & platforms
PureBasic Requires Chilkat v11.7.0+

Box: Resolve Folder and File IDs with the HttpCurl Dependency Engine

See more Box Examples

Download images/penguins.jpg using search-based HttpCurl dependencies and one DoYourThing call. Register search requests/output rules once, then supply names. Search results must each contain exactly one item; exact names and immediate parent IDs are checked before saving the downloaded bytes. The candidate content is downloaded into memory before validation, so this example is for small files. Multiple results are rejected instead of paginated or silently choosing a candidate. Search indexing can delay visibility of newly created or renamed items.

See the Box API guide for setup and the complete workflow.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkBinData.pb"
IncludeFile "CkStringBuilder.pb"
IncludeFile "CkJsonObject.pb"
IncludeFile "CkHttpCurl.pb"

Procedure ChilkatExample()

    success.i = 0

    ;  Requires Chilkat 11.7.0 or later and a previously unlocked Chilkat bundle.
    ;  See Global Unlock Sample.
    ;  Guide: Box API Guide.

    success = 0

    ;  BEGIN ONE-TIME SETUP
    ;  Requires Chilkat 11.7.0. Registration sends no requests.
    ;  Run this once and keep the SAME HttpCurl object for later downloads.
    ;  This focused setup searches for a root folder and a file directly inside it.
    curl.i = CkHttpCurl::ckCreate()
    If curl.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkHttpCurl::ckSetVar(curl,"access_token","BOX_ACCESS_TOKEN")
    setupCommand.i = CkStringBuilder::ckCreate()
    If setupCommand.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    setupReplacements.i

    ;  searchFolder: Box searches names; quotes request a phrase match.
    CkStringBuilder::ckSetString(setupCommand,"curl -X GET " + Chr(34) + "https://api.box.com/2.0/search?query={{folder_query}}&type=folder&content_types=name&fields=id,type,name,parent&limit=2" + Chr(34) + " -H " + Chr(34) + "Authorization: Bearer ACCESS_TOKEN" + Chr(34))
    setupReplacements = CkStringBuilder::ckReplace(setupCommand,"ACCESS_TOKEN",CkHttpCurl::ckGetVar(curl,"access_token"))
    success = CkHttpCurl::ckAddFunction(curl,"searchFolder",CkStringBuilder::ckGetAsString(setupCommand))
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    ;  Deferred selection: folder_name need not be set during setup.
    success = CkHttpCurl::ckAddOutput2(curl,"searchFolder","entries","name","{{folder_name}}",1,"id","folder_id")
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    success = CkHttpCurl::ckAddOutput2(curl,"searchFolder","entries","name","{{folder_name}}",1,"name","folder_result_name")
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    success = CkHttpCurl::ckAddOutput2(curl,"searchFolder","entries","name","{{folder_name}}",1,"parent.id","folder_parent_id")
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    success = CkHttpCurl::ckAddOutput(curl,"searchFolder","total_count","folder_search_count")
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    ;  searchFile: Box searches names; quotes request a phrase match.
    CkStringBuilder::ckSetString(setupCommand,"curl -X GET " + Chr(34) + "https://api.box.com/2.0/search?query={{file_query}}&type=file&content_types=name&fields=id,type,name,parent&limit=2&ancestor_folder_ids={{folder_id}}" + Chr(34) + " -H " + Chr(34) + "Authorization: Bearer ACCESS_TOKEN" + Chr(34))
    setupReplacements = CkStringBuilder::ckReplace(setupCommand,"ACCESS_TOKEN",CkHttpCurl::ckGetVar(curl,"access_token"))
    success = CkHttpCurl::ckAddFunction(curl,"searchFile",CkStringBuilder::ckGetAsString(setupCommand))
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    ;  Deferred selection: file_name need not be set during setup.
    success = CkHttpCurl::ckAddOutput2(curl,"searchFile","entries","name","{{file_name}}",1,"id","file_id")
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    success = CkHttpCurl::ckAddOutput2(curl,"searchFile","entries","name","{{file_name}}",1,"name","file_result_name")
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    success = CkHttpCurl::ckAddOutput2(curl,"searchFile","entries","name","{{file_name}}",1,"parent.id","file_parent_id")
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    success = CkHttpCurl::ckAddOutput(curl,"searchFile","total_count","file_search_count")
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        ProcedureReturn
    EndIf

    ;  END ONE-TIME SETUP
    ;  Search is indexed: newly uploaded/renamed items may not appear immediately.
    ;  Search matches phrases, not exact strings, and ancestor filtering includes
    ;  subfolders. The operation validates counts, exact names, and immediate parents.
    ;  limit=2 is enough to demonstrate an ambiguous search; total_count covers all
    ;  results, not just this page. This introductory example requires exactly one
    ;  search result at each step and does not select among multiple candidates.

    ;  BEGIN OPERATION -- use the previously configured object.
    ;  Human-readable inputs. No resource IDs are supplied by the caller.
    folderName.s = "images"
    fileName.s = "penguins.jpg"
    ;  Encode the quoted search queries separately from the literal output filters.
    ;  In this build, URL variable substitution does not encode '&' in a name.
    queryText.i = CkStringBuilder::ckCreate()
    If queryText.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkStringBuilder::ckSetString(queryText,Chr(34))
    CkStringBuilder::ckAppend(queryText,folderName)
    CkStringBuilder::ckAppend(queryText,Chr(34))
    CkHttpCurl::ckSetVar(curl,"folder_query",CkStringBuilder::ckGetEncoded(queryText,"url","utf-8"))
    CkStringBuilder::ckSetString(queryText,Chr(34))
    CkStringBuilder::ckAppend(queryText,fileName)
    CkStringBuilder::ckAppend(queryText,Chr(34))
    CkHttpCurl::ckSetVar(curl,"file_query",CkStringBuilder::ckGetEncoded(queryText,"url","utf-8"))
    If CkHttpCurl::ckGetVar(curl,"folder_name") <> folderName
        CkHttpCurl::ckClearVar(curl,"folder_id")
        CkHttpCurl::ckClearVar(curl,"folder_result_name")
        CkHttpCurl::ckClearVar(curl,"folder_parent_id")
        CkHttpCurl::ckClearVar(curl,"folder_search_count")
        CkHttpCurl::ckClearVar(curl,"file_id")
        CkHttpCurl::ckClearVar(curl,"file_result_name")
        CkHttpCurl::ckClearVar(curl,"file_parent_id")
        CkHttpCurl::ckClearVar(curl,"file_search_count")
        CkHttpCurl::ckSetVar(curl,"folder_name",folderName)
    EndIf

    If CkHttpCurl::ckGetVar(curl,"file_name") <> fileName
        CkHttpCurl::ckClearVar(curl,"file_id")
        CkHttpCurl::ckClearVar(curl,"file_result_name")
        CkHttpCurl::ckClearVar(curl,"file_parent_id")
        CkHttpCurl::ckClearVar(curl,"file_search_count")
        CkHttpCurl::ckSetVar(curl,"file_name",fileName)
    EndIf

    ;  With unchanged names, cached IDs and validation fields can be reused.
    ;  Clear the corresponding cached fields to refresh after a remote rename/move.
    localPath.s = "qa_output/penguins.jpg"
    ;  A cold plan is searchFolder -> searchFile -> targetCurl.
    ;  No listing endpoint or manual search call is used.
    plan.i = CkJsonObject::ckCreate()
    If plan.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkJsonObject::setCkEmitCompact(plan, 0)
    authorizedCommand1.i = CkStringBuilder::ckCreate()
    If authorizedCommand1.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkStringBuilder::ckSetString(authorizedCommand1,"curl -X GET " + Chr(34) + "https://api.box.com/2.0/files/{{file_id}}/content" + Chr(34) + " -H " + Chr(34) + "Authorization: Bearer {{access_token}}" + Chr(34) + " -L")
    headerReplacement1.i = CkStringBuilder::ckReplace(authorizedCommand1,"{{access_token}}",CkHttpCurl::ckGetVar(curl,"access_token"))
    success = CkHttpCurl::ckExaminePlan(curl,CkStringBuilder::ckGetAsString(authorizedCommand1),plan)
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        CkStringBuilder::ckDispose(queryText)
        CkJsonObject::ckDispose(plan)
        CkStringBuilder::ckDispose(authorizedCommand1)
        ProcedureReturn
    EndIf

    Debug CkJsonObject::ckEmit(plan)
    ;  Keep the candidate download in memory; do not write an unvalidated result.
    CkHttpCurl::setCkResponseFilePath(curl, "")
    CkHttpCurl::ckClearTargetOutput(curl,"*")
    authorizedCommand2.i = CkStringBuilder::ckCreate()
    If authorizedCommand2.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkStringBuilder::ckSetString(authorizedCommand2,"curl -X GET " + Chr(34) + "https://api.box.com/2.0/files/{{file_id}}/content" + Chr(34) + " -H " + Chr(34) + "Authorization: Bearer {{access_token}}" + Chr(34) + " -L")
    headerReplacement2.i = CkStringBuilder::ckReplace(authorizedCommand2,"{{access_token}}",CkHttpCurl::ckGetVar(curl,"access_token"))
    success = CkHttpCurl::ckDoYourThing(curl,CkStringBuilder::ckGetAsString(authorizedCommand2))
    If (success <> 1) OR (CkHttpCurl::ckStatusCode(curl) <> 200)
        Debug "Box request failed. HTTP status: " + Str(CkHttpCurl::ckStatusCode(curl))
        Debug "Failure reason: " + Str(CkHttpCurl::ckFailReason(curl))
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        CkStringBuilder::ckDispose(queryText)
        CkJsonObject::ckDispose(plan)
        CkStringBuilder::ckDispose(authorizedCommand1)
        CkStringBuilder::ckDispose(authorizedCommand2)
        ProcedureReturn
    EndIf

    ;  AddOutput2 supplies candidate IDs. Box's phrase search and recursive
    ;  ancestor filter are not an exact path lookup, so validate before saving.
    If (CkHttpCurl::ckGetVar(curl,"folder_search_count") <> "1") OR (CkHttpCurl::ckGetVar(curl,"file_search_count") <> "1")
        Debug "Search was ambiguous or incomplete. Expected exactly one result per search; no file was saved."
        Debug "Folder results: " + CkHttpCurl::ckGetVar(curl,"folder_search_count") + " File results: " + CkHttpCurl::ckGetVar(curl,"file_search_count")
        CkHttpCurl::ckClearVar(curl,"folder_id")
        CkHttpCurl::ckClearVar(curl,"folder_result_name")
        CkHttpCurl::ckClearVar(curl,"folder_parent_id")
        CkHttpCurl::ckClearVar(curl,"folder_search_count")
        CkHttpCurl::ckClearVar(curl,"file_id")
        CkHttpCurl::ckClearVar(curl,"file_result_name")
        CkHttpCurl::ckClearVar(curl,"file_parent_id")
        CkHttpCurl::ckClearVar(curl,"file_search_count")
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        CkStringBuilder::ckDispose(queryText)
        CkJsonObject::ckDispose(plan)
        CkStringBuilder::ckDispose(authorizedCommand1)
        CkStringBuilder::ckDispose(authorizedCommand2)
        ProcedureReturn
    EndIf

    If (CkHttpCurl::ckGetVar(curl,"folder_result_name") <> folderName) OR (CkHttpCurl::ckGetVar(curl,"folder_parent_id") <> "0") OR (CkHttpCurl::ckGetVar(curl,"file_result_name") <> fileName) OR (CkHttpCurl::ckGetVar(curl,"file_parent_id") <> CkHttpCurl::ckGetVar(curl,"folder_id"))
        Debug "The search result is not the exact root-folder/filename requested; no file was saved."
        CkHttpCurl::ckClearVar(curl,"folder_id")
        CkHttpCurl::ckClearVar(curl,"folder_result_name")
        CkHttpCurl::ckClearVar(curl,"folder_parent_id")
        CkHttpCurl::ckClearVar(curl,"folder_search_count")
        CkHttpCurl::ckClearVar(curl,"file_id")
        CkHttpCurl::ckClearVar(curl,"file_result_name")
        CkHttpCurl::ckClearVar(curl,"file_parent_id")
        CkHttpCurl::ckClearVar(curl,"file_search_count")
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        CkStringBuilder::ckDispose(queryText)
        CkJsonObject::ckDispose(plan)
        CkStringBuilder::ckDispose(authorizedCommand1)
        CkStringBuilder::ckDispose(authorizedCommand2)
        ProcedureReturn
    EndIf

    ;  Validation is after the network download but before writing the destination.
    ;  This in-memory example is intended for small files such as penguins.jpg.
    ;  Create qa_output before running it.
    contents.i = CkBinData::ckCreate()
    If contents.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkHttpCurl::ckGetResponseBd(curl,contents)
    If success <> 1
        Debug CkHttpCurl::ckLastErrorText(curl)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        CkStringBuilder::ckDispose(queryText)
        CkJsonObject::ckDispose(plan)
        CkStringBuilder::ckDispose(authorizedCommand1)
        CkStringBuilder::ckDispose(authorizedCommand2)
        CkBinData::ckDispose(contents)
        ProcedureReturn
    EndIf

    success = CkBinData::ckWriteFile(contents,localPath)
    If success <> 1
        Debug CkBinData::ckLastErrorText(contents)
        CkHttpCurl::ckDispose(curl)
        CkStringBuilder::ckDispose(setupCommand)
        CkStringBuilder::ckDispose(queryText)
        CkJsonObject::ckDispose(plan)
        CkStringBuilder::ckDispose(authorizedCommand1)
        CkStringBuilder::ckDispose(authorizedCommand2)
        CkBinData::ckDispose(contents)
        ProcedureReturn
    EndIf

    Debug "Downloaded to " + localPath


    CkHttpCurl::ckDispose(curl)
    CkStringBuilder::ckDispose(setupCommand)
    CkStringBuilder::ckDispose(queryText)
    CkJsonObject::ckDispose(plan)
    CkStringBuilder::ckDispose(authorizedCommand1)
    CkStringBuilder::ckDispose(authorizedCommand2)
    CkBinData::ckDispose(contents)


    ProcedureReturn
EndProcedure