This is Application Framework Layer for Hexaville
All Hexaville applications should be written in this framework.
import HexavilleFramework
let app = HexavilleFramework()
app.use(RandomNumberGenerateMiddleware())
let router = Router()
router.use(.get, "/") { request, context in
let htmlString = "<html><head><title>Hexaville</title></head><body>Welcome to Hexaville!</body></html>"
return Response(headers: ["Content-Type": "text/html"], body: htmlString)
}
app.use(router)
try app.run()
let app = HexavilleFramework()
let router = Router()
router.use(.get, "/hello") { response, context in
return Response(body: "Hello")
}
app.use(router)
let app = HexavilleFramework()
let router = Router()
router.use(.get, middlewares: [RandomNumberGenerateMiddleware()], "/hello") { response, context in
return Response(body: "Random number is \(context["randomNumber"])")
}
app.use(router)
You can create your own Middlewares to confirm Middleware
protocol.
enum JWTAuthenticationMiddleware {
case authrozationHeaderIsMissing
}
struct JWTAuthenticationMiddleware: Middleware {
func respond(to request: Request, context: ApplicationContext) throws -> Chainer {
guard let jwtString = request.headers["Authorization"] else {
throw JWTAuthenticationMiddleware.authrozationHeaderIsMissing
}
let jwt = try JWT.decode(jwtString)
context.memory["JWT"] = jwt
return .next(request)
}
}
app.use(JWTAuthenticationMiddleware())
ApplicationContext is the shared storage for the request.
- memory
- responseHeaders
- session
memory
property is used for share value between Middlewares and the Router.
struct FooMiddleware: Middleware {
func respond(to request: Request, context: ApplicationContext) throws -> Chainer {
context.memory["Foo"] = "Bar"
return .next(request)
}
}
app.use(.get, middlewares: [FooMiddleware()], "/foo") { request, context in
print(context["Foo"]) // Bar
}
In the some middlewares, You'll want to preset response headers, sunch as Set-Cookie
. By preseting HTTP headers into the responseHeaders
property, the header values are automatically adedd to the actual response on the Framework side.
Here is an example.
struct CookieSetMiddleware: Middleware {
func respond(to request: Request, context: ApplicationContext) throws -> Chainer {
context.responseHeaders["Set-Cookie"] = "vaild cookie value"
return .next(request)
}
}
app.use(.get, middlewares: [FooMiddleware()], "/foo") { request, context in
return Response(body: "OK")
}
HTTP/1.1 200
Set-Cookie: vaild cookie value
OK
session
property is used for data persistence that use in the application.
See Session for the detail.
HexavilleFramework provides Session Mechanism by SessionMiddleware
. You can create your own SessionStore to conform SessionStoreProvider
protocol.
Bundled Sesssion Store is MemoryStore
.
- MemoryStore: Bundled Session Store
- DynamoDBSessionStore
- RedisSessionStore
let session = SessionMiddleware(
cookieAttribute: CookieAttribute(
expiration: 3600,
httpOnly: true,
secure: false
),
store: MemoryStore()
)
app.use(session)
app.use { request, context in
// add value to session(memory)
context.session["user"] = User(name: "Luke", age: 25).serializeToJSONString()
}
var router = Router()
// take value from context.session
router.use(.get, "/") { request, context in
return Response(body: context.session["user"]!)
}
You can catch all of the errors that are throwed in the session with catch
error handler.
In the catch closure, the best way of the determining error response is pattern matching for the Error
.
let app = HexavilleFramework()
app.use(.....)
app.catch { error in
switch error {
case FooError.notFound:
return Response(status: .notFound)
case JWTAuthenticationMiddleware.authrozationHeaderIsMissing:
return Response(status: .unauthorized)
default:
return Response(status: .internalServerError)
}
}
try app.run()
See the Hexaville Documentation
You can debug your application with the builtin web server with serve
command.
YourApplication/.build/debug/YourApplication serve
# => Hexaville Builtin Server started at 0.0.0.0:3000
HexavilleFramework is released under the MIT license. See LICENSE for details.