Skip to content

A Swift Multiplatform Web and Networking Framework

License

Notifications You must be signed in to change notification settings

fengweijp/Edge

 
 

Repository files navigation

Edge
Serverside non-blocking IO in Swift
Ask questions in our Slack channel!

Edge

Swift Build Status codecov Slack Status

Node

Edge is an HTTP Server and TCP Client/Server framework written in Swift and inspired by Node.js. It runs on both OS X and Linux. Like Node.js, Edge uses an event-driven, non-blocking I/O model. In the same way that Node.js uses libuv to implement this model, Edge uses libdispatch.

This makes Edge fast and efficient, but it also means that Edge applications can naturally make use of libdispatch to easily offload heavy processing to a background thread.

The name Edge is a play on the name Node, as they are both components of graphs.

Reactive Programming

Edge's event API embraces the concepts of Functional Reactive Programming while still not having any external dependencies. The API is called Reflex and it is a modified version of ReactiveCocoa, but also inspired by RxSwift.

Why did we reimplement?

  • Edge should be easy to use out of the box.
  • Edge is optimized for maximum performance, which requires careful tuning of the internals.
  • The modified API is meant to be more similar to the familiar concepts of Futures and Promises.
  • We don't want to be opinionated about any one framework. We want it to be easy to integate Edge with either ReactiveCocoa or RxSwift.

FRP, greatly simplies management of asynchronous events. The general concept is that we can build a spout which pushes out asynchronous events as they happen. Then we hookup a pipeline of transformations that operate on events and pass the transformed values along. We can even do things like merge streams in interesting ways! Take a look at some of these operations or watch this talk about how FRP is used at Netflix.

Installation

Edge is available as a Swift 3 package. Simply add Edge as a dependency to your Swift Package.

import PackageDescription

let package = Package(
    name: "MyProject",
    dependencies: [
        .Package(url: "https://github.com/SwiftOnEdge/Edge.git", majorVersion: 0, minor: 1)
    ]
)

Usage

Routing

import Edge
import Foundation

// Create an API router.
let api = Router()

// Add a GET "/users" endpoint.
api.get("/users") { request in
    return Response(status: .ok)
}

// NOTE: Equivalent to `api.post("/auth/login")`
let auth = api.filter("/auth").post("/login") { request in
    return Response(status: .ok)
}
api.add(auth)

// Middleware to log all requests
// NOTE: Middleware is a simple as a map function or closure!
let app = Router().map { request in
    print(request)
    return request
}

// Mount the API router under "/v1.0".
app.add("/v1.0", api)

// NOTE: Errors on all unhandled requests. No more hanging clients!
app.any { _ in
    return Response(status: .notFound)
}

// Start the application.
app.start(host: "0.0.0.0", port: 3000)

Raw HTTP

import Edge
import Foundation

func handleRequest(request: Request) -> Response {
    print(String(bytes: request.body, encoding: .utf8)!)
    return try! Response(json: ["message": "Message received!"])
}

let server = HTTP.Server()
server.listen(host: "0.0.0.0", port: 3000).startWithNext { client in

    let requestStream = client.read()
    requestStream.map(handleRequest).onNext{ response in
        client.write(response).start()
    }

    requestStream.onFailed { clientError in
        print("Oh no, there was an error! \(clientError)")
    }

    requestStream.onCompleted {
        print("Goodbye \(client)!")
    }

    requestStream.start()
}

TCP

import Edge
import Foundation

let server = try! TCP.Server()
try! server.bind(host: "0.0.0.0", port: 50000)
    
server.listen().startWithNext { connection in
    let byteStream = connection.read()
    let strings = byteStream.map { String(bytes: $0, encoding: .utf8)! }
    
    strings.onNext { message in
        print("Client \(connection) says \"\(message)\"!")
    }
    
    strings.onFailed { error in
        print("Oh no, there was an error! \(error)")
    }
    
    strings.onCompleted {
        print("Goodbye \(connection)!")
    }
    
    strings.start()
}

RunLoop.runAll()

Edge is not Node.js

Edge is not meant to fulfill all of the roles of Node.js. Node.js is a JavaScript runtime, while Edge is a TCP/Web server framework. The Swift compiler and package manager, combined with third-party Swift packages, make it unnecessary to build that functionality into Edge.

About

A Swift Multiplatform Web and Networking Framework

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 96.8%
  • Shell 3.2%