Noob question: JuliaWebAPI - does not accept keyword arguments

Hello Julia Community!!!
Can’t tell you how much I’m enjoying Julia’s core concepts and implementation. I’m hoping this becomes my main language.

Ok, so I created a little prototype using JuliaWebAPI and its GitHub documentation. My goals are simple: call listSoundFiles via the API and get json back what’s in SoundFile struct (succesful) and then be able to update it (failed).

This works and I get json:
curl http://localhost:8888/listSoundFiles

However, this doesn’t:
curl -d “title1=Concerto&author=Beethoven?date1=01102020?tag1=classical?url1=https://duckduckgo.comhttp://localhost:8888/updateSoundFiles

I get this error:
{“data”:“ErrorException("function updateSoundFiles does not accept keyword arguments")”,“code”:-2}

As I said, I’m new to Julia so I’m assuming my issue is with the syntax for updateSoundFiles or perhaps a scope issue? Maybe the JuliaWebAPI.create_responder needs different options for POST calls? Regardless, I haven’t been able to figure it out.

Any help would really be appreciated.

Thanks,
Jose

srvr.jl

using Dates
using JuliaWebAPI

mutable struct SoundFile
    title::String
    creator::String
    date::String
    tags::Array
    URL::String
end

const InfoncastSoundFiles = SoundFile[
  SoundFile("Fur Elise", "Ludwig Beethoven","12202019",["mp3","song", "music"],"”https://URL Here”"),
  SoundFile("Fidelio", "Ludwig Beethoven","11032011",["song", "dance"],"”https://URL Here”),
  SoundFile("Missa Solemnis", "Ludwig Beethoven","03102019",["mp3", "song"], ”https://URL Here”)
]

function listSoundFiles()
  return InfoncastSoundFiles
end

function updateSoundFiles(title1, author, date1, tag1, url1)
  SoundFile(title,creator,date,tags,url)
end


process(
    JuliaWebAPI.create_responder([
        (listSoundFiles, true),
        (updateSoundFiles, true)
    ], "tcp://127.0.0.1:9999", true, "")
)

Welcome to Julia.

I am not able to reproduce your examples. Not the working one and not the error state. You have several issues in your code (e.g., port 9999 or 8888 or the "”).

Please try to give a MWE (see this https://discourse.julialang.org/t/psa-make-it-easier-to-help-you) in such a way that we just can copy paste your code to reproduce your issues.
If you think you are ready, you may check your own post with a newly opened REPL if it is really working.

My apologies for not including the http server code:

httpsrvr.jl

using JuliaWebAPI   #Load package

#Create the ZMQ client that talks to the ZMQ listener above
const apiclnt = APIInvoker("tcp://127.0.0.1:9999");

#Starts the HTTP server in current process
run_http(apiclnt, 8888)

Not sure how to create a REPL for this when the two files create a process. This code is nothing more than an adaptation of the example on JulaWebAPI GitHub.

To run it one needs two Julia sessions: one for srvr.jl and the other for httpsrvr.jl. Once they’re both running - assuming locally - you can the curl it as a test and a get a son response:

curl http://localhost:8888/listSoundFiles

The second function (updateSoundFiles) I’m trying to expose is the one I get an error with.

curl -d “title1=Concerto&author=Beethoven?date1=01102020?tag1=classical?url1=https://duckduckgo.com” http://localhost:8888/updateSoundFiles

this is the error

{“data”:“ErrorException(“function updateSoundFiles does not accept keyword arguments”)”,“code”:-2}

The server functionality works. Srvr.jl and httpsrvr.jl work as expected. The area I’m flaky on is the signature for the updateSoundFiles function. All I want to do is be able to append to InfoncastSoundFiles a new SoundFile. Hope that makes sense.

Thanks for the help.

Still, there are some issues in your OP (original post) like typos, e.g. author instead of author1 and than SoundFile(title,creator,date,tags,url) and so on, so its difficult to solve your real issue.

So I just present the working code and let you find out the differences. If there are still questions about the code example below, don’t hesitate to ask:

using Dates
using JuliaWebAPI

mutable struct SoundFile
    title::String
    creator::String
    date::String
    tags::Array
    URL::String
end


const InfoncastSoundFiles = SoundFile[
  SoundFile("Fur Elise", "Ludwig Beethoven","12202019",["mp3","song", "music"],"https://URL Here"),
  SoundFile("Fidelio", "Ludwig Beethoven","11032011",["song", "dance"],"https://URL Here"),
  SoundFile("Missa Solemnis", "Ludwig Beethoven","03102019",["mp3", "song"], "https://URL Here")
]

function listSoundFiles()
	return InfoncastSoundFiles
end

function updateSoundFiles( ; title1=title1, author1=author1, date1=date1, tag1=tag1, url1=url1)
	push!(InfoncastSoundFiles,SoundFile(title1,author1,date1,[tag1],url1))
end


process(
    JuliaWebAPI.create_responder([
        (listSoundFiles, true),
        (updateSoundFiles, true)
    ], "tcp://127.0.0.1:9999", true, "")
)

I did not use the curl commands as they produce another issue on my side, which would only help for more confusion. I used two browser tabs with following URLs:

For the read:
http://localhost:8888/listSoundFiles

For the change of the data:
http://localhost:8888/updateSoundFiles?title1=Concerto&author1=Beethoven&date1=01102020&tag1=classical&url1=https://duckduckgo.com

Some notes:
Keyword arguments for functions start after a “;”:
https://docs.julialang.org/en/v1/manual/functions/#Keyword-Arguments-1
(This is the answer to your primary issue and question)

Your function updateSoundFiles didn’t change your array InfoncastSoundFiles, but only created another instance of struct SoundFile and returned it.

tag1 is a string, your struct expects an array, so it should be [tag1].

From

I get, that the URL parameters ( author=Beethoven, …) map to keyword arguments, non keyword arguments are passed via / in the URL path itself, for you this could have been:
http://localhost:8888/updateSoundFiles/Beethoven/01102020/...
In general in URLs the parameters starts with ? after the URL host and path and are concatenated with & , therefore this URL:
http://localhost:8888/updateSoundFiles?title1=Concerto&author1=Beethoven&date1=01102020&tag1=classical&url1=https://duckduckgo.com

And just in general: Try to copy paste the code from your first post above from here, not from your file, into a fresh Julia session and you will see, that this alone already is a problem. Try to make it as easy as possible for us to help you.

I realized that InfoncastSoundFiles is an array so updateSoundFiles should probably look like this:

function updateSoundFiles(InfoncastSoundFiles, title1, author, date1, tag1, url1)
    a = SoundFile(title1,author,date1,tag1,url1);
    #push!(InfoncastSoundFiles, a);
    append!(InfoncastSoundFiles, a);
    print(InfoncastSoundFiles);
end

Whether is push! or append! I’m not to clear on, but no matter what I still get the same error which lets me to believe the error I’m getting is from APIResponder in the JuliaWebAPI package.

A moving target here!
I try again. This is what you want:

function updateSoundFiles( ; title1=title1, author1=author1, date1=date1, tag1=tag1, url1=url1)
        a = SoundFile(title1,author1,date1,[tag1],url1)
	append!(InfoncastSoundFiles, a)
end

With this function, you can pass the parameters in the URL as:
http://host/path?title1=“xxx”&author1=“somebody”&
(see full example above)

The error is clearly from your code! What I posted in the previous answer does work as expected.

@oheil

Thank you so much. For some reason I didn’t even see your first response. I’ll try as you suggested and inform.

Thanks again for the help.

1 Like

@oheil It worked!!

Just as you said. I looked at the documentation for keyword arguments before, but I guess in that sentence I stopped at “optional” and missed the caveat that follow. Take a look Functions · The Julia Language

Like you, I was doing my tests via the browser prior to my post but decided to post here using curl, but what’s up with that? I had issues with curl as well even with your fix. Any idea what might be causing that?

In any case…
Color me <<whatever those that use Julia call themselves Julian?>> I’m a convert. I could’ve done this in Rust - Actix-web example contributor at one point - but wanted to force myself to do this in Julia and get a feel for the language as well as tools. More importantly, I’m delighted that the community is just as great to interface with as the language. Thank you.

My interests are in cybersec, AI and hardware so I’m sure you’ll see my tagname around more often in this forum.

2 Likes