Giter Club home page Giter Club logo

blackfish's Introduction

Blackfish

A Node/Express Inspired Web Framework for Swift that works on iOS, OS X, and Ubuntu.

Travis Badge Join the chat at https://gitter.im/elliottminns/blackfish codebeat

  • Insanely fast
  • Single Threaded
  • Beautiful syntax
  • Type safe
  • Powered by Echo & libdispatch
  • Running on Heroku

##News

Blackfish 0.8 is here, faster than ever. Blackfish uses libdispatch at it's core, allowing for safe and fast non-blocking I/O.

Table of Contents

Getting Started

You must have Swift 3.0 or later installed. You can learn more about Swift 3.0 at Swift.org

Blackfish is tested using the latest Swift Development snapshots, with current testing using snapshot May 09, 2016

To get started on Linux, you need to have Dispatch installed on your system. To do this you can use the below command to set it up.

Ubuntu

First, install the system linux libraries:

sudo apt-get install autoconf libtool libkqueue-dev libkqueue0 libcurl4-openssl-dev libbsd-dev libblocksruntime-dev

Then clone and build libdispatch against your Swift toolchain

git clone -b experimental/foundation https://github.com/apple/swift-corelibs-libdispatch.git && cd swift-corelibs-libdispatch && git submodule init && git submodule update && sh ./autogen.sh && ./configure --with-swift-toolchain=<path-to-swift>/usr --prefix=<path-to-swift>/usr && make && make install

Work in Progress

This is a work in progress and will likely change frequently, pull requests are welcome!

The example project shows how easy it is to begin, and has an instance running on Heroku here

Server

Starting the server is as simple as express.

main.swift

import Blackfish

let app = BlackfishApp()

app.get("/") { request, response in
    response.send(text: "Hello World!")
}

app.listen(port: 3000) { error in
    if error == nil {
        print("Example app listening on port 3000")
    }
}

If you are having trouble connecting, make sure your ports are open. Check out apt-get ufw for simple port management.

Routing

Routing in Blackfish is simple and very similar to Express.

main.swift

app.get("/welcome") { request, response in
	response.send(text: "Hello")
}

app.post('/') { request, response in
    // POST data
    print(request.data)
    response.send(text: 'Got a POST request')
});

//...start server

Router

You can also create a Router object which will allow you to define multiple routes with a prefix.

let router = Router()

router.get("/") { request, response in
    response.send(text: "Bird is the word")
}

router.get("/about") { request, response in
    response.send(text: "Don't you know, about the bird?")
}

app.use(path: "/birds", router: router)

// ...start server

Navigating to http://example.com/birds will show a page with Bird is the word and navigating to http://example.com/birds/about will show a page with "Don't you know, about the bird?".

Controller

You can also use controllers to define your paths. All you need to do is extend from the Controller protocol and implement your routes in func routes(router: Router) to the router object passed in:

MyController.swift
class MyController: Controller {
    
    func routes(router: Router) {
        router.get("/", handler: index)
        router.post("/update", handler: formUpdate)
    }
    
    var index: Route.Handler {
        return { request, response in
            response.send(text: "Hello Index")
        }
    }
    
    func formUpdate(request: Request, response: Response) {
        response.send(text: "Form updated")
    }
}

Routes can be either functions with the correct parameters or Route.Handler objects themselves.

Then we just need to add the controller to the server:

main.swift
let app = BlackfishApp()

app.use(path: "/test", controller: MyController())

app.listen(port: 3000) { error in
    if error == nil {
        print("App listening on port 3000")
    } else {
        print("Error")
    }
}

Now our /test and /test/update paths will be correct populated

JSON

Responding with JSON is easy.

app.get("version") { request, response in
	response.send(json: ["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.

Requesting with JSON is also supported:

app.post("/") { request, response in 

    for (key, value) in request.data {
         print("\(key): \(value)")
    }
    
    response.send(text: "Hello")
}
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d "{'json':{'data': 1}}" http://127.0.0.1:3000

$ "json: ["data": 1]"

Views

You can also respond with HTML pages.

app.get("/") { request, response in
    response.render("index.html")
}

Just put the file in the Resources folder at the root of your project and it will be served.

You can also create your own renderers to use within Blackfish. A renderer for Stencil is already available here Blackfish Stencil.

index.stencil
<html>
    <h1>{{ title }}</h1>
</html>
app.get("/") { request, response in
    res.render("index.stencil", data:["title": "Hello world"])
}

Response

A manual response can be returned if you want to set something like cookies.

Route.get("cookie") { request, response in
    response.status = .OK
    response.text = "Cookie was set"
	response.cookies["test"] = "123"
	response.send()
}

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.twitter.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).

Database

Blackfish works best with any event based based database, especially if powered by Echo.

Currently, Orca is recommended, which allows for asynchronous, non-blocking data persistence.

Orca currently supports

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

Middleware

Similar to Express, Blackfish provides Middleware which can be used to extend the request stack.

You can either create a middleware class that conforms to the Middleware protocol, or pass a closure in to the Blackfish instance.

Below is an example of a validation Middleware conforming class, that validates every request before passing it down the stack.

class Validator: Middleware {

    func handle(request: Request, response: Response, next: () -> ()) {
    
    // Some validation logic
    if validator.validate(request) {

        // Go to the next call in the stack.
        next()

    } else {

        // Return an error and don't call anything else in the stack.
        response.send(error: "Request was unauthorized")
    }	
}

app.use(middleware: Validator()) 

You can also use middleware on a path which will add it to that path and further on.

let userDetail = { (request, response, next) in 
    let user = findUserById(request.data["userId"])
    request.data["user"] = user
    next()
}

app.use(path: "/user", middleware: userDetail)
app.use(path: "/dashboard", middleware: Validator())

Middleware is a powerful feature of Blackfish that can open up endless possibilities.

Multipart

To allow multipart parsing of files and other data from enctype="multitype/form-data" you need to add the Multiparser` middleware to the stack:

app.use(middleware: Multiparser())

Following this, you can access all multipart text input under request.data and files under request.files.

example:

app.use(middleware: Multiparser())

app.post("/") { request, response in 
   print(request.data["name"])
   print(request.files["images"].first)
}

Session

Sessions will be kept track of using the blackfish-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"] = "Blackfish"

Deploying

Heroku

The Blackfish Example app is successfully running on Heroku here

To set up on Heroku, use the Swift Heroku Buildpack by Kyle Fuller.

Instructions for setting up are:

Create a Procfile at the same level as your Package.swift

./Procfile
web: <AppName> --port=$PORT

Then

$ heroku create --buildpack https://github.com/kylef/heroku-buildpack-swift.git

$ git push heroku master

And you're good!

For more information, see the Blackfish Example project.

blackfish's People

Contributors

elliottminns avatar abiaad avatar glessard avatar kimar avatar floschliep avatar konnork avatar keloran avatar gitter-badger avatar korzonek avatar overtrue avatar nonameplum avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.