Oxygen.jl
π¨ A breath of fresh air for programming web apps in Julia
Install / Use
/learn @OxygenFramework/Oxygen.jlREADME
Oxygen.jl
<!-- START HTML --> <div> </br> <p align="center"><img src="oxygen.png" width="20%"></p> <p align="center"> <strong>A breath of fresh air for programming web apps in Julia.</strong> </p> <p align="center"> <a href='https://juliahub.com/ui/Packages/General/Oxygen'><img src='https://juliahub.com/docs/General/Oxygen/stable/version.svg' alt='Version' /></a> <a href='https://oxygenframework.github.io/Oxygen.jl/stable/'><img src='https://img.shields.io/badge/docs-stable-blue.svg' alt='documentation stable' /></a> <a href='https://github.com/OxygenFramework/Oxygen.jl/actions/workflows/ci.yml'><img src='https://github.com/OxygenFramework/Oxygen.jl/actions/workflows/ci.yml/badge.svg' alt='Build Status' /></a> <a href='https://coveralls.io/github/OxygenFramework/Oxygen.jl?branch=master'><img src='https://coveralls.io/repos/github/OxygenFramework/Oxygen.jl/badge.svg?branch=master' alt='Coverage Status' /></a> <!-- <a href='https://codecov.io/gh/OxygenFramework/Oxygen.jl'><img src='https://codecov.io/gh/OxygenFramework/Oxygen.jl/branch/master/graph/badge.svg' alt='Coverage Status' /></a> --> </p> </div> <!-- END HTML -->About
Oxygen is a micro-framework built on top of the HTTP.jl library. Breathe easy knowing you can quickly spin up a web server with abstractions you're already familiar with.
Contact
Need Help? Feel free to reach out on our social media channels.
Features
- Straightforward routing
- Real-time Metrics Dashboard
- Auto-generated swagger documentation
- Out-of-the-box JSON serialization & deserialization (customizable)
- Type definition support for path parameters
- Request Extractors
- Application Context
- Multiple Instance Support
- Multithreading support
- Websockets, Streaming, and Server-Sent Events
- Cron Scheduling (on endpoints & functions)
- Middleware chaining (at the application, router, and route levels)
- Prebuilt Middleware (RateLimiter, Cors, BearerAuth)
- Static & Dynamic file hosting
- Hot reloads with Revise.jl
- Templating Support
- Plotting Support
- Protocol Buffer Support
- Route tagging
- Repeat tasks
Installation
pkg> add Oxygen
Minimalistic Example
Create a web-server with very few lines of code
using Oxygen
using HTTP
@get "/greet" function(req::HTTP.Request)
return "hello world!"
end
# start the web server
serve()
Handlers
Handlers are used to connect your code to the server in a clean & straightforward way. They assign a url to a function and invoke the function when an incoming request matches that url.
- Handlers can be imported from other modules and distributed across multiple files for better organization and modularity
- All handlers have equivalent macro & function implementations and support
do..endblock syntax - The type of first argument is used to identify what kind of handler is being registered
- This package assumes it's a
Requesthandler by default when no type information is provided
There are 3 types of supported handlers:
RequestHandlersStreamHandlersWebsocketHandlers
using HTTP
using Oxygen
# Request Handler
@get "/" function(req::HTTP.Request)
...
end
# Stream Handler
@stream "/stream" function(stream::HTTP.Stream)
...
end
# Websocket Handler
@websocket "/ws" function(ws::HTTP.WebSocket)
...
end
They are just functions which means there are many ways that they can be expressed and defined. Below is an example of several different ways you can express and assign a Request handler.
@get "/greet" function()
"hello world!"
end
@get("/gruessen") do
"Hallo Welt!"
end
@get "/saluer" () -> begin
"Bonjour le monde!"
end
@get "/saludar" () -> "Β‘Hola Mundo!"
@get "/salutare" f() = "ciao mondo!"
# This function can be declared in another module
function subtract(req, a::Float64, b::Float64)
return a - b
end
# register foreign request handlers like this
@get "/subtract/{a}/{b}" subtract
<details>
<summary><b>More Handler Docs</b></summary>
Request Handlers
Request handlers are used to handle HTTP requests. They are defined using macros or their function equivalents, and accept a HTTP.Request object as the first argument. These handlers support both function and do-block syntax.
- The default Handler when no type information is provided
- Routing Macros:
@get,@post,@put,@patch,@delete,@route - Routing Functions:
get(),post(),put(),patch(),delete(),route()
Stream Handlers
Stream handlers are used to stream data. They are defined using the @stream macro or the stream() function and accept a HTTP.Stream object as the first argument. These handlers support both function and do-block syntax.
@streamandstream()don't require a type definition on the first argument, they assume it's a stream.Streamhandlers can be assigned with standard routing macros & functions:@get,@post, etc- You need to explicitly include the type definition so Oxygen can identify this as a
Streamhandler
Websocket Handlers
Websocket handlers are used to handle websocket connections. They are defined using the @websocket macro or the websocket() function and accept a HTTP.WebSocket object as the first argument. These handlers support both function and do-block syntax.
@websocketandwebsocket()don't require a type definition on the first argument, they assume it's a websocket.Websockethandlers can also be assigned with the@getmacro orget()function, because the websocket protocol requires aGETrequest to initiate the handshake.- You need to explicitly include the type definition so Oxygen can identify this as a
Websockethandler
Routing Macro & Function Syntax
There are two primary ways to register your request handlers: the standard routing macros or the routing functions which utilize the do-block syntax.
For each routing macro, we now have a an equivalent routing function
@get -> get()
@post -> post()
@put -> put()
@patch -> patch()
@delete -> delete()
@route -> route()
The only practical difference between the two is that the routing macros are called during the precompilation stage, whereas the routing functions are only called when invoked. (The routing macros call the routing functions under the hood)
# Routing Macro syntax
@get "/add/{x}/{y}" function(request::HTTP.Request, x::Int, y::Int)
x + y
end
# Routing Function syntax
get("/add/{x}/{y}") do request::HTTP.Request, x::Int, y::Int
x + y
end
Render Functions
Oxygen, by default, automatically identifies the Content-Type of the return value from a request handler when building a Response. This default functionality is quite useful, but it does have an impact on performance. In situations where the return type is known, It's recommended to use one of the pre-existing render functions to speed things up.
Here's a list of the currently supported render functions:
html, text, json, file, xml, js, css, binary
Below is an example of how to use these functions:
using Oxygen
get("/html") do
html("<h1>Hello World</h1>")
end
get("/text") do
text("Hello World")
end
get("/json") do
json(Dict("message" => "Hello World"))
end
serve()
In most cases, these functions accept plain strings as inputs. The only exceptions are the binary function, which accepts a Vector{UInt8}, and the json function which accepts any serializable type.
- Each render function accepts a status and custom headers.
- The Content-Type and Content-Length headers are automatically set by these render functions
Path parameters
Path parameters are declared with braces and are passed directly to your request handler.
using Oxygen
# use path params without type definitions (defaults to Strings)
@get "/add/{a}/{b}" function(req, a, b)
return parse(Float64, a) + parse(Float64, b)
end
# use path params with type definitions (they are automatically converted)
@get "/multiply/{a}/{b}" function(req, a::Float64, b::Float64)
return a * b
end
# The order of the parameters doesn't matter (just the name matters)
@get "/subtract/{a}/{b}" function(req, b::Int64, a::Int64)
return a - b
end
# start the web server
serve()
Query parameters
Query parameters can be declared directly inside of your handlers signature. Any parameter that isn't mentioned inside the route path is assumed to be a query parameter.
- If a default value is not provided, it's assumed to be a required parameter
@get "/query" function(req::HTTP.Request, a::Int, message::String="hello world")
return (a, message)
end
Alternatively, you can use the queryparams() function to extract the raw values from the url as a dictionary.
@get "/query" function(req::HTTP.Request)
return queryparams(req)
end
HTML Forms
Use the formdata() function to extract and parse the form data from the body of a request. This function returns a dictionary of key-value pairs from the form
using Oxygen
# Setup a basic form
@get "/" function()
html("""
<form action="/form" method="post">
<label for="firstname">First name:</label><br>
<input type="text" id="firstname" name="firstname"><br>
<label for="lastname">Last name:</label><br>
<input type="text" id="lastname" name="lastname"><br><br>
<input type="submit" value="Submit">
</form>
""")
end
# Parse the form data and return it
@post "/form" function(req)
data = formdata(req)
return data
end
serve()
Return JSON
All objects are automatically
