vapor - 优雅的Swift Web框架
Vapor
一个受 Laravel/Lumen 启发的Swift Web 框架,可用于iOS, OS X, 和Ubuntu。
- Insanely fast
- Beautiful syntax
- Type safe
Getting Started
Clone the Example project to start making your application or check out the live demo running on Ubuntu. This repository is for the framework module.
You can also download the alpha Vapor Installer, which allows you to create a new project at the command line e.g. vapor new MyProject
You must have Swift 2.2 or later installed. You can learn more about Swift 2.2 at Swift.org
Want to make a pull request? You can learn how from this free series How to Contribute to an Open Source Project on GitHub
Work in Progress
This is a work in progress, so don't rely on this for anything important. And pull requests are welcome!
Wiki
Visit the Vapor Wiki for extensive documentation on using and contributing to Vapor.
Server
Starting the server takes two lines.
main.swift
import Vapor let server = Server() server.run()
You can also choose which port the server runs on.
server.run(port: 8080)
If you are having trouble connecting, make sure your ports are open. Check out apt-get ufw
for simple port management.
Routing
Routing in Vapor is simple and very similar to Laravel.
main.swift
Route.get("welcome") { request in return "Hello" } //...start server
Here we will respond to all requests to http://example.com/welcome
with the string "Hello"
.
JSON
Responding with JSON is easy.
Route.get("version") { request in return ["version": "1.0"] }
This responds to all requests to http://example.com/version
with the JSON dictionary {"version": "1.0"}
and Content-Type: application/json
.
Views
You can also respond with HTML pages.
Route.get("/") { request in return View(path: "index.html") }
Or Stencil templates.
index.stencil
<html> <h1>{{ message }}</h1> </html>
Route.get("/") { request in return View(path: "index.stencil", context: ["message": "Hello"]) }
If you have VaporStencil
added, just put the View file in the Resources
folder at the root of your project and it will be served.
Stencil
To add VaporStencil
, add the following package to your Package.swift
.
Package.swift
.Package(url: "https://github.com/tannernelson/vapor-stencil.git", majorVersion: 0)
Then set the StencilRenderer()
on your View.renderers
for whatever file extensions you would like to be rendered as Stencil
templates.
main.swift
import VaporStencil //set the stencil renderer //for all .stencil files View.renderers[".stencil"] = StencilRenderer()
Response
A manual response can be returned if you want to set something like cookies
.
Route.get("cookie") { request in let response = Response(status: .OK, text: "Cookie was set") response.cookies["test"] = "123" return response }
The Status enum above (.OK
) can be one of the following.
public enum Status { case OK, Created, Accepted case MovedPermanently case BadRequest, Unauthorized, Forbidden, NotFound case ServerError case Unknown case Custom(Int) }
Or something custom.
let status: Status = .Custom(420) //https://dev.推ter.com/overview/api/response-codes
Public
All files put in the Public
folder at the root of your project will be available at the root of your domain. This is a great place to put your assets (.css
, .js
, .png
, etc).
Request
Every route call gets passed a Request
object. This can be used to grab query and path parameters.
This is a list of the properties available on the request object.
let method: Method var parameters: [String: String] //URL parameters like id in user/:id var data: [String: String] //GET or POST data var cookies: [String: String] var session: Session
Session
Sessions will be kept track of using the vapor-session
cookie. The default (and currently only) session driver is .Memory
.
if let name = request.session.data["name"] { //name was in session } //store name in session request.session.data["name"] = "Vapor"
Database
Vapor was designed alongside Fluent, an Eloquent inspired ORM that empowers simple and expressive database management.
import Fluent if let user = User.find(5) { print("Found \(user.name)") user.name = "New Name" user.save() }
Underlying Fluent is a powerful Query builder.
let user = Query<User>().filter("id", notIn: [1, 2, 3]).filter("age", .GreaterThan, 21).first
Controllers
Controllers are great for keeping your code organized. Route
directives can take whole controllers or controller methods as arguments instead of closures.
main.swift
Route.get("heartbeat", closure: HeartbeatController().index)
To pass a function name as a closure like above, the closure must have the function signature
func index(request: Request) -> ResponseConvertible
Here is an example of a controller for returning an API heartbeat.
HearbeatController.swift
import Vapor class HeartbeatController: Controller { override func index(request: Request) -> AnyObject { return ["lub": "dub"] } }
Here the HeartbeatControllers
's index method will be called when http://example.com/heartbeat/alternate
is visited.
Resource Controllers
Resource controllers take advantage of CRUD-like index
, show
, store
, update
, destroy
methods to make setting up REST APIs easy.
Route.resource("user", controller: UserController())
This will create the appropriate GET
, POST
, DELETE
, etc methods for individual and groups of users.
Middleware
Create a class conforming to Middleware
to hook into server requests and responses. Append your classes to the server.middleware
array in the order you want them to run..
class MyMiddleware: Middleware { func handle(handler: Request -> Response) -> (Request -> Response) { return { request in print("Incoming request from \(request.address)") let response = handler(request) print("Responding with status \(response.status)") return response } } } server.middleware.append(MyMiddleware())
Async
Use the AsyncResponse
to send custom, asynchronous responses. You have full control over the response here, meaning you are responsible for writing all required headers and releasing the Socket
when done. (Thanks @elliottminns)
Route.get("async") { request in return AsyncResponse() { socket in try socket.writeUTF8("HTTP/1.1 200 OK\r\n") try socket.writeUTF8("Content-Type: application/json\r\n\r\n") try socket.writeUTF8("{\"hello\": \"world\"}") socket.release() } }
Hash
Vapor currently supports SHA1
hashes.
let hello = Hash.make("world")
For added security, set a custom applicationKey
on the Hash
class.
Hash.applicationKey = "my-secret-key"
Deploying
Vapor has been successfully tested on Ubuntu 14.04 LTS (DigitalOcean) and Ubuntu 15.10 (VirtualBox).
DigitalOcean
To deploy to DigitalOcean, simply
- Install Swift 2.2
wget
the .tar.gz from Apple- Set the
export PATH
in your~/.bashrc
- (you may need to install
binutils
as well if you seear not found
)
- Clone your fork of the
vapor-example
repository to the server cd
into the repository- Run
swift build
- Run
.build/debug/MyApp
- (you may need to run as
sudo
to use certain ports) - (you may need to install
ufw
to set appropriate ports)
- Run
Upstart
To start your Vapor
site automatically when the server is booted, add this file to your server.
/etc/init/vapor-example.conf
description "Vapor Example" start on startup exec /home/<user_name>/vapor-example/.build/release/VaporApp --workDir=/home/<user_name>/vapor-example
You additionally have access to the following commands for starting and stopping your server.
sudo stop vapor-example sudo start vapor-example
The following script is useful for upgrading your website.
git pull swift build --configuration release sudo stop vapor-example sudo start vapor-example
Heroku
To deploy on Heroku, one can use Kyle Fuller's Heroku buildpack which works out of the box with the vapor-example
.
My website http://tanner.xyz
is currently running using Vapor.
Attributions
This project is based on Swifter by Damian Kołakowski. It uses compatibility code from NSLinux by johnno1962.
Go checkout and star their repos.