├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── Turnstone.podspec.json ├── Turnstone └── Turnstone.swift └── TurnstoneSpecs └── TurnstoneSpec.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .conche/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode7 3 | install: brew install --HEAD kylef/formulae/conche 4 | script: conche test 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Kyle Fuller 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Turnstone 2 | 3 | [![Build Status](http://img.shields.io/travis/kylef/Turnstone/master.svg?style=flat)](https://travis-ci.org/kylef/Turnstone) 4 | 5 | Lightweight request routing for [Nest](https://github.com/nestproject/Nest). 6 | Turnstone allows you to register a URI Template against a handler to provide 7 | request routing. 8 | 9 | ## Installation 10 | 11 | ```ruby 12 | pod 'Turnstone' 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```swift 18 | import Turnstone 19 | import Inquiline 20 | 21 | let turnstone = Turnstone() 22 | 23 | turnstone.addRoute("/") { request in 24 | return Response(.Ok, body: "Root URI") 25 | } 26 | 27 | turnstone.addRoute("/tasks/{id}") { request, parameters in 28 | let id = parameters["id"]! 29 | return Response(.Ok, body: "Task \(id)") 30 | } 31 | 32 | serve("localhost", 8080, turnstone.nest) 33 | ``` 34 | 35 | ## License 36 | 37 | Turnstone is released under the BSD license. See [LICENSE](LICENSE). 38 | -------------------------------------------------------------------------------- /Turnstone.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Turnstone", 3 | "version": "0.2.0", 4 | "summary": "Lightweight request routing for Nest using URI Template.", 5 | "homepage": "https://github.com/kylef/Turnstone", 6 | "license": { 7 | "type": "BSD", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "Kyle Fuller": "kyle@fuller.li" 12 | }, 13 | "social_media_url": "http://twitter.com/kylefuller", 14 | "source": { 15 | "git": "https://github.com/kylef/Turnstone.git", 16 | "tag": "0.2.0" 17 | }, 18 | "source_files": "Turnstone/*.swift", 19 | "platforms": { 20 | "ios": "8.0", 21 | "osx": "10.9" 22 | }, 23 | "dependencies": { 24 | "Nest": [ "~> 0.2.0" ], 25 | "Inquiline": [ "~> 0.2.0" ], 26 | "URITemplate": [ "~> 1.3" ] 27 | }, 28 | "test_specification": { 29 | "source_files": "TurnstoneSpecs/*.swift", 30 | "dependencies": { 31 | "Inquiline": [ "~> 0.2.0" ], 32 | "Spectre": [ "~> 0.3.0" ] 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Turnstone/Turnstone.swift: -------------------------------------------------------------------------------- 1 | import Nest 2 | import Inquiline 3 | import URITemplate 4 | 5 | 6 | // Simple Nest compatible URI Template Router 7 | public class Turnstone { 8 | public typealias Parameters = [String: String] 9 | public typealias Application = (RequestType, Parameters) -> ResponseType 10 | 11 | typealias Route = (URITemplate, Application) 12 | 13 | var routes = [Route]() 14 | 15 | /// The handler for when a router isn't found 16 | public var notFoundHandler: Nest.Application = { request in 17 | return Response(.NotFound, contentType: "text/plain; charset=utf8", body: "Page Not Found") 18 | } 19 | 20 | public init() {} 21 | 22 | /** Add a handler for the given URI Template 23 | - parameter uri: A URI Template 24 | - parameter handler: The handler for the given URI 25 | */ 26 | public func addRoute(uri: String, application: Application) { 27 | routes.append((URITemplate(template: uri), application)) 28 | } 29 | 30 | public func addNestRoute(uri: String, application: Nest.Application) { 31 | addRoute(uri) { request, parameters in 32 | application(request) 33 | } 34 | } 35 | 36 | /// A Nest compatible interface 37 | public func nest(request: RequestType) -> ResponseType { 38 | for (template, handler) in routes { 39 | if let variables = template.extract(request.path) { 40 | return handler(request, variables) 41 | } 42 | } 43 | 44 | return notFoundHandler(request) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TurnstoneSpecs/TurnstoneSpec.swift: -------------------------------------------------------------------------------- 1 | import Spectre 2 | import Nest 3 | import Inquiline 4 | import Turnstone 5 | 6 | 7 | describe("Turnstone") { 8 | let turnstone = Turnstone() 9 | 10 | turnstone.notFoundHandler = { request in 11 | return Response(.NotFound, body: "Custom 404") 12 | } 13 | 14 | turnstone.addNestRoute("/") { request in 15 | return Response(.Ok, body: "Root URI") 16 | } 17 | 18 | turnstone.addRoute("/tasks/{id}") { request, parameters in 19 | let id = parameters["id"]! 20 | return Response(.Ok, body: "Task \(id)") 21 | } 22 | 23 | $0.it("returns 404 response for unhandled URIs") { 24 | let turnstone = Turnstone() 25 | let request = Request(method: "GET", path: "/404") 26 | let response = turnstone.nest(request) 27 | try equal(response.statusLine, "404 NOT FOUND") 28 | } 29 | 30 | $0.it("uses the csutom handler for unhandled URIs") { 31 | let request = Request(method: "GET", path: "/404") 32 | let response = turnstone.nest(request) 33 | try equal(response.body, "Custom 404") 34 | } 35 | 36 | $0.it("matches an added route") { 37 | let request = Request(method: "GET", path: "/") 38 | let response = turnstone.nest(request) 39 | try equal(response.statusLine, "200 OK") 40 | } 41 | 42 | $0.it("matches an added route with parameters") { 43 | let request = Request(method: "GET", path: "/tasks/5") 44 | let response = turnstone.nest(request) 45 | try equal(response.statusLine, "200 OK") 46 | try equal(response.body, "Task 5") 47 | } 48 | } 49 | --------------------------------------------------------------------------------