Oxygen adalah kerangka mikro yang dibangun di atas pustaka http.jl. Bernapaslah dengan mudah mengetahui Anda dapat dengan cepat memutar server web dengan abstraksi yang sudah Anda kenal.
Butuh bantuan? Jangan ragu untuk menjangkau saluran media sosial kami.
pkg > add OxygenBuat server web dengan sangat sedikit baris kode
using Oxygen
using HTTP
@get " /greet " function (req :: HTTP.Request )
return " hello world! "
end
# start the web server
serve ()Penangan digunakan untuk menghubungkan kode Anda ke server dengan cara yang bersih & langsung. Mereka menetapkan URL ke fungsi dan memohon fungsi ketika permintaan yang masuk cocok dengan URL itu.
do..end sintaks blokRequest secara default ketika tidak ada informasi jenis yang disediakanAda 3 jenis penangan yang didukung:
Request penanganStreamWebsocket 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 Mereka hanyalah fungsi yang berarti ada banyak cara yang dapat diekspresikan dan didefinisikan. Di bawah ini adalah contoh dari beberapa cara berbeda yang dapat Anda ungkapkan dan berikan penangan Request .
@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 Penangan permintaan digunakan untuk menangani permintaan HTTP. Mereka didefinisikan menggunakan makro atau ekuivalen fungsinya, dan menerima objek HTTP.Request sebagai argumen pertama. Penangan ini mendukung sintaks fungsi dan do-block.
@get , @post , @put , @patch , @delete , @routeget() , post() , put() , patch() , delete() , route() Penangan aliran digunakan untuk melakukan streaming data. Mereka didefinisikan menggunakan fungsi @stream macro atau stream() dan menerima objek HTTP.Stream sebagai argumen pertama. Penangan ini mendukung sintaks fungsi dan do-block.
@stream dan stream() tidak memerlukan definisi tipe pada argumen pertama, mereka menganggap itu aliran.Stream dapat ditugaskan dengan macro & fungsi routing standar: @get , @post , dllStream Penangan Websocket digunakan untuk menangani koneksi Websocket. Mereka didefinisikan menggunakan fungsi @websocket atau fungsi websocket() dan menerima objek HTTP.WebSocket sebagai argumen pertama. Penangan ini mendukung sintaks fungsi dan do-block.
@websocket dan websocket() tidak memerlukan definisi tipe pada argumen pertama, mereka menganggap itu adalah Websocket.Websocket juga dapat ditetapkan dengan fungsi @get makro atau get() , karena protokol WebSocket memerlukan permintaan GET untuk memulai jabat tangan.Websocket Ada dua cara utama untuk mendaftarkan penangan permintaan Anda: makro perutean standar atau fungsi perutean yang memanfaatkan sintaks DO-blok.
Untuk setiap makro perutean, kami sekarang memiliki fungsi perutean yang setara
@get -> get ()
@post -> post ()
@put -> put ()
@patch -> patch ()
@delete -> delete ()
@route -> route ()Satu -satunya perbedaan praktis antara keduanya adalah bahwa makro perutean dipanggil selama tahap prekompilasi, sedangkan fungsi perutean hanya dipanggil saat dipanggil. (Makro perutean memanggil fungsi perutean di bawah kap)
# 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 Oksigen, secara default, secara otomatis mengidentifikasi tipe konten dari nilai pengembalian dari penangan permintaan saat membangun respons. Fungsi default ini cukup berguna, tetapi memang berdampak pada kinerja. Dalam situasi di mana tipe pengembalian diketahui, disarankan untuk menggunakan salah satu fungsi render yang sudah ada sebelumnya untuk mempercepat.
Berikut daftar fungsi render yang saat ini didukung: html , text , json , file , xml , js , css , binary
Di bawah ini adalah contoh cara menggunakan fungsi -fungsi ini:
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 () Dalam kebanyakan kasus, fungsi -fungsi ini menerima string polos sebagai input. Satu -satunya pengecualian adalah fungsi binary , yang menerima Vector{UInt8} , dan fungsi json yang menerima jenis serial apa pun.
Parameter jalur dinyatakan dengan kawat gigi dan diteruskan langsung ke penangan permintaan Anda.
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 ()Parameter kueri dapat dinyatakan langsung di dalam tanda tangan penangan Anda. Parameter apa pun yang tidak disebutkan di dalam jalur rute diasumsikan sebagai parameter kueri.
@get " /query " function (req :: HTTP.Request , a :: Int , message :: String = " hello world " )
return (a, message)
end Atau, Anda dapat menggunakan fungsi queryparams() untuk mengekstrak nilai mentah dari URL sebagai kamus.
@get " /query " function (req :: HTTP.Request )
return queryparams (req)
end Gunakan fungsi formdata() untuk mengekstrak dan menguraikan data formulir dari badan permintaan. Fungsi ini mengembalikan kamus pasangan nilai kunci dari formulir
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 ()Semua objek secara otomatis deserialized ke JSON menggunakan pustaka JSON3
using Oxygen
using HTTP
@get " /data " function (req :: HTTP.Request )
return Dict ( " message " => " hello! " , " value " => 99.3 )
end
# start the web server
serve ()Oksigen menyediakan beberapa serialisasi & deserialisasi di luar kotak untuk sebagian besar objek tetapi membutuhkan penggunaan structtypes saat mengonversi structs
using Oxygen
using HTTP
using StructTypes
struct Animal
id :: Int
type :: String
name :: String
end
# Add a supporting struct type definition so JSON3 can serialize & deserialize automatically
StructTypes . StructType ( :: Type{Animal} ) = StructTypes . Struct ()
@get " /get " function (req :: HTTP.Request )
# serialize struct into JSON automatically (because we used StructTypes)
return Animal ( 1 , " cat " , " whiskers " )
end
@post " /echo " function (req :: HTTP.Request )
# deserialize JSON from the request body into an Animal struct
animal = json (req, Animal)
# serialize struct back into JSON automatically (because we used StructTypes)
return animal
end
# start the web server
serve ()Oksigen hadir dengan beberapa ekstraktor bawaan yang dirancang untuk mengurangi jumlah boilerplate yang dibutuhkan untuk membuat serial input ke fungsi penangan Anda. Dengan hanya mendefinisikan struct dan menentukan sumber data, ekstraktor ini merampingkan proses konsumsi & validasi data melalui API yang seragam.
payload@kwdefEkstraktor yang didukung:
Path - Ekstrak dari parameter jalurQuery - Ekstrak dari parameter kueri,Header - Ekstrak dari header permintaanForm - mengekstrak data formulir dari badan permintaanBody - Serial seluruh Badan Permintaan ke jenis yang diberikan (string, float64, dll.)ProtoBuffer - Mengekstrak pesan ProtoBuf dari badan permintaan (tersedia melalui ekstensi paket)Json - mengekstrak json dari badan permintaanJsonFragment - mengekstrak "fragmen" dari tubuh JSON menggunakan nama parameter untuk mengidentifikasi dan mengekstrak kunci tingkat atas yang sesuai Dalam contoh ini kami menunjukkan bahwa ekstraktor Path dapat digunakan bersama parameter jalur biasa. Ini juga berfungsi dengan parameter kueri biasa dan ekstraktor Query .
struct Add
b :: Int
c :: Int
end
@get " /add/{a}/{b}/{c} " function (req, a :: Int , pathparams :: Path{Add} )
add = pathparams . payload # access the serialized payload
return a + add . b + add . c
end Nilai default dapat diatur dengan struct menggunakan makro @kwdef .
@kwdef struct Pet
name :: String
age :: Int = 10
end
@post " /pet " function (req, params :: Json{Pet} )
return params . payload # access the serialized payload
end Di atas serialisasi data yang masuk, Anda juga dapat menentukan aturan validasi Anda sendiri dengan menggunakan fungsi validate . Dalam contoh di bawah ini kami menunjukkan cara menggunakan validator global dan local dalam kode Anda.
global sebelum menjalankan validator local . import Oxygen : validate
struct Person
name :: String
age :: Int
end
# Define a global validator
validate (p :: Person ) = p . age >= 0
# Only the global validator is ran here
@post " /person " function (req, newperson :: Json{Person} )
return newperson . payload
end
# In this case, both global and local validators are ran (this also makes sure the person is age 21+)
# You can also use this sytnax instead: Json(Person, p -> p.age >= 21)
@post " /adult " function (req, newperson = Json {Person} (p -> p . age >= 21 ))
return newperson . payload
end Anda dapat menginterpolasi variabel langsung ke jalur, yang membuat rute mendaftarkan secara dinamis menjadi mudah
(Terima kasih kepada @ANANDIJAIN untuk idenya)
using Oxygen
operations = Dict ( " add " => + , " multiply " => * )
for (pathname, operator) in operations
@get " / $pathname /{a}/{b} " function (req, a :: Float64 , b :: Float64 )
return operator (a, b)
end
end
# start the web server
serve () Fungsi router() adalah HOF (fungsi urutan yang lebih tinggi) yang memungkinkan Anda untuk menggunakan kembali awalan & properti jalur yang sama di beberapa titik akhir. Ini sangat membantu ketika API Anda mulai tumbuh dan Anda ingin menjaga operasi jalur Anda tetap teratur.
Di bawah ini adalah argumen yang dapat diambil oleh fungsi router() :
router (prefix :: String ; tags :: Vector , middleware :: Vector , interval :: Real , cron :: String )tags - digunakan untuk mengatur titik akhir dalam dokumen yang diotogenerasimiddleware - digunakan untuk menyiapkan router rute & middleware khusus ruteinterval - digunakan untuk mendukung tindakan berulang ( memanggil penangan permintaan pada interval yang ditetapkan dalam hitungan detik )cron - digunakan untuk menentukan ekspresi cron yang menentukan kapan harus memanggil penangan permintaan. using Oxygen
# Any routes that use this router will be automatically grouped
# under the 'math' tag in the autogenerated documenation
math = router ( " /math " , tags = [ " math " ])
# You can also assign route specific tags
@get math ( " /multiply/{a}/{b} " , tags = [ " multiplication " ]) function (req, a :: Float64 , b :: Float64 )
return a * b
end
@get math ( " /divide/{a}/{b} " ) function (req, a :: Float64 , b :: Float64 )
return a / b
end
serve ()Oksigen hadir dengan sistem penjadwalan cron bawaan yang memungkinkan Anda untuk memanggil titik akhir dan fungsi secara otomatis ketika ekspresi cron cocok dengan waktu saat ini.
Ketika sebuah pekerjaan dijadwalkan, tugas baru dibuat dan dijalankan di latar belakang. Setiap tugas menggunakan ekspresi cron yang diberikan dan waktu saat ini untuk menentukan berapa lama perlu tidur sebelum dapat dijalankan.
Parser cron dalam oksigen didasarkan pada spesifikasi yang sama dengan yang digunakan di musim semi. Anda dapat menemukan informasi lebih lanjut tentang ini di halaman Spring Cron Expressions.
Berikut ini adalah rincian dari apa yang diwakili oleh setiap parameter dalam ekspresi cron kami. Sementara spesifikasi kami sangat mirip dengan yang ditentukan oleh Spring, itu bukan pertandingan 1-ke-1 yang tepat.
The string has six single space-separated time and date fields:
┌───────────── second (0-59)
│ ┌───────────── minute (0 - 59)
│ │ ┌───────────── hour (0 - 23)
│ │ │ ┌───────────── day of the month (1 - 31)
│ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC)
│ │ │ │ │ ┌───────────── day of the week (1 - 7)
│ │ │ │ │ │ (Monday is 1, Tue is 2... and Sunday is 7)
│ │ │ │ │ │
* * * * * *
Ekspresi parsial juga didukung, yang berarti bahwa ekspresi selanjutnya dapat ditinggalkan (mereka default ke '*' ).
# In this example we see only the `seconds` part of the expression is defined.
# This means that all following expressions are automatically defaulted to '*' expressions
@cron " */2 " function ()
println ( " runs every 2 seconds " )
end Fungsi router() memiliki argumen kata kunci yang disebut cron , yang menerima ekspresi cron yang menentukan kapan titik akhir dipanggil. Sama seperti argumen kata kunci lainnya, dapat digunakan kembali dengan titik akhir yang berbagi router atau ditimpa oleh titik akhir yang diwariskan.
# execute at 8, 9 and 10 o'clock of every day.
@get router ( " /cron-example " , cron = " 0 0 8-10 * * * " ) function (req)
println ( " here " )
end
# execute this endpoint every 5 seconds (whenever current_seconds % 5 == 0)
every5 = router ( " /cron " , cron = " */5 " )
# this endpoint inherits the cron expression
@get every5 ( " /first " ) function (req)
println ( " first " )
end
# Now this endpoint executes every 2 seconds ( whenever current_seconds % 2 == 0 ) instead of every 5
@get every5 ( " /second " , cron = " */2 " ) function (req)
println ( " second " )
end Selain menjadwalkan titik akhir, Anda juga dapat menggunakan @cron makro baru untuk menjadwalkan fungsi. Ini berguna jika Anda ingin menjalankan kode pada waktu tertentu tanpa membuatnya terlihat atau dapat dipanggil di API.
@cron " */2 " function ()
println ( " runs every 2 seconds " )
end
@cron " 0 0/30 8-10 * * * " function ()
println ( " runs at 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day " )
end Saat Anda menjalankan serve() atau serveparallel() , semua pekerjaan cron terdaftar secara otomatis dimulai. Jika server dihentikan atau dibunuh, semua pekerjaan yang berjalan juga akan diakhiri. Anda dapat menghentikan server dan semua tugas berulang dan pekerjaan cron dengan memanggil fungsi terminate() atau membunuh server secara manual dengan ctrl+C .
Selain itu, oksigen menyediakan fungsi utilitas untuk memulai dan menghentikan pekerjaan cron secara manual: startcronjobs() dan stopcronjobs() . Fungsi -fungsi ini juga dapat digunakan di luar server web.
Tugas Ulangi memberikan API sederhana untuk menjalankan fungsi pada interval yang ditetapkan.
Ada dua cara untuk mendaftarkan tugas berulang:
interval dalam router()@repeat Penting untuk dicatat bahwa meminta penangan yang menggunakan properti ini tidak dapat menentukan parameter fungsi tambahan di luar parameter HTTP.Request default.
Dalam contoh di bawah ini, titik akhir /repeat/hello disebut setiap 0,5 detik dan "hello" dicetak ke konsol setiap kali.
Fungsi router() memiliki parameter interval yang digunakan untuk memanggil penangan permintaan pada interval yang ditetapkan (dalam detik).
using Oxygen
taskrouter = router ( " /repeat " , interval = 0.5 , tags = [ " repeat " ])
@get taskrouter ( " /hello " ) function ()
println ( " hello " )
end
# you can override properties by setting route specific values
@get taskrouter ( " /bonjour " , interval = 1.5 ) function ()
println ( " bonjour " )
end
serve ()Di bawah ini adalah contoh cara mendaftarkan tugas berulang di luar router
@repeat 1.5 function ()
println ( " runs every 1.5 seconds " )
end
# you can also "name" a repeat task
@repeat 5 " every-five " function ()
println ( " runs every 5 seconds " )
end Ketika server dijalankan, semua tugas dimulai secara otomatis. Tetapi modul ini juga menyediakan utilitas untuk memiliki kontrol yang lebih halus atas tugas yang sedang berjalan menggunakan fungsi berikut: starttasks() , stoptasks() , dan cleartasks()
Oksigen dapat berintegrasi dengan revisi untuk memberikan pemuatan ulang panas, mempercepat pengembangan. Karena revisi merekomendasikan untuk menjaga semua kode untuk direvisi dalam paket, Anda pertama -tama harus pindah ke tata letak jenis ini.
Pertama, pastikan Project.toml Anda.toml memiliki bidang yang diperlukan seperti name untuk mengerjakan paket daripada proyek.
Selanjutnya, tulis kode utama untuk Anda rute dalam modul src/MyModule.jl :
module MyModule
using Oxygen; @oxidise
@get "/greet" function(req::HTTP.Request)
return "hello world!"
end
end
Kemudian Anda dapat membuat skrip entri debug.jl :
using Revise
using Oxygen
using MyModule
MyModule.serve(revise=:eager)
Opsi revise juga dapat diatur ke :lazy , dalam hal ini revisi akan selalu dibiarkan sebelum permintaan dilayani, daripada dicoba dengan penuh semangat ketika file sumber berubah pada disk.
Perhatikan bahwa Anda harus menjalankan skrip titik entri lain tanpa merevisi dalam produksi.
Dalam beberapa skenario canggih, Anda mungkin perlu memutar beberapa Web Severs dalam modul yang sama pada port yang berbeda. Oxygen menyediakan cara statis dan dinamis untuk membuat beberapa contoh server web.
Sebagai aturan praktis umum, jika Anda tahu berapa banyak contoh yang Anda butuhkan sebelumnya, yang terbaik adalah menggunakan pendekatan statis.
@oxidiseOxygen menyediakan makro baru yang memungkinkan untuk mengatur dan menjalankan beberapa contoh. Ini menghasilkan metode dan mengikatnya ke keadaan internal baru untuk modul saat ini.
Dalam contoh di bawah ini, dua server sederhana didefinisikan dalam modul A dan B dan dimulai dalam modul induk. Kedua modul berisi semua fungsi yang diekspor dari oksigen yang dapat dipanggil secara langsung seperti yang ditunjukkan di bawah ini.
module A
using Oxygen; @oxidise
get ( " / " ) do
text ( " server A " )
end
end
module B
using Oxygen; @oxidise
get ( " / " ) do
text ( " server B " )
end
end
try
# start both instances
A . serve (port = 8001 , async = true )
B . serve (port = 8002 , async = false )
finally
# shut down if we `Ctrl+C`
A . terminate ()
B . terminate ()
endinstance() Fungsi instance membantu Anda membuat instance yang sepenuhnya independen dari server web oksigen saat runtime. Ini bekerja dengan secara dinamis membuat modul Julia saat runtime dan memuat kode oksigen di dalamnya.
Semua metode yang sama dari oksigen tersedia di bawah instance bernama. Dalam contoh di bawah ini kita dapat menggunakan get , dan serve hanya dengan menggunakan sintaks dot pada variabel app1 untuk mengakses metode yang mendasarinya.
using Oxygen
# ######## Setup the first app #########
app1 = instance ()
app1 . get ( " / " ) do
text ( " server A " )
end
# ######## Setup the second app #########
app2 = instance ()
app2 . get ( " / " ) do
text ( " server B " )
end
# ######## Start both instances #########
try
# start both servers together
app1 . serve (port = 8001 , async = true )
app2 . serve (port = 8002 )
finally
# clean it up
app1 . terminate ()
app2 . terminate ()
end Untuk skenario di mana Anda perlu menangani jumlah lalu lintas yang lebih tinggi, Anda dapat menjalankan oksigen dalam mode multithreaded. Untuk memanfaatkan mode ini, Julia harus memiliki lebih dari 1 utas untuk dikerjakan. Anda dapat memulai sesi Julia dengan 4 utas menggunakan perintah di bawah ini
julia --threads 4 serveparallel() memulai server web dalam mode streaming dan menangani permintaan dalam pendekatan multitasking yang kooperatif. Fungsi ini menggunakan Threads.@spawn untuk menjadwalkan tugas baru di utas apa pun yang tersedia. Sementara itu, @Async digunakan di dalam tugas ini saat memanggil setiap penangan permintaan. Ini memungkinkan tugas menghasilkan selama operasi I/O.
using Oxygen
using StructTypes
using Base . Threads
# Make the Atomic struct serializable
StructTypes . StructType ( :: Type{Atomic{Int64}} ) = StructTypes . Struct ()
x = Atomic {Int64} ( 0 );
@get " /show " function ()
return x
end
@get " /increment " function ()
atomic_add! (x, 1 )
return x
end
# start the web server in parallel mode
serveparallel () Oksigen termasuk ekstensi untuk paket Protobuf.jl. Ekstensi ini menyediakan fungsi protobuf() , menyederhanakan proses bekerja dengan buffer protokol dalam konteks server web. Untuk pemahaman yang lebih baik tentang paket ini, silakan merujuk ke dokumentasi resminya.
Fungsi ini memiliki kelebihan muatan untuk skenario berikut:
using HTTP
using ProtoBuf
using Oxygen
# The generated classes need to be created ahead of time (check the protobufs)
include ( " people_pb.jl " );
using . people_pb : People, Person
# Decode a Protocol Buffer Message
@post " /count " function (req :: HTTP.Request )
# decode the request body into a People object
message = protobuf (req, People)
# count the number of Person objects
return length (message . people)
end
# Encode & Return Protocol Buffer message
@get " /get " function ()
message = People ([
Person ( " John Doe " , 20 ),
Person ( " Alice " , 30 ),
Person ( " Bob " , 35 )
])
# seralize the object inside the body of a HTTP.Response
return protobuf (message)
endBerikut ini adalah contoh skema yang digunakan untuk membuat ikatan Julia yang diperlukan. Binding ini memungkinkan pengkodean dan penguraian pesan dalam contoh di atas.
syntax = "proto3" ;
message Person {
string name = 1 ;
sint32 age = 2 ;
}
message People {
repeated Person people = 1 ;
} Oksigen dilengkapi dengan beberapa ekstensi paket yang meningkatkan kemampuan merencanakannya. Ekstensi ini memudahkan untuk mengembalikan plot langsung dari penangan permintaan. Semua operasi dilakukan dalam memori menggunakan iobuffer dan mengembalikan HTTP.Response
Paket yang didukung dan util penolong mereka:
png , svg , pdf , htmlhtmlhtml using CairoMakie : heatmap
using Oxygen
@get " /cairo " function ()
fig, ax, pl = heatmap ( rand ( 50 , 50 ))
png (fig)
end
serve () using Bonito
using WGLMakie : heatmap
using Oxygen
using Oxygen : html # Bonito also exports html
@get " /wgl " function ()
fig = heatmap ( rand ( 50 , 50 ))
html (fig)
end
serve () using Bonito
using WGLMakie : heatmap
using Oxygen
using Oxygen : html # Bonito also exports html
@get " /bonito " function ()
app = App () do
return DOM . div (
DOM . h1 ( " Random 50x50 Heatmap " ),
DOM . div ( heatmap ( rand ( 50 , 50 )))
)
end
return html (app)
end
serve () Daripada membangun mesin internal untuk templating OteraEngine.jl menambahkan dependensi tambahan, oksigen menyediakan dua ekstensi paket untuk mendukung Mustache.jl .
Oxygen menyediakan API pembungkus sederhana di sekitar kedua paket yang membuatnya mudah untuk membuat templat dari string, templat, dan file. API pembungkus ini mengembalikan fungsi render yang menerima kamus input untuk mengisi templat.
Dalam semua skenario, templat yang diberikan dikembalikan di dalam objek http.response yang siap dilayani oleh API. Secara default, tipe MIME terdeteksi secara otomatis baik dengan melihat konten templat atau nama ekstensi pada file. Jika Anda tahu jenis MIME, Anda dapat meneruskannya langsung melalui argumen kata kunci mime_type untuk melewatkan proses deteksi.
Silakan lihat dokumentasi kumis.jl untuk mempelajari kemampuan lengkap paket
Contoh 1: Menghadapi templat kumis dari file
using Mustache
using Oxygen
# Load the Mustache template from a file and create a render function
render = mustache ( " ./templates/greeting.txt " , from_file = false )
@get " /mustache/file " function ()
data = Dict ( " name " => " Chris " )
return render (data) # This will return an HTML.Response with the rendered template
endContoh 2: Menentukan jenis mime untuk template kumis string polos
using Mustache
using Oxygen
# Define a Mustache template (both plain strings and mustache templates are supported)
template_str = " Hello, {{name}}! "
# Create a render function, specifying the MIME type as text/plain
render = mustache (template_str, mime_type = " text/plain " ) # mime_type keyword arg is optional
@get " /plain/text " function ()
data = Dict ( " name " => " Chris " )
return render (data) # This will return a plain text response with the rendered template
endSilakan lihat dokumentasi OteraEngine.jl untuk mempelajari kemampuan lengkap paket
Contoh 1: Rendering template OTera dengan logika dan loop
using OteraEngine
using Oxygen
# Define an Otera template
template_str = """
<html>
<head><title>{{ title }}</title></head>
<body>
{% for name in names %}
Hello {{ name }}<br>
{% end %}
</body>
</html>
"""
# Create a render function for the Otera template
render = otera (template_str)
@get " /otera/loop " function ()
data = Dict ( " title " => " Greetings " , " names " => [ " Alice " , " Bob " , " Chris " ])
return render (data) # This will return an HTML.Response with the rendered template
endDalam contoh ini, template OTERA didefinisikan dengan for-loop yang mengulangi daftar nama, menyapa setiap nama.
Contoh 2: Menjalankan Kode Julia di Template Otera
using OteraEngine
using Oxygen
# Define an Otera template with embedded Julia code
template_str = """
The square of {{ number }} is {< number^2 >}.
"""
# Create a render function for the Otera template
render = otera (template_str)
@get " /otera/square " function ()
data = Dict ( " number " => 5 )
return render (data) # This will return an HTML.Response with the rendered template
end
Dalam contoh ini, templat OTERA didefinisikan dengan kode julia tertanam yang menghitung kuadrat dari nomor yang diberikan.
Anda dapat memasang file statis menggunakan fungsi praktis ini yang secara rekursif mencari folder untuk file dan memasang semuanya. Semua file dimuat ke dalam memori saat startup.
using Oxygen
# mount all files inside the "content" folder under the "/static" path
staticfiles ( " content " , " static " )
# start the web server
serve ()Mirip dengan staticFiles, fungsi ini memasang setiap jalur dan membaca ulang file untuk setiap permintaan. Ini berarti bahwa setiap perubahan pada file setelah server dimulai akan ditampilkan.
using Oxygen
# mount all files inside the "content" folder under the "/dynamic" path
dynamicfiles ( " content " , " dynamic " )
# start the web server
serve () Menonaktifkan penebang internal dapat memberikan beberapa keuntungan kinerja besar -besaran, yang dapat membantu dalam beberapa skenario. Secara anekdot, saya telah melihat speedup 2-3x dalam serve() dan speedup 4-5x dalam kinerja serveparallel() .
# This is how you disable internal logging in both modes
serve (access_log = nothing )
serveparallel (access_log = nothing ) Oxygen menyediakan format logging default tetapi memungkinkan Anda untuk menyesuaikan format menggunakan parameter access_log . Fungsionalitas ini tersedia dalam fungsi serve() dan serveparallel() .
Anda dapat membaca lebih lanjut tentang opsi logging di sini
# Uses the default logging format
serve ()
# Customize the logging format
serve (access_log = logfmt " [$time_iso8601] " $request " $status " )
# Disable internal request logging
serve (access_log = nothing )Fungsi Middleware memudahkan membuat alur kerja khusus untuk mencegat semua permintaan yang masuk dan tanggapan keluar. Mereka dieksekusi dalam urutan yang sama mereka dilewatkan (dari kiri ke kanan).
Mereka dapat diatur di aplikasi, router, dan lapisan rute dengan argumen kata kunci middleware . Semua middleware adalah aditif dan setiap middleware yang ditentukan dalam lapisan ini akan digabungkan dan dieksekusi.
Middleware akan selalu dieksekusi dalam urutan berikut:
application -> router -> route
Sekarang mari kita lihat beberapa middleware beraksi:
using Oxygen
using HTTP
const CORS_HEADERS = [
" Access-Control-Allow-Origin " => " * " ,
" Access-Control-Allow-Headers " => " * " ,
" Access-Control-Allow-Methods " => " POST, GET, OPTIONS "
]
# https://juliaweb.github.io/HTTP.jl/stable/examples/#Cors-Server
function CorsMiddleware (handler)
return function (req :: HTTP.Request )
println ( " CORS middleware " )
# determine if this is a pre-flight request from the browser
if HTTP . method (req) == " OPTIONS "
return HTTP . Response ( 200 , CORS_HEADERS)
else
return handler (req) # passes the request to the AuthMiddleware
end
end
end
function AuthMiddleware (handler)
return function (req :: HTTP.Request )
println ( " Auth middleware " )
# ** NOT an actual security check ** #
if ! HTTP . headercontains (req, " Authorization " , " true " )
return HTTP . Response ( 403 )
else
return handler (req) # passes the request to your application
end
end
end
function middleware1 (handle)
function (req)
println ( " middleware1 " )
handle (req)
end
end
function middleware2 (handle)
function (req)
println ( " middleware2 " )
handle (req)
end
end
# set middleware at the router level
math = router ( " math " , middleware = [middleware1])
# set middleware at the route level
@get math ( " /divide/{a}/{b} " , middleware = [middleware2]) function (req, a :: Float64 , b :: Float64 )
return a / b
end
# set application level middleware
serve (middleware = [CorsMiddleware, AuthMiddleware])Jika Anda tidak ingin menggunakan serializer respons default oksigen, Anda dapat mematikannya dan menambahkan sendiri! Cukup buat fungsi middleware khusus Anda sendiri untuk membuat serial respons dan menambahkannya di ujung rantai middleware Anda sendiri.
Baik serve() dan serveparallel() memiliki argumen kata kunci serialize yang dapat mematikan serializer default.
using Oxygen
using HTTP
using JSON3
@get " /divide/{a}/{b} " function (req :: HTTP.Request , a :: Float64 , b :: Float64 )
return a / b
end
# This is just a regular middleware function
function myserializer (handle)
function (req)
try
response = handle (req)
# convert all responses to JSON
return HTTP . Response ( 200 , [], body = JSON3 . write (response))
catch error
@error " ERROR: " exception = (error, catch_backtrace ())
return HTTP . Response ( 500 , " The Server encountered a problem " )
end
end
end
# make sure 'myserializer' is the last middleware function in this list
serve (middleware = [myserializer], serialize = false )Dokumentasi Swagger secara otomatis dihasilkan untuk setiap rute yang Anda daftarkan di aplikasi Anda. Hanya nama rute, jenis parameter, dan respons 200 & 500 yang secara otomatis dibuat untuk Anda secara default.
Anda dapat melihat dokumentasi yang Anda hasilkan di /docs , dan skema dapat ditemukan di bawah /docs/schema . Kedua nilai ini dapat diubah menjadi apa pun yang Anda inginkan menggunakan fungsi configdocs() . Anda juga dapat memilih keluar dari dokumen autogenerasi sepenuhnya dengan memanggil fungsi disabledocs() sebelum memulai aplikasi Anda.
Untuk menambahkan detail tambahan, Anda dapat menggunakan fungsi bawaan mergeschema() atau setschema() untuk secara langsung memodifikasi skema sendiri atau menggabungkan skema yang dihasilkan dari paket SwaggerMarkdown.jl (saya akan merekomendasikan yang terakhir)
Di bawah ini adalah contoh cara menggabungkan skema yang dihasilkan dari paket SwaggerMarkdown.jl .
using Oxygen
using SwaggerMarkdown
# Here's an example of how you can merge autogenerated docs from SwaggerMarkdown.jl into your api
@swagger """
/divide/{a}/{b}:
get:
description: Return the result of a / b
parameters:
- name: a
in: path
required: true
description: this is the value of the numerator
schema:
type : number
responses:
'200':
description: Successfully returned an number.
"""
@get " /divide/{a}/{b} " function (req, a :: Float64 , b :: Float64 )
return a / b
end
# title and version are required
info = Dict ( " title " => " My Demo Api " , " version " => " 1.0.0 " )
openApi = OpenAPI ( " 3.0 " , info)
swagger_document = build (openApi)
# merge the SwaggerMarkdown schema with the internal schema
mergeschema (swagger_document)
# start the web server
serve ()Di bawah ini adalah contoh cara memodifikasi skema secara manual
using Oxygen
using SwaggerMarkdown
# Only the basic information is parsed from this route when generating docs
@get " /multiply/{a}/{b} " function (req, a :: Float64 , b :: Float64 )
return a * b
end
# Here's an example of how to update a part of the schema yourself
mergeschema ( " /multiply/{a}/{b} " ,
Dict (
" get " => Dict (
" description " => " return the result of a * b "
)
)
)
# Here's another example of how to update a part of the schema yourself, but this way allows you to modify other properties defined at the root of the schema (title, summary, etc.)
mergeschema (
Dict (
" paths " => Dict (
" /multiply/{a}/{b} " => Dict (
" get " => Dict (
" description " => " return the result of a * b "
)
)
)
)
) @get (path, func)| Parameter | Jenis | Keterangan |
|---|---|---|
path | string atau router() | Diperlukan . Rute untuk mendaftar |
func | function | Diperlukan . Penangan permintaan untuk rute ini |
Digunakan untuk mendaftarkan fungsi ke titik akhir tertentu untuk menangani jenis permintaan yang sesuai
@route (methods, path, func)| Parameter | Jenis | Keterangan |
|---|---|---|
methods | array | Diperlukan . Jenis permintaan HTTP untuk mendaftar ke rute ini |
path | string atau router() | Diperlukan . Rute untuk mendaftar |
func | function | Diperlukan . Penangan permintaan untuk rute ini |
Makro tingkat rendah yang memungkinkan rute menangani beberapa jenis permintaan
staticfiles (folder, mount)| Parameter | Jenis | Keterangan |
|---|---|---|
folder | string | Diperlukan . Folder untuk melayani file dari |
mountdir | string | Titik akhir root untuk memasang file di bawah (default adalah "statis") |
set_headers | function | Kustomisasi header respons HTTP saat mengembalikan file -file ini |
loadfile | function | Kustomisasi perilaku saat memuat file |
Sajikan semua file statis dalam satu folder. Fungsi ini secara rekursif mencari direktori dan memasang semua file di bawah Direktori Mount menggunakan jalur relatifnya.
dynamicfiles (folder, mount)| Parameter | Jenis | Keterangan |
|---|---|---|
folder | string | Diperlukan . Folder untuk melayani file dari |
mountdir | string | Titik akhir root untuk memasang file di bawah (default adalah "statis") |
set_headers | function | Kustomisasi header respons HTTP saat mengembalikan file -file ini |
loadfile | function | Kustomisasi perilaku saat memuat file |
Sajikan semua file statis dalam satu folder. Fungsi ini secara rekursif mencari direktori dan memasang semua file di bawah Direktori Mount menggunakan jalur relatifnya. File dimuat pada setiap permintaan, berpotensi mengambil perubahan file apa pun.
html (content, status, headers)| Parameter | Jenis | Keterangan |
|---|---|---|
content | string | Diperlukan . String yang akan dikembalikan sebagai html |
status | integer | Kode Respons HTTP (default adalah 200) |
headers | dict | Header untuk respons HTTP (default memiliki header tipe konten yang diatur ke "Teks/html; charset = UTF-8") |
Fungsi helper untuk ditunjuk saat konten harus dikembalikan sebagai html
queryparams (request)| Parameter | Jenis | Keterangan |
|---|---|---|
req | HTTP.Request | Diperlukan . Objek Permintaan HTTP |
Mengembalikan parameter kueri dari permintaan sebagai dikte ()
text (request)| Parameter | Jenis | Keterangan |
|---|---|---|
req | HTTP.Request | Diperlukan . Objek Permintaan HTTP |
Mengembalikan tubuh permintaan sebagai string
binary (request)| Parameter | Jenis | Keterangan |
|---|---|---|
req | HTTP.Request | Diperlukan . Objek Permintaan HTTP |
Mengembalikan tubuh permintaan sebagai file biner (mengembalikan vektor UInt8 s)
json (request, classtype)| Parameter | Jenis | Keterangan |
|---|---|---|
req | HTTP.Request | Diperlukan . Objek Permintaan HTTP |
classtype | struct | Sebuah struct untuk menghapus objek JSON ke |
Deserialize tubuh permintaan ke struct julia