{"id":1985,"url":"https://github.com/sauliusgrigaitis/Swifton","last_synced_at":"2025-07-31T12:33:25.816Z","repository":{"id":66391924,"uuid":"52214257","full_name":"sauliusgrigaitis/Swifton","owner":"sauliusgrigaitis","description":"A Ruby on Rails inspired Web Framework for Swift that runs on Linux and OS X","archived":false,"fork":false,"pushed_at":"2017-02-22T08:29:17.000Z","size":128,"stargazers_count":1968,"open_issues_count":9,"forks_count":70,"subscribers_count":72,"default_branch":"master","last_synced_at":"2024-12-01T12:36:49.863Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sauliusgrigaitis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-02-21T15:58:27.000Z","updated_at":"2024-11-22T21:33:04.000Z","dependencies_parsed_at":"2024-01-05T20:18:40.893Z","dependency_job_id":null,"html_url":"https://github.com/sauliusgrigaitis/Swifton","commit_stats":null,"previous_names":["necolt/swifton"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sauliusgrigaitis%2FSwifton","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sauliusgrigaitis%2FSwifton/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sauliusgrigaitis%2FSwifton/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sauliusgrigaitis%2FSwifton/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sauliusgrigaitis","download_url":"https://codeload.github.com/sauliusgrigaitis/Swifton/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228248422,"owners_count":17891447,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-01-05T20:16:00.537Z","updated_at":"2024-12-05T06:31:20.467Z","avatar_url":"https://github.com/sauliusgrigaitis.png","language":"Swift","funding_links":[],"categories":["Server","Swift"],"sub_categories":["Keychain"],"readme":"IMPORTANT! We don't see any way how to make web development as great as Ruby on Rails or Django with a very static nature of current Swift. We hope that things will change at some point and we will return to active development.\n\n# Swifton\n\nA Ruby on Rails inspired Web Framework for Swift that runs on Linux and OS X.\n\n![Build Status](https://travis-ci.org/necolt/Swifton.svg?branch=master)\n![Linux](https://img.shields.io/badge/os-linux-green.svg?style=flat)\n![Mac OS X](https://img.shields.io/badge/os-Mac%20OS%20X-green.svg?style=flat)\n![Swift 2 compatible](https://img.shields.io/badge/swift2-compatible-4BC51D.svg?style=flat)\n[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)\n[![codebeat badge](https://codebeat.co/badges/c5246f1f-d1cd-4424-b9ec-9340a175a844)](https://codebeat.co/projects/github-com-necolt-swifton)\n\n## Getting Started\n\n* Install Development snapshot [version](https://github.com/necolt/Swifton/blob/master/.swift-version) from [Swift.org](https://swift.org/download/) or via [swiftenv](https://github.com/kylef/swiftenv). If you are on OSX I highly recommend [swiftenv](https://github.com/kylef/swiftenv) - latest Swift will be able to coexist with system wide Swift that comes with Xcode.\n* ```swift --version``` should show something like: ```Swift version 3.0-dev ...```\n* Checkout [TodoApp](https://github.com/necolt/Swifton-TodoApp) example project.\n* Run ```swift build``` inside app (most of dependencies throw deprecation warnings).\n* Run ```./.build/debug/Swifton-TodoApp```.\n* Open ```http://0.0.0.0:8000/todos``` in your browser.\n\n## Contributing\n\nContributions are more than welcome! The easiest way to start contributing to Swifton: \n\n* Setup [TodoApp](https://github.com/necolt/Swifton-TodoApp) \n* Pick one issue from the [issues list](https://github.com/necolt/swifton/issues) or propose enhancement. \n* You can find Swifton source code in ```Swifton-TodoApp/Packages/Swifton-\u003cversion\u003e``` directory. Packages inside ```Packages``` directory comes with Git repository so feel free to do you changes there.\n* Compile and test [TodoApp](https://github.com/necolt/Swifton-TodoApp), this will help to check your changes and avoid regressions.\n* Write tests and run it ```swift build \u0026\u0026 swift test``` (run ```rm -r Packages/*/Tests``` inside Swifton folder if tests crashes)\n* Commit and push your changes, open pull request.\n* Enjoy ;) \n\n## Routing\n\nSwifton comes with ready to use Router, also you can use any router as long as it accepts Request and returns Response. Routes are defined in ```main.swift``` file. Configured Router is passed to [S4](https://github.com/open-swift) interface supporting server. Router allows to define ```resources``` and regular routes.\n\n```swift\n...\nlet router = Router.create { route in\n  route.resources(\"todos\", controller: TodosController())\n}\n...\n```\n\nWhich is equivalent to:\n\n```swift\nlet router = Router()\nrouter.get(\"/todos/new\", TodosController()[\"new\"])\nrouter.get(\"/todos/{id}\", TodosController()[\"show\"])\nrouter.get(\"/todos/{id}/edit\", TodosController()[\"edit\"])\nrouter.get(\"/todos\", TodosController()[\"index\"])\nrouter.post(\"/todos\", TodosController()[\"create\"])\nrouter.delete(\"/todos/{id}\", TodosController()[\"destroy\"])\nrouter.patch(\"/todos/{id}\", TodosController()[\"update\"])\n```\n\nConfigured routes then are passed to application server.\n\n```swift\n...\nserve { request in\n    router.respond(request) \n}\n...\n```\n\n## Controllers \n\nA controller inherits from ApplicationController class, which inherits from Controller class. Action is a closure that accepts Request object and returns Response object. \n\n```swift\nclass TodosController: ApplicationController { \n    // shared todo variable used to pass value between setTodo filter and actions\n    var todo: Todo?    \n    override func controller() {\n    super.controller()\n    // sets before filter setTodo only for specified actions.\n    beforeAction(\"setTodo\", only: [\"show\", \"edit\", \"update\", \"destroy\"])\n\n    // render all Todo instances with Index template (in Views/Todos/Index.html.stencil)\n    action(\"index\") { request in\n        let todos = [\"todos\": Todo.allAttributes()]\n        return render(\"Todos/Index\", todos)\n    }\n\n    // render Todo instance that was set in before filter\n    action(\"show\") { request in\n        return render(\"Todos/Show\", self.todo)\n    }\n\n    // render static New template\n    action(\"new\") { request in\n        return render(\"Todos/New\")\n    }\n\n    // render Todo instance's edit form\n    action(\"edit\") { request in\n        return render(\"Todos/Edit\", self.todo)\n    } \n\n    // create new Todo instance and redirect to list of Todos \n    action(\"create\") { request in\n        Todo.create(request.params)\n        return redirectTo(\"/todos\")\n    }\n    \n    // update Todo instance and redirect to updated Todo instance\n    action(\"update\") { request in\n        self.todo!.update(request.params)\n        return redirectTo(\"/todos/\\(self.todo!.id)\")\n    }\n\n    // destroy Todo instance\n    action(\"destroy\") { request in\n        Todo.destroy(self.todo)\n        return redirectTo(\"/todos\")\n    }\n\n    // set todo shared variable to actions can use it\n    filter(\"setTodo\") { request in\n        // Redirect to \"/todos\" list if Todo instance is not found \n        guard let t = Todo.find(request.params[\"id\"]) else { return self.redirectTo(\"/todos\") } \n        self.todo = t as? Todo\n        // Run next filter or action\n        return self.next\n    }\n\n}}\n\n```\n### Controller Responders\n\n```respondTo``` allows to define multiple responders based client ```Accept``` header:\n\n```swift \n...\naction(\"show\") { request in\n    return respondTo(request, [\n        \"html\": { render(\"Todos/Show\", self.todo) },\n        \"json\": { renderJSON(self.todo) }\n    ])\n}\n...\n\n```\n\n### Controller Filters\n\nSwifton Controllers support ```beforeAction``` and ```afterAction``` filters, which run filters before or after action correspodingly. Filter is a closure that returns ```Response?```. Controller proceeds execution only if filter returns ```self.next``` (which is actually ```nil```), otherwise it returns ```Response``` object and doesn't proceed execution of other filters and action.  \n\n```swift\nfilter(\"setTodo\") { request in\n    // Redirect to \"/todos\" list if Todo instance is not found\n    guard let t = Todo.find(request.params[\"id\"]) else { return self.redirectTo(\"/todos\") }\n    self.todo = t as? Todo\n    // Run next filter or action\n    return self.next\n}\n```\n\n## Models\n\nSwifton is ORM agnostic web framework. You can use any ORM of your choice. Swifton comes with simple in-memory MemoryModel class that you can inherit and use for your apps. Simple as this: \n\n```swift\nclass User: MemoryModel {\n}\n\n...\n\nUser.all.count // 0\nvar user = User.create([\"name\": \"Saulius\", \"surname\": \"Grigaitis\"])\nUser.all.count // 1\nuser[\"name\"] // \"Saulius\"\nuser[\"surname\"] // \"Grigaitis\"\nuser.update([\"name\": \"James\", \"surname\": \"Bond\"])\nuser[\"surname\"] // \"Bond\"\nUser.destroy(user)\nUser.all.count // 0\n\n```\n\nFew options if you need persistence:\n\n* [PostgreSQL](https://github.com/Zewo/PostgreSQL) adapter.\n* [MySQL](https://github.com/Zewo/MySQL) adapter.\n* [Fluent](https://github.com/qutheory/fluent) simple SQLite ORM. \n\n## Views\n\nSwifton supports Mustache like templates via [Stencil](https://github.com/kylef/Stencil) template language. View is rendered with controller's method ```render(template_path, object)```. Object needs either to conform to ```HTMLRenderable``` protocol, either be ```[String: Any]``` type where ```Any``` allows to pass complex structures.\n\n```html\n\u003ctbody\u003e\n  {% for todo in todos %}\n    \u003ctr\u003e\n      \u003ctd\u003e{{ todo.title }}\u003c/td\u003e\n      \u003ctd\u003e{{ todo.completed }}\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"/todos/{{ todo.id }}\"\u003eShow\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"/todos/{{ todo.id }}/edit\"\u003eEdit\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003ca data-confirm=\"Are you sure?\" rel=\"nofollow\" data-method=\"delete\" href=\"/todos/{{ todo.id }}\"\u003eDestroy\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  {% endfor %}\n\u003c/tbody\u003e\n\n```\n\nViews are loaded from ```Views``` directory by default, you can also change this default setting by changing value of ```SwiftonConfig.viewsDirectory``` (preferable in ```main.swift``` file). Currently views are not cached, so you don't need to restart server or recompile after views are changed. \n\nStatic assets (JavaScript, CSS, images etc.) are loaded from ```Public``` directory by default, you can also change this default setting by changing value of ```SwiftonConfig.publicDirectory``` (preferable in ```main.swift``` file).\n\n## JSON support\n\n```renderJSON(object)``` generates and returns JSON of an object. Object must conform to ```JSONRenderable``` protocol.\n\n```swift\naction(\"show\") { request in\n    return respondTo(request, [\n        \"html\": { render(\"Todos/Show\", self.todo) },\n        \"json\": { renderJSON(self.todo) }\n    ])\n}\n```\n\n## Middleware\n\n```main.swift``` is probably best place to put middleware. Simply wrap ```Router``` instance with your middleware, you can even nest multiple middlewares.  \n\n```swift\n...\nserve { request in\n    router.respond(request) \n}\n...\n```\n\n## Application Server\n\nSwifton comes with [VeniceX](https://github.com/VeniceX/Venice) based HTTP server. Swifton supports [S4](https://github.com/open-swift/S4) HTTP standards for Swift so you can easily use any [S4](https://github.com/open-swift/S4) supporting server. \n\n### Building for production\n\nBuild ```release``` configuration for better performance:\n\n```shell\n$ swift build --configuration release\n```\n## Deployment\n\n### Heroku\n\nExample [TodoApp](https://github.com/necolt/Swifton-TodoApp) can be deployed to Heroku using the [heroku-buildpack-swift](https://github.com/kylef/heroku-buildpack-swift).\n\nClick the button below to automatically set up this example to run on your own Heroku account.\n\n[![Deploy to Heroku](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/necolt/Swifton-TodoApp)\n\n### Docker \n\nSwifton can be deployed with Docker. Some examples how to deploy it with Docker:\n* [TodoApp](https://github.com/necolt/Swifton-TodoApp) on EC2 Container Services (ECS) [example](http://ngs.io/2016/03/04/swift-webapp-on-ecs/)\n* Docker Container for the Apple's Swift programming language - [docker-swift](https://github.com/swiftdocker/docker-swift).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsauliusgrigaitis%2FSwifton","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsauliusgrigaitis%2FSwifton","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsauliusgrigaitis%2FSwifton/lists"}