So what I want to do: I want to build a julia package Foo.jl which should be used by users writing scripts in julia primarily. There’s also a secondary group of users who will want to use a subset of the package through a REST API.
This sounds mostly like a question of perspective. From my point of view it’s server.jl that happens to live within the Foo package and thus there’s nothing strange about using Foo. But then I would also start server.jl with
using Pkg
Pkg.activate(@__DIR__)
Pkg.instantiate()
On the other hand you’re using Julia 1.12, so the best practice would probably be to use the Pkg workspace feature to set up the api environment and package the REST api as a Pkg App.
I’d also heavily recommend using the @oxidise macro in your package.
If your consumers also have Oxygen.jl installed in the same project they’ll end up using the same internal state object - which will cause all routes to get registerd to the same instance.
This macro will create a new internal context object in the current module (and bind all stateful methods to it) instead of leveraging the global one and prevent any accidental collisions or overwrites.
module MyServer
using HTTP
using Oxygen; @oxidize
# now all the @get, @put, serve()... methods are bound to this module
export start, stop
# if we want to register routes outside of this module and have them bound to the same internal state, you'll need to add the exports to this module like this:
export @get, @post
@get "/" function()
return text("hello world")
end
start() = serve()
stop() = terminate()
end
Now somewhere else you can import your sever module and work with it
module Main
# only pull in the text helper method since @get is coming from the custom module
using Oxygen: text
# now we have access to the exported methods of the server
include("./MyServer.jl"); using .MyServer
# And we can register new routes on the same server instance outside of the file
@get "/custom" function()
return text("a custom endpoint")
end
start()
end