How to upload file and also specify data options with Requests.jl?

288 views
Skip to first unread message

Ismael VC

unread,
Dec 2, 2015, 8:20:51 PM12/2/15
to julia-users
Hello everyone!

I've been trying/learning how to wrap HPE Haven OnDemand API with Julia: HavenOnDemand.jl. but I havent figured out how to send multipart data, plus other parameters, it seems to me that one can only do one or the other:

"Main `HavenOnDemand` function, used to call **Haven OnDemand** API."
function call_HOD(
        endpoint        :: String,
        async           :: Bool,    # Some endpoints are `async_only`.
        files           :: Vector{FileParam},
        options         :: Dict;
        api_url         :: String = "https://api.havenondemand.com",
        version         :: Int    = 1,
        default_version :: Int    = 1,
    )

    try
        options["apikey"] = _HOD_API_KEY
    catch
        error("Use `HavenOnDemand.set_api_key(api_key::AbstractString)` first.")
    end

    sync_str = async ? "async" : "sync"
    r = post(
        "$(api_url)/$(version)/api/$(sync_str)/$(endpoint)/v$(default_version)",
        files = files,    # <--- HERE'S THE PROBLEM!
        data = options
    )
    return r.status == 200 ? json(r) : throw(HODException(r))
end

"`DataFrame` that holds the `HavenOnDemand` data used wrap the API."
const _HOD_API = readtable(
    joinpath(Pkg.dir("HavenOnDemand"), "src", "api.data"),
    separator = ' '
)

# Meta wrap most of the API:
for row in eachrow(_HOD_API::DataFrame)
    func_name, endpoint, async_only, description = [v for (k, v) in row]
    title = join([ucfirst(s) for s in split(func_name, '_')], ' ')
    docstring = """
        **HPE Haven OnDemand: $(title)**

        `$(func_name)([kwargs...])`

        $description

        All the arguments are optional and they must be supplied as keyword
        arguments, non valid keyword names are ignored.

        For information about valid arguments, visit:

        """

    @eval begin
        @doc $docstring ->
        function $(symbol(func_name))(; file = [], kwargs...)
            return call_HOD(
                $endpoint,
                $async_only,
                [FileParam(open(f)) for f in file],
                Dict(kwargs)
            )
        end
    end
end

The error I get is:

ERROR: Multiple body options specified. Please only specify one
 in do_stream_request at C:\Users\Peter\.julia\v0.4\Requests\src\Requests.jl:268

If I try to use both `file` and `data` in the `Requests.post` function. I need both because I send the `apikey` within the `data` parameter, if I just use `file`, then the `apikey` is not passed to the API and the request fails


Here are some implementations in other languages:
It all boils down to how to do something like this:

julia> post("$(api_url)/$(version)/api/$(sync_str)/$(endpoint)/v$(default_version)", files = [FileParam("open(text.txt"))], data = Dict("apikey" => ENV["HOD_API_KEY"]))
ERROR: Multiple body options specified. Please only specify one
 in do_stream_request at C:\Users\Peter\.julia\v0.4\Requests\src\Requests.jl:268

Thanks in advance!

Ismael VC

unread,
Dec 2, 2015, 8:35:40 PM12/2/15
to julia-users
Curl:

curl -X POST --form "apikey=<API_KEY>" --form "file=@myscan.pdf" --form "mode=document_photo" https://api.idolondemand.com/1/api/async/ocrdocument/v1


HTML:

<html>
   
<head>
       
<title>Multipart Form Example</title>
   
</head>
   
<body>
       
<form action="https://api.idolondemand.com/1/api/sync/ocrdocument/v1"
                     
method="post" enctype="multipart/form-data">
           
<p><input type="hidden" name="apikey" value="your-apikey-here"></p>
           
<p><input type="file" name="file"></p>
           
<p><button type="submit">Submit</button></p>
       
</form>
   
</body>
   
</html>

Node:

var needle = require('needle');
var data = {
  apikey
: myapikey,
  file
: { file: 'myscan.pdf', content_type: 'multipart/form-data' }
}

needle
.post('https://api.idolondemand.com/1/api/async/ocrdocument/v1', data, { multipart: true }, function(err, resp, body) {
  console
.log(body)
 
// needle will read the file and include it in the form-data as binary
});

Ruby:

require 'httpclient'
require 'json'

data
={file:open("myscan.pdf"), mode:"document_photo", apikey:"apikey"}
clnt
= HTTPClient.new
resp
=clnt.post(url, data)
body
=JSON.parse(resp.body)

Python:

files = {'file': open('myscan.pdf', 'rb')}
data
= {'apikey':myapikey,'mode':'document_photo'}
requests
.post("https://api.idolondemand.com/1/api/async/ocrdocument/v1",data=data,files=files)
print r.json()

Julia ...how to???

Tyler Nappy

unread,
Mar 4, 2016, 1:30:00 PM3/4/16
to julia-users
Hi,

I would check out the Requests.jl library. The following code POSTs a file to the OCR Document API and reads the response:

Pkg.add("Requests")

using Requests
import Requests: get, post, put, delete, options

filenamne
= "/path/to/file"

response = post("http://api.havenondemand.com/1/api/sync/ocrdocument/v1"; data=Dict("apikey"=>"YOUR_APIKEY", "file"=>FileParam(open(filename,"r"),"text/julia","file2","file2.jl",true)))

readall(response)


I work for HPE.
Reply all
Reply to author
Forward
0 new messages