![GitHub license](https://img.shields.io/badge/license-LGPL v3-green.svg)
UPDATE March 2017: Swift Express is back on track and is Swift 3.x compatible. From now on we will suport the latest stable swift builds only. There is no release of the newest version done yet, though you can enjoy it from the "master" branch. Stay tuned. |
Version 0.3.x (current stable) notice: Current version works with Xcode 7.2, 7.3 and Linux DEV SNAPSHOT released on 03.01.2016. Upcoming version (0.4.x) will fully support Swift 3.0 and will maintain compatibility with Swift 2.2 (Xcode 7.3). Stay tuned by following us on social networks. |
First make sure, please, you have followed the installation section steps.
swift-express init HelloExpress
cd HelloExpress
swift-express bootstrap
open HelloExpress.xcodeproj
app.get("/myecho") { request in
.ok(request.query["message"]?.first)
}
swift-express build
swift-express run
Test it in the browser: http://localhost:9999/myecho?message=Hello
xcode-select --install
in terminalbrew tap crossroadlabs/tap
brew install swift-express
Create a project as it is described in the getting started section. Now you can start playing with examples.
All the examples can be found in Demo
project inside the main repo.
app.get("/hello") { request in
.ok(AnyContent(str: "<h1>Hello Express!!!</h1>", contentType: "text/html"))
}
Launch the app and follow the link: http://localhost:9999/hello?message=Hello
If you don't know what this is you might want to better skip it for now to the next section: URL params. To get more information see this first. We have our APIs based on Future pattern. Our implementation is based on BrightFutures, thanks @Thomvis!
Express can handle it both ways. All your syncronous code will be executed in a separate queue in a traditional way, so if you are a fan of this approach - it will work (like in "Hello Express" example above).
Still if you want to benefit from asynchronicity, we provide a very powerful API set that accepts futures as result of your handler.
Let's assume you have following function somewhere:
func calcFactorial(num:Double) -> Future<Double, AnyError>
it's a purely asyncronous function that returns future. It would be really nice if it could be handled asynchronously as well in a nice functional way. Here is an example of how it could be done.
// (request -> Future<Action<AnyContent>, AnyError> in) - this is required to tell swift you want to return a Future
// hopefully inference in swift will get better eventually and just "request in" will be enough
app.get("/factorial/:num(\\d+)") { request -> Future<Action<AnyContent>, AnyError> in
// get the number from the url
let num = request.params["num"].flatMap{Double($0)}.getOrElse(0)
// get the factorial Future. Returns immediately - non-blocking
let factorial = calcFactorial(num)
//map the result of future to Express Action
let future = factorial.map { fac in
Action.ok(String(fac))
}
//return the future
return future
}
Let's get our echo example from Getting Started a bit further. Our routing engine, which is largely based on NodeJS analog path-to-regex. You can read the complete documentation on how to use path patterns here. Now an example with URL param:
//:param - this is how you define a part of URL you want to receive through request object
app.get("/echo/:param") { request in
//here you get the param from request: request.params["param"]
.ok(request.params["param"])
}
app.get("/:file+", action: StaticAction(path: "public", param:"file"))
The code above tells Express to serve all static files from the public folder recursively. If you want to serve just the first level in folder, use:
app.get("/:file", action: StaticAction(path: "public", param:"file"))
The difference is just in the pattern: /:file
versus /:file+
. For more information see our routing section.
First of all we need to register the JSON view in the system:
//now we can refer to this view by name
app.views.register(JsonView())
Let's say we want to build a simple API for users registration. We want our API consumers to POST
to /api/user
a JSON object and get a JSON
response back.
app.post("/api/user") { request in
//check if JSON has arrived
guard let json = request.body?.asJSON() else {
return Action.ok("Invalid request")
}
//check if JSON object has username field
guard let username = json["username"].string else {
return Action.ok("Invalid request")
}
//compose the response as a simple dictionary
let response =
["status": "ok",
"description": "User with username '" + username + "' created succesfully"]
//render disctionary as json (remember the one we've registered above?)
return .render(JsonView.name, context: response)
}
Lines above will do the job. Post this JSON
:
{
"username": "swiftexpress"
}
to our api URL: http://localhost:9999/api/user
(don't forget application/json
content type header) and you will get this response:
{
"status": "ok",
"description": "User with username 'swiftexpress' created succesfully"
}
First of all you need to switch the template engine on:
//we recommend mustache template engine
app.views.register(StencilViewEngine())
Now create a file called hello.stencil
in the views
directory:
<html>
<body>
<h1>Hello from Stencil: {{user}}</h1>
</body>
</html>
Add a new request handler:
//user as an url param
app.get("/hello/:user.html") { request in
//get user
let user = request.params["user"]
//if there is a user - create our context. If there is no user, context will remain nil
let context = user.map {["user": $0]}
//render our template named "hello"
return .render("hello", context: context)
}
Now follow the link to see the result: http://localhost:9999/hello/express.html
Swift essentially is a new generation programming language combining simplicity and all the modern stuff like functional programming.
We were inspired (and thus influenced) mainly by two modern web frameworks: Express.js and Play. So, we are trying to combine the best of both worlds taking simplicity from Express.js and modern robust approach of Play
Let us know if we are on the right path! Influence the project, create feature requests, API change requests and so on. While we are in our early stages, it's easy to change. We are open to suggestions!
v0.4: Swift 3.0
v0.3: linux support
v0.2.1: minor changes
v0.2: Solid OS X release
v0.1: Initial Public Release
To get started, sign the Contributor License Agreement.