I would like to build a REST API for a Julia code. I am currently evaluating whether I use also Julia to implement the REST server or if I use another language (e.g. Python) for the server part.
These are the package that I have seen so far:
HTTP.Servers (from HTTP.jl)
HttpServer.jl
Genie.jl
Mux.jl
Do you have any recommendations?
Personally, I like the style of the python library Flask. The julia code can take a long-time to run (hours). So the client will need to check periodically if the calculation is done. But it is important that the calculation should not block any new request.
I’m in the same boat. I’m currently setting up demos using the new HTTP.jl but it’s slow going (there’s not a lot of high-level documentation for it at the moment). In the short term it’s probably easier to build the API in Flask or similar and spawn Julia worker processes.
If you just need a couple of endpoints just to expose computations to the outer world, I’d go with HttpServer.jl - it’s very basic and low-level, but worked well for me a couple of times. If you need more complex routing, Mux.jl should a better fit. Genie.jl is more like Django in Python world: it’s server + ORM + templates, etc., for me it turned to be an overkill. No idea what HTTP.Server is about, so you’d need to figure it out yourself.
I recently updated Pages.jl to use the new / improved HTTP.jl. It might be something to consider for APIs (it’s what I made it for) and I’m happy to help out if you have questions.
We use JuliaWebAPI quite extensively to build REST servers. It is built on top of HTTPServer and Mux, and makes it easy to expose any julia function via a JSON based interface. For example, all of Juliabox’s internal APIs are built using this package. It is quite flexible, and extensible to other transports and message formats, if you need something other than HTTP and JSON respectively.
https://github.com/amellnik/Joseki.jl is an example of how you can make simple APIs with just HTTP.jl. In your case it’s probably easier to make the API in whatever to write the jobs to redis or similar and report on progress, and separately have a julia worker that processes them.
Although Mux.jl works fine for my latest project it seems like overkill since all I have to do is serve a static web page and respond to simple POST requests. So just yesterday I was wishing for more examples of doing simple stuff with HTTP.jl. Apparently I just willed this into existence.
I peaked around 6 kyu on kgs, and while I haven’t played seriously in a decade I got excited about the new AlphaGo joseki. I’ll add in an example of serving static content soon (although in my use cases I would always do that separately).
What were your conclusions regarding implementating restful API s in Julia? I’m currently doing all of this in flask but Would love to switch to Julia.
HTTP.jl is quite flexible and already quite complete for my needs. The syntax/API is not as short as in Flask but the code overhead is acceptable. Maybe registering function could be simplified by using do functions (like sinatra Sinatra: README ) or macros.
using Bukdu
using JSON
struct WelcomeController <: ApplicationController
conn::Conn
end
function index(c::WelcomeController)
render(JSON, "Hello World")
end
function process_resource(c::WelcomeController)
json = JSON.parse(String(c.conn.request.body))
@show json
render(JSON, json)
end
routes() do
get("/", WelcomeController, index)
post("/resource/process", WelcomeController, process_resource)
end
Bukdu.start(8080)
Base.JLOptions().isinteractive == 0 && wait()
How did your implementation handle multiple requests? I’m implementing something similar at the moment with Genie but the calculation is only on the order of 1-5 minutes and I’ve noticed it will block further requests.
I don’t use the REST server anymore, but I remember to have the same problem. You might want to try with @async or Threads.@spawn. There is more discussion here:
In the end, I had one HTTP request to start the long calculation, and another HTTP request to check if it is completed.
This is the correct implementation regardless of any asynchronous behavior. There may be elements between the client and server outside of your control that have relatively short timeouts that would disconnect a client waiting on a long computation.
Indeed, Oxygen.jl handels this case very well ! And the interface looks very lightweight and pleasant to use.
(for reference here is my test code: a call to e.g. /long/1 does not block a call to /short/1 )
# julia is started with
# julia -t4
using Oxygen, Dates, HTTP
function long(a)
t = Dates.now() + Dates.Minute(1)
while (t > Dates.now())
a = a+1
end
return a
end
@get "/long/{a}" function(req::HTTP.Request,a::Int)
@info "long"
return Dict("value" => long(a))
end
@get "/short/{a}" function(req::HTTP.Request,a::Int)
@info "short"
return Dict("value" => a)
end
serveparallel()
Thanks very much for getting back to me and including an example, really appreciate it. Oxygen indeed looks like quite a nice, simple solution - thanks.