Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion moon.mod.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "oboard/mocket",
"version": "0.5.8",
"version": "0.6.0",
"deps": {
"illusory0x0/native": "0.2.1",
"moonbitlang/x": "0.4.34",
Expand Down
48 changes: 0 additions & 48 deletions src/body_reader.mbt → src/content_type.mbt
Original file line number Diff line number Diff line change
@@ -1,51 +1,3 @@
///|
pub suberror BodyError {
InvalidJsonCharset
InvalidJson
InvalidText
}

///|
fn read_body(
req_headers : Map[StringView, StringView],
body_bytes : BytesView,
) -> HttpBody raise BodyError {
let content_type = req_headers.get("Content-Type")
if content_type is Some(content_type) {
let content_type = parse_content_type(content_type)
if content_type is Some(content_type) {
return match content_type {
{ subtype: "json", .. } => {
let json = @encoding/utf8.decode(body_bytes) catch {
_ => raise BodyError::InvalidJsonCharset
}
Json(@json.parse(json) catch { _ => raise BodyError::InvalidJson })
}
{ media_type: "text", .. } =>
Text(
@encoding/utf8.decode(body_bytes) catch {
_ => raise BodyError::InvalidText
},
)
{ subtype: "x-www-form-urlencoded", .. } =>
Form(parse_form_data(body_bytes))
{ subtype: "form-data" | "multipart", params, .. } => {
let boundary = match params.get("boundary") {
Some(b) => Some(b)
None => params.get("BOUNDARY")
}
match boundary {
Some(b) => Multipart(parse_multipart(body_bytes, b.to_string()))
None => Bytes(body_bytes)
}
}
_ => Bytes(body_bytes)
}
}
}
Bytes(body_bytes)
}

///|
priv struct ContentType {
media_type : StringView
Expand Down
2 changes: 1 addition & 1 deletion src/cors/cors.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub fn handle_cors(
max_age~,
)
// 对于预检请求,直接返回空响应,不调用next()
@mocket.Empty
@mocket.HttpResponse::new(OK).to_responder()
} else {
append_cors_headers(
event,
Expand Down
2 changes: 1 addition & 1 deletion src/cors/pkg.generated.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn append_cors_headers(@mocket.MocketEvent, origin? : String, methods? : String,

fn append_cors_preflight_headers(@mocket.MocketEvent, origin? : String, methods? : String, allow_headers? : String, credentials? : Bool, max_age? : Int) -> Unit

fn handle_cors(origin? : String, methods? : String, allow_headers? : String, expose_headers? : String, credentials? : Bool, max_age? : Int) -> async (@mocket.MocketEvent, async () -> @mocket.HttpBody noraise) -> @mocket.HttpBody noraise
fn handle_cors(origin? : String, methods? : String, allow_headers? : String, expose_headers? : String, credentials? : Bool, max_age? : Int) -> async (@mocket.MocketEvent, async () -> &@mocket.Responder noraise) -> &@mocket.Responder noraise

fn is_preflight_request(@mocket.MocketEvent) -> Bool

Expand Down
4 changes: 2 additions & 2 deletions src/examples/cookie/main.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ fn main {
app.get("/", e => {
e.res.set_cookie("session_id", "12345", max_age=3600)
if e.req.get_cookie("session_id") is Some(session_id) {
Text(session_id.value)
session_id.value
} else {
Text("No session_id")
"No session_id"
}
})

Expand Down
65 changes: 65 additions & 0 deletions src/examples/responder/main.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
///|
using @mocket {type HttpResponse}

///|
struct Person {
name : String
age : Int
} derive(ToJson, FromJson)

///|
impl @mocket.BodyReader for Person with from_request(req) -> Person raise {
@json.from_json(req.body())
}

///|
fn main {
let app = @mocket.new()

// Text Response
app
..get("/", _event => "⚡️ Tadaa!")

// Object Response
..get("/json", _event => { name: "oboard", age: 21 }.to_json())

// JSON Request
// curl --location 'localhost:4000/json' \
// --header 'Content-Type: application/json' \
// --data '{
// "name": "oboard",
// "age": 21
// }'
..post("/json", event => try {
let person : Person = event.req.body()
HttpResponse::new(OK).body(
"Hello, \{person.name}. You are \{person.age} years old.",
)
} catch {
_ => HttpResponse::new(BadRequest).body("Invalid JSON")
})

// Echo Server
..post("/echo", e => e.req)

// 404 Page
..get("/404", _ => HttpResponse::new(NotFound).body(
@mocket.html(
(
#|<html>
#|<body>
#| <h1>404</h1>
#|</body>
#|</html>
),
),
))

// Print Server URL
for path in app.mappings.keys() {
println("\{path.0} http://localhost:4000\{path.1}")
}

// Serve
app.serve(port=4000)
}
4 changes: 4 additions & 0 deletions src/examples/responder/moon.pkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"is-main": true,
"import": ["oboard/mocket"]
}
20 changes: 20 additions & 0 deletions src/examples/responder/pkg.generated.mbti
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Generated using `moon info`, DON'T EDIT IT
package "oboard/mocket/examples/responder"

import(
"moonbitlang/core/json"
)

// Values

// Errors

// Types and methods
type Person
impl ToJson for Person
impl @json.FromJson for Person

// Type aliases

// Traits

58 changes: 30 additions & 28 deletions src/examples/route/main.mbt
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
///|
fn main {
let app = @mocket.new(logger=@mocket.new_production_logger())
let app = @mocket.new()

// Register global middleware
app
..use_middleware((event, next) => {
println("📝 Request: \{event.req.http_method} \{event.req.url}")
next()
})
..use_middleware(logger_middleware)
..use_middleware(@cors.handle_cors())

// Text Response
..get("/", _event => Text("⚡️ Tadaa!"))
..get("/", _event => "⚡️ Tadaa!")

// Hello World
..on("GET", "/hello", _ => Text("Hello world!"))
..on("GET", "/hello", _ => "Hello world!")
..group("/api", group => {
// 添加组级中间件
group.use_middleware((event, next) => {
Expand All @@ -23,61 +20,54 @@ fn main {
)
next()
})
group.get("/hello", _ => Text("Hello world!"))
group.get("/json", _ => Json({
"name": "John Doe",
"age": 30,
"city": "New York",
}))
group.get("/hello", _ => "Hello world!")
group.get("/json", _ => (
{ "name": "John Doe", "age": 30, "city": "New York" } : Json))
})

// JSON Response
..get("/json", _event => Json({
"name": "John Doe",
"age": 30,
"city": "New York",
}))
..get("/json", _event => (
{ "name": "John Doe", "age": 30, "city": "New York" } : Json))

// Async Response
..get("/async_data", async fn(_event) noraise {
Json({ "name": "John Doe", "age": 30, "city": "New York" })
({ "name": "John Doe", "age": 30, "city": "New York" } : Json)
})

// Dynamic Routes
// /hello2/World = Hello, World!
..get("/hello/:name", event => {
let name = event.params.get("name").unwrap_or("World")
Text("Hello, \{name}!")
"Hello, \{name}!"
})
// /hello2/World = Hello, World!
..get("/hello2/*", event => {
let name = event.params.get("_").unwrap_or("World")
Text("Hello, \{name}!")
"Hello, \{name}!"
})

// Wildcard Routes
// /hello3/World/World = Hello, World/World!
..get("/hello3/**", event => {
let name = event.params.get("_").unwrap_or("World")
Text("Hello, \{name}!")
"Hello, \{name}!"
})

// Echo Server
..post("/echo", e => e.req.body)
..post("/echo", e => e.req)

// 404 Page
..get("/404", e => {
e.res.status_code = 404
HTML(
..get("/404", _ => @mocket.HttpResponse::new(NotFound).body(
@mocket.html(
(
#|<html>
#|<body>
#| <h1>404</h1>
#|</body>
#|</html>
),
)
})
),
))

// Print Server URL
for path in app.mappings.keys() {
Expand All @@ -87,3 +77,15 @@ fn main {
// Serve
app.serve(port=4000)
}

///|
pub async fn logger_middleware(
event : @mocket.MocketEvent,
next : async () -> &@mocket.Responder noraise,
) -> &@mocket.Responder noraise {
let start_time = @env.now()
let res = next()
let duration = @env.now() - start_time
println("\{event.req.http_method} \{event.req.url} - \{duration}ms")
res
}
5 changes: 5 additions & 0 deletions src/examples/route/pkg.generated.mbti
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// Generated using `moon info`, DON'T EDIT IT
package "oboard/mocket/examples/route"

import(
"oboard/mocket"
)

// Values
async fn logger_middleware(@mocket.MocketEvent, async () -> &@mocket.Responder noraise) -> &@mocket.Responder noraise

// Errors

Expand Down
30 changes: 30 additions & 0 deletions src/examples/static_assets/main.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
///|
fn main {
let app = @mocket.new()
app.use_middleware(logger_middleware)
// Register global middleware
app.static_assets("/", @static_file.new("./"))

// Text Response
app.get("/", _event => "⚡️ Tadaa!")

// Print Server URL
for path in app.mappings.keys() {
println("\{path.0} http://localhost:4000\{path.1}")
}

// Serve
app.serve(port=4000)
}

///|
pub async fn logger_middleware(
event : @mocket.MocketEvent,
next : async () -> &@mocket.Responder noraise,
) -> &@mocket.Responder noraise {
let start_time = @env.now()
let res = next()
let duration = @env.now() - start_time
println("\{event.req.http_method} \{event.req.url} - \{duration}ms")
res
}
7 changes: 7 additions & 0 deletions src/examples/static_assets/moon.pkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"is-main": true,
"import": [
"oboard/mocket",
"oboard/mocket/static_file"
]
}
18 changes: 18 additions & 0 deletions src/examples/static_assets/pkg.generated.mbti
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Generated using `moon info`, DON'T EDIT IT
package "oboard/mocket/examples/static_assets"

import(
"oboard/mocket"
)

// Values
async fn logger_middleware(@mocket.MocketEvent, async () -> &@mocket.Responder noraise) -> &@mocket.Responder noraise

// Errors

// Types and methods

// Type aliases

// Traits

Loading