Fastro
Fast and simple web application framework for deno. With near-native perfomance, you can manage your routing, middlewares, and dependencies cleanly. You can also take advantage of existing Deno objects and methods: Request, Response, Headers, and Cookie.
Examples
- Getting Started
- Custom Port
- JSON Response
- JSON with Native Response
- JSON with Fastro Response
- HTML with Native Response
- HTML with Fastro Response
- HTML with JSX
- Server Side Rendering (SSR)
- Render with Eta Template Engine
- Cookie with Native Response
- Cookie with Fastro Response
- Set Content Type
- Set HTTP Status
- Set Authorization
- Routing
- Route Parameters
- Router Middleware
- Router Middleware with Array
- Application Level Middleware
- Application Level Middleware with Array
- Route Level Middleware
- Route Level Middleware with Array
- SQLite and Dependency Injection
Getting started
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => "Hello world")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/main.ts
Custom port
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => "Hello world!")
await app.serve({ port: 3000 })
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/custom_port.ts
JSON Response
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
const json = { text: "Hello world" }
app.get("/", () => json)
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/json_response_default.ts
JSON with Native Response
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => {
const json = { text: "Hello world" }
return new Response(JSON.stringify(json), {
status: 200,
headers: {
"content-type": "application/json",
},
})
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/response_json_native.ts
JSON with Fastro Response
import application, { response } from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => response().json({ text: "Hello world" }))
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/response_json.ts
HTML with Native Response
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => {
return new Response("<html> Hello world </html>", {
status: 200,
headers: {
"content-type": "text/html",
},
})
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/html_response.ts
HTML with Fastro Response
import application, { response } from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => response().html("<h2>Hello world</h2>"))
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/response_html.ts
HTML with JSX
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => <h1>Hello world</h1>)
console.log("Listening on: http://localhost:8000")
await app.serve()
deno.json
tsconfig: {
"compilerOptions": {
"strict": true,
"jsx": "react-jsx",
"jsxImportSource": "https://esm.sh/react"
}
}
deno run -A --unstable --config deno.json https://deno.land/x/fastro@v0.55.0/examples/jsx_response.tsx
Set Content Type
import application, { response } from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => {
const res = response()
return res.contentType("application/json")
.send(JSON.stringify({ msg: "Hello world" }))
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/response_content_type.ts
Set HTTP Status
import application, { response } from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => {
const res = response()
return res.status(200).send("status")
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/response_status.ts
Set Authorization
import application, { response } from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/", () => {
const res = response()
return res.authorization("Basic YWxhZGRpbjpvcGVuc2VzYW1l")
.send("Basic auth")
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/response_auth.ts
Cookie with Native Response
import {
Cookie,
deleteCookie,
getCookies,
setCookie,
} from "https://deno.land/std@0.133.0/http/cookie.ts"
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/set", () => {
const headers = new Headers()
const cookie: Cookie = { name: "Space", value: "Cat" }
setCookie(headers, cookie)
return new Response(JSON.stringify(cookie), {
headers
})
})
app.get("/delete", () => {
const headers = new Headers()
deleteCookie(headers, "Space")
const cookies = getCookies(headers)
return new Response(JSON.stringify(cookies), {
headers,
})
})
app.get("/check", (req: Request) => {
const cookie = getCookies(req.headers)
return new Response(JSON.stringify(cookie))
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/cookies.ts
Cookie with Fastro Response
import application, {
Cookie,
getCookies,
response,
} from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/set", () => {
const cookie: Cookie = { name: "Space", value: "Cat" }
return response()
.setCookie(cookie)
.send(JSON.stringify(cookie))
})
app.get("/delete", () => {
return response()
.deleteCookie("Space")
.send("Cookie deleted")
})
app.get("/check", (req: Request) => {
const cookie = getCookies(req.headers)
return response().send(JSON.stringify(cookie))
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/response_cookies.ts
Render with Eta Template Engine
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
import { render } from "https://deno.land/x/eta@1.12.3/mod.ts"
const app = application()
const headers = new Headers()
headers.set("Content-Type", "text/html charset=UTF-8")
app.get("/", () => {
const html = <string> render(
"<h4>The answer to everything is <%= it.answer %></h4>",
{
answer: 42,
},
)
return new Response(html, { headers })
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/render.ts
Routing
import application from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/abcd", () => new Response("/abcd"))
app.get("/ef?gh", () => new Response("/ef?gh"))
app.get("/ij+kl", () => new Response("/ij+kl"))
app.get("/mn*op", () => new Response("mn*op"))
app.get("/qr(st)?u", () => new Response("qr(st)?u"))
app.get(/v/, () => new Response("/v/"))
app.get(/.*fast$/, () => new Response("/.*fast$/"))
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/routing.ts
Route parameters
import application, {
getParam,
getParams,
} from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.get("/:id/user/:name", (req: Request) => {
const params = getParams(req)
return new Response(JSON.stringify({ params }))
})
app.get("/post/:id", (req: Request) => {
const param = getParam("id", req)
return new Response(param)
})
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/route_params.ts
Router Middleware
import application, {
ConnInfo,
Next,
router,
} from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
const r = router()
const middleware = (_req: Request, _connInfo: ConnInfo, next: Next) => {
console.log("v2 - 1")
next()
}
r.get("/", () => new Response("Get"))
.post("/", () => new Response("Post"))
.put("/", () => new Response("Put"))
.delete("/", () => new Response("Delete"))
app.use("/v1", r)
app.use("/v2", middleware, r)
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/router_middleware.ts
Router Middleware with Array
import application, {
ConnInfo,
Next,
router,
} from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
const r = router()
const middlewares = [(_req: Request, _connInfo: ConnInfo, next: Next) => {
console.log("v2 - 1")
next()
}, (_req: Request, _connInfo: ConnInfo, next: Next) => {
console.log("v2 - 2")
next()
}]
r.get("/", () => new Response("Get"))
.post("/", () => new Response("Post"))
.put("/", () => new Response("Put"))
.delete("/", () => new Response("Delete"))
app.use("/v1", r)
app.use("/v2", middlewares, r)
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/router_middleware_with_array.ts
Application Level Middleware
import application, {
ConnInfo,
Next,
} from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
app.use((_req: Request, _conn: ConnInfo, next: Next) => {
console.log("app middleware #1")
next()
})
app.use((_req: Request, _conn: ConnInfo, next: Next) => {
console.log("app middleware #2")
next()
})
app.use((_req: Request, _conn: ConnInfo, next: Next) => {
console.log("app middleware #3")
next()
}, (_req: Request, _conn: ConnInfo, next: Next) => {
console.log("app middleware #4")
next()
})
app.get("/", () => new Response("App level #1"))
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/application_level_middleware.ts
Application Level Middleware with Array
import application, {
ConnInfo,
Next,
} from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
const middlewares = [(_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #1")
next()
}, (_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #2")
next()
}, (_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #3")
next()
}, (_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #4")
next()
}]
app.use(middlewares)
app.get("/", () => new Response("App level #1"))
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/application_level_middleware_with_array.ts
Route Level Middleware
import application, {
ConnInfo,
Next,
} from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
const middlewares = (_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #1")
next()
}
app.get("/", middlewares, () => new Response("App level #1"))
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/route_level_middleware.ts
Route Level Middleware with Array
import application, {
ConnInfo,
Next,
} from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
const app = application()
const middlewares = [(_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #1")
next()
}, (_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #2")
next()
}, (_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #3")
next()
}, (_req: Request, _conn: ConnInfo, next: Next) => {
console.log("middleware #4")
next()
}]
app.get("/mnop", middlewares, () => new Response("Route level middleware #3"))
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/route_level_middleware_with_array.ts
SQLite and Dependency Injection
import application, { dependency } from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
import { DB } from "https://deno.land/x/sqlite@3.3.0/mod.ts"
const app = application()
const db = new DB("test.db")
const deps = dependency()
deps.set("hello", () => "Hello world")
deps.set("db", db)
app.use(deps)
app.get("/", () => {
type FunctionType = () => string
const fn = <FunctionType> app.getDeps("hello")
return new Response(fn())
})
app.post("/name", () => {
const db = <DB> app.getDeps("db")
db.query(`CREATE TABLE IF NOT EXISTS people (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT)`)
const names = ["Peter Parker", "Clark Kent", "Bruce Wayne"]
for (const name of names) {
db.query("INSERT INTO people (name) VALUES (?)", [name])
}
return new Response(JSON.stringify(names))
})
app.get("/name", () => {
const db = <DB> app.getDeps("db")
const res = db.query("SELECT name FROM people")
return new Response(JSON.stringify(res))
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno run -A --unstable https://deno.land/x/fastro@v0.55.0/examples/deps_injection.ts
Server Side Rendering
Component
Create react component: app.tsx
import React from "https://esm.sh/react@17.0.2"
const App = () => {
const [count, setCount] = React.useState(0)
return (
<div>
<h1>Hello Deno Land!</h1>
<button onClick={() => setCount(count + 1)}>Click the 🦕</button>
<p>You clicked the 🦕 {count} times</p>
</div>
)
}
export default App
SSR Hydration
Create react hydration: hydrate.tsx
. See: hydrate.
import React from "https://esm.sh/react@17.0.2"
import ReactDOM from "https://esm.sh/react-dom@17.0.2"
import App from "./app.tsx"
ReactDOM.hydrate(
<App />,
//@ts-ignore: used by Deno.emit
document.getElementById("root")
)
Endpoint
Create routing file: api.tsx
import application, { response } from "https://deno.land/x/fastro@v0.55.0/server/mod.ts"
import App from "./app.tsx"
const app = application()
const hydratePath = "./examples/ssr/hydrate.tsx"
app.get("/", () => {
return response().ssr(<App />, hydratePath)
})
console.log("Listening on: http://localhost:8000")
await app.serve()
deno.json
tsconfig: {
"compilerOptions": {
"strict": true,
"jsx": "react-jsx",
"jsxImportSource": "https://esm.sh/react"
}
}
How to run locally
deno run -A --unstable api.tsx