{"id":1981,"url":"https://github.com/crossroadlabs/Express","last_synced_at":"2025-08-02T05:33:27.912Z","repository":{"id":151711863,"uuid":"51105517","full_name":"crossroadlabs/Express","owner":"crossroadlabs","description":"Swift Express is a simple, yet unopinionated web application server written in Swift","archived":false,"fork":false,"pushed_at":"2018-12-22T09:38:23.000Z","size":520,"stargazers_count":848,"open_issues_count":13,"forks_count":44,"subscribers_count":41,"default_branch":"master","last_synced_at":"2025-05-24T14:21:25.020Z","etag":null,"topics":["asynchronous","crossroad-labs","linux","linux-support","reactive","server","swift","swift-express"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crossroadlabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-02-04T21:06:46.000Z","updated_at":"2025-02-23T16:12:37.000Z","dependencies_parsed_at":"2023-07-17T21:00:54.945Z","dependency_job_id":null,"html_url":"https://github.com/crossroadlabs/Express","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/crossroadlabs/Express","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossroadlabs%2FExpress","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossroadlabs%2FExpress/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossroadlabs%2FExpress/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossroadlabs%2FExpress/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crossroadlabs","download_url":"https://codeload.github.com/crossroadlabs/Express/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossroadlabs%2FExpress/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268339405,"owners_count":24234544,"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","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["asynchronous","crossroad-labs","linux","linux-support","reactive","server","swift","swift-express"],"created_at":"2024-01-05T20:16:00.447Z","updated_at":"2025-08-02T05:33:27.556Z","avatar_url":"https://github.com/crossroadlabs.png","language":"Swift","readme":"[//]: https://www.iconfinder.com/icons/383207/doc_tag_icon#size=64\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"http://swiftexpress.io/\"\u003e\n\t\t\u003cimg alt=\"Swift Express\" src =\"./logo-full.png\" height=256/\u003e\n\t\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n\t\u003cp align=left\u003e\n\t\t\u003ca href=\"https://twitter.com/swift_express\" target=\"_blank\"\u003e\u003cimg align=\"left\" vspace=42 src=\"https://cdn4.iconfinder.com/data/icons/social-messaging-ui-color-shapes-2-free/128/social-twitter-circle-128.png\" height=64 alt=\"Twitter\"/\u003e\u003c/a\u003e\n\t\t\u003ca href=\"https://www.facebook.com/swiftexpress.io\" target=\"_blank\"\u003e\u003cimg align=\"left\" vspace=42 src=\"https://cdn4.iconfinder.com/data/icons/social-messaging-ui-color-shapes-2-free/128/social-facebook-circle-128.png\" height=64 alt=\"Facebook\"/\u003e\u003c/a\u003e\n\t\t\u003ca href=\"https://www.linkedin.com/company/swift-express\" target=\"_blank\"\u003e\u003cimg align=\"left\" vspace=42 src=\"https://cdn4.iconfinder.com/data/icons/social-messaging-ui-color-shapes-2-free/128/social-linkedin-circle-128.png\" height=64 alt=\"LinkedIn\"/\u003e\u003c/a\u003e\n\t\t\u003ca href=\"http://swiftexpress.io\" target=\"_blank\"\u003e\u003cimg align=\"left\" vspace=42 src=\"https://cdn3.iconfinder.com/data/icons/internet-and-web-4/78/internt_web_technology-01-128.png\" height=64 alt=\"Web site\"/\u003e\u003c/a\u003e\n\t\t\u003ca href=\"mailto:slack@swiftexpress.io?Subject=Add me to Slack\" target=\"_blank\"\u003e\u003cimg vspace=35 align=\"left\" src=\"https://cdn0.iconfinder.com/data/icons/picons-social/57/109-slack-128.png\" height=72 alt=\"Slack\"/\u003e\u003c/a\u003e\n\t\u003c/p\u003e\n\t\u003cp\u003e\n\t\t\u003ch5 align=\"right\"\u003e\u003ca href=\"./doc/index.md\"\u003eDocumentation    \u003cimg src=\"https://cdn0.iconfinder.com/data/icons/glyphpack/82/tag-doc-64.png\" height=16/\u003e\u003c/a\u003e\u003c/h5\u003e\n\t\t\n\t\t\u003ch5 align=\"right\"\u003e\u003ca href=\"http://demo.swiftexpress.io/\"\u003eLive 🐧 server running Demo  \u003cimg src=\"https://cdn0.iconfinder.com/data/icons/glyphpack/34/play-circle-32.png\" height=16/\u003e\u003c/a\u003e\u003c/h5\u003e\n\t\t\n\t\t\u003ch5 align=\"right\"\u003e\u003ca href=\"http://swiftexpress.io/\"\u003eEating our own dog food  \u003cimg src=\"https://cdn0.iconfinder.com/data/icons/glyphpack/147/globe-full-32.png\" height=16/\u003e\u003c/a\u003e\u003c/h5\u003e\n\t\t\u003cbr/\u003e\n\t\u003c/p\u003e\n\u003c/p\u003e\n\n![🐧 linux: ready](https://img.shields.io/badge/%F0%9F%90%A7%20linux-ready-red.svg)\n[![Build Status](https://travis-ci.org/crossroadlabs/Express.svg?branch=master)](https://travis-ci.org/crossroadlabs/Express)\n[![SPM compatible](https://img.shields.io/badge/SPM-compatible-4BC51D.svg?style=flat)](https://swift.org/package-manager/)\n![Platform OS X | Linux](https://img.shields.io/badge/platform-OS%20X%20%7C%20Linux-orange.svg)\n![Swift version](https://img.shields.io/badge/Swift-3.x-blue.svg)\n[![GitHub license](https://img.shields.io/badge/license-LGPL v3-green.svg)](https://raw.githubusercontent.com/crossroadlabs/Express/master/LICENSE)\n[![GitHub release](https://img.shields.io/github/release/crossroadlabs/Express.svg)](https://github.com/crossroadlabs/Express/releases)\n\n\u003ctable bgcolor=\"#ff0000\"\u003e\n\u003ctr\u003e\u003ctd\u003e\n\u003cimg src=\"https://www.iconfinder.com/icons/728979/download/png/256\" height=64 align=\"left\"/\u003eUPDATE March 2017: Swift Express is back on track and is Swift 3.x compatible. From now on we will suport the latest stable swift builds only. There is no release of the newest version done yet, though you can enjoy it from the \"master\" branch. Stay tuned.\n\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable bgcolor=\"#ff0000\"\u003e\n\u003ctr\u003e\u003ctd\u003e\n\u003cimg src=\"https://www.iconfinder.com/icons/728979/download/png/256\" height=64 align=\"left\"/\u003eVersion 0.3.x (current stable) notice: Current version works with Xcode 7.2, 7.3 and Linux DEV SNAPSHOT released on 03.01.2016. Upcoming version (0.4.x) will fully support Swift 3.0 and will maintain compatibility with Swift 2.2 (Xcode 7.3). Stay tuned by following us on social networks.\n\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n### Being [perfectionists](http://www.crossroadlabs.xyz), we took the best from what we think is the best: power of [Play Framework](https://www.playframework.com/) and simplicity of [Express.js](http://expressjs.com/)\n\n#### Express is an asynchronous, simple, powerful, yet unopinionated web application server written in Swift\n\n## Getting started\n\nFirst make sure, please, you have followed the [installation](#installation) section steps.\n\n##### Create a project:\n\n```sh\nswift-express init HelloExpress\ncd HelloExpress\nswift-express bootstrap\nopen HelloExpress.xcodeproj\n```\n\n##### Create new API:\n\n```swift\napp.get(\"/myecho\") { request in\n    .ok(request.query[\"message\"]?.first)\n}\n```\n\n##### Run from xCode or command line with:\n\n```sh\nswift-express build\nswift-express run\n```\n\nTest it in the browser: [http://localhost:9999/myecho?message=Hello](http://localhost:9999/myecho?message=Hello)\n\n##### A complete Swift Express command line documentation can be found here: [https://github.com/crossroadlabs/ExpressCommandLine](https://github.com/crossroadlabs/ExpressCommandLine)\n\n\n## Installation\n\n[//]: # (Icons are here: https://www.iconfinder.com/icons/395228/linux_tox_icon#size=16)\n\n### [OS X ![OS X](https://cdn1.iconfinder.com/data/icons/system-shade-circles/512/mac_os_X-16.png)](http://www.apple.com/osx/)\n\n##### First install the following components (if you have not yet):\n\n* [XCode](https://developer.apple.com/xcode/download/) 7.2 or higher\n* [Homebrew](http://brew.sh/) the latest available version\n* Command Line tools: run ```xcode-select --install``` in terminal\n\n##### Run the following in terminal:\n\n```sh\nbrew tap crossroadlabs/tap\nbrew install swift-express\n```\n\n#### [Linux ![Linux](https://cdn1.iconfinder.com/data/icons/system-shade-circles/512/linux_tox-16.png)](http://www.linux.org/)\n\n##### For instructions on how to get [Express](http://swiftexpress.io/) installed on Linux, please, refer to the [installation section](./doc/gettingstarted/installing.md#linux-) in the [ducumentation](./doc/index.md).\n\n## Examples\n\nCreate a project as it is described in the [getting started](#getting-started) section. Now you can start playing with examples.\n\nAll the examples can be found in `Demo` project inside the main repo.\n\n### Hello Express:\n\n```swift\napp.get(\"/hello\") { request in\n    .ok(AnyContent(str: \"\u003ch1\u003eHello Express!!!\u003c/h1\u003e\", contentType: \"text/html\"))\n}\n```\n\nLaunch the app and follow the link: [http://localhost:9999/hello?message=Hello](http://localhost:9999/hello?message=Hello)\n\n### Synchronous vs Asynchronous\n\nIf you don't know what this is you might want to better skip it for now to the next section: [URL params](#url-params). To get more information see [this](http://cs.brown.edu/courses/cs168/s12/handouts/async.pdf) first. We have our APIs based on [Future pattern](https://en.wikipedia.org/wiki/Futures_and_promises). Our implementation is based on [BrightFutures](https://github.com/Thomvis/BrightFutures), thanks @Thomvis!\n\nExpress can handle it both ways. All your syncronous code will be executed in a separate queue in a traditional way, so if you are a fan of this approach - it will work (like in \"Hello Express\" example above).\n\nStill if you want to benefit from asynchronicity, we provide a very powerful API set that accepts futures as result of your handler.\n\nLet's assume you have following function somewhere:\n\n```swift\nfunc calcFactorial(num:Double) -\u003e Future\u003cDouble, AnyError\u003e\n```\n\nit's a purely asyncronous function that returns future. It would be really nice if it could be handled asynchronously as well in a nice functional way. Here is an example of how it could be done.\n\n\n```swift\n// (request -\u003e Future\u003cAction\u003cAnyContent\u003e, AnyError\u003e in) - this is required to tell swift you want to return a Future\n// hopefully inference in swift will get better eventually and just \"request in\" will be enough\napp.get(\"/factorial/:num(\\\\d+)\") { request -\u003e Future\u003cAction\u003cAnyContent\u003e, AnyError\u003e in\n    // get the number from the url\n    let num = request.params[\"num\"].flatMap{Double($0)}.getOrElse(0)\n    \n    // get the factorial Future. Returns immediately - non-blocking\n    let factorial = calcFactorial(num)\n    \n    //map the result of future to Express Action\n    let future = factorial.map { fac in\n        Action.ok(String(fac))\n    }\n    \n    //return the future\n    return future\n}\n```\n\n### URL params\n\nLet's get our echo example from [Getting Started](#getting-started) a bit further. Our routing engine, which is largely based on NodeJS analog [path-to-regex](https://github.com/pillarjs/path-to-regexp). You can read the complete documentation on how to use path patterns [here](https://github.com/pillarjs/path-to-regexp). Now an example with URL param:\n\n```swift\n//:param - this is how you define a part of URL you want to receive through request object\napp.get(\"/echo/:param\") { request in\n    //here you get the param from request: request.params[\"param\"]\n    .ok(request.params[\"param\"])\n}\n```\n\n### Serving static files\n\n```swift\napp.get(\"/:file+\", action: StaticAction(path: \"public\", param:\"file\"))\n```\n\nThe code above tells Express to serve all static files from the public folder recursively. If you want to serve just the first level in folder, use:\n\n```swift\napp.get(\"/:file\", action: StaticAction(path: \"public\", param:\"file\"))\n```\n\nThe difference is just in the pattern: `/:file` versus `/:file+`. For more information see our routing section.\n\n### Serving JSON requests\n\nFirst of all we need to register the JSON view in the system:\n\n```swift\n//now we can refer to this view by name\napp.views.register(JsonView())\n```\n\nLet's say we want to build a simple API for users registration. We want our API consumers to `POST` to `/api/user` a JSON object and get a `JSON` response back.\n\n```swift\napp.post(\"/api/user\") { request in\n    //check if JSON has arrived\n    guard let json = request.body?.asJSON() else {\n        return Action.ok(\"Invalid request\")\n    }\n    //check if JSON object has username field\n    guard let username = json[\"username\"].string else {\n        return Action.ok(\"Invalid request\")\n    }\n    //compose the response as a simple dictionary\n    let response =\n        [\"status\": \"ok\",\n        \"description\": \"User with username '\" + username + \"' created succesfully\"]\n    \n    //render disctionary as json (remember the one we've registered above?)\n    return .render(JsonView.name, context: response)\n}\n```\n\nLines above will do the job. Post this `JSON`:\n\n```json\n{\n    \"username\": \"swiftexpress\"\n}\n```\n\nto our api URL: `http://localhost:9999/api/user` (don't forget `application/json` content type header) and you will get this response:\n\n```json\n{\n  \"status\": \"ok\",\n  \"description\": \"User with username 'swiftexpress' created succesfully\"\n}\n```\n\n### Using template engine\n\nFirst of all you need to switch the template engine on:\n\n```swift\n//we recommend mustache template engine\napp.views.register(StencilViewEngine())\n```\n\nNow create a file called `hello.stencil` in the `views` directory:\n\n```stencil\n\u003chtml\u003e\n\u003cbody\u003e\n\u003ch1\u003eHello from Stencil: {{user}}\u003c/h1\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nAdd a new request handler:\n\n```swift\n//user as an url param\napp.get(\"/hello/:user.html\") { request in\n    //get user\n    let user = request.params[\"user\"]\n    //if there is a user - create our context. If there is no user, context will remain nil\n    let context = user.map {[\"user\": $0]}\n    //render our template named \"hello\"\n    return .render(\"hello\", context: context)\n}\n```\n\nNow follow the link to see the result: [http://localhost:9999/hello/express.html](http://localhost:9999/hello/express.html)\n\n\n### If you want more, please, visit our [documentation](./doc/index.md) page\n\n## Ideology behind\n\n### Taking the best of Swift\n\n[Swift](https://swift.org/) essentially is a new generation programming language combining simplicity and all the modern stuff like functional programming.\n\nWe were inspired (and thus influenced) mainly by two modern web frameworks: [Express.js](http://expressjs.com/) and [Play](https://www.playframework.com/). So, we are trying to combine the best of both worlds taking simplicity from [Express.js](http://expressjs.com/) and modern robust approach of [Play](https://www.playframework.com/)\n\nLet us know if we are on the right path! Influence the project, create feature requests, API change requests and so on. While we are in our early stages, it's easy to change. We are open to suggestions!\n\n## Features\n\n* 🐧 Linux support with and without [Dispatch](https://swift.org/core-libraries/#libdispatch)\n* 100% asynchronous (Future-based API)\n* Flexible and extensible\n* Full [MVC](https://ru.wikipedia.org/wiki/Model-View-Controller) support\n* Swift 2.1 and 2.2 compatible\n* [Simple routing mechanism](./doc/gettingstarted/routing.md)\n* Request handlers chaining\n* [Typesafe Error Handlers](./doc/gettingstarted/errorhandling.md)\n* Templates: [Stencil](https://github.com/kylef/Stencil) and [Mustache](https://mustache.github.io)\n* Built-in [JSON](http://www.json.org) support\n* Easy creation of [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) APIs\n* Built-in [static files serving](./doc/gettingstarted/static.md)\n* Multiple contents types built-in support\n\n### And heah, the most important feature: [Highly passionate development team](http://www.crossroadlabs.xyz/)\n\n## Roadmap\n\n* v0.4: stable version with Swift 3.0\n* v0.5: proper streaming\n* v0.6: new core (based on [Reactive Swift](https://github.com/reactive-swift))\n* v0.7: more content types available out of the box\n* v0.8: Web Sockets\n* v0.9: hot code reload\n* v1.0: hit the production!\n\n## Changelog\n\n* v0.4: Swift 3.0\n\t* Ported Express to Swift 3.0\n\t* Moved to [Reactive Swift](https://github.com/reactive-swift) foundation ([Execution contexts](https://github.com/reactive-swift/ExecutionContext), [Futures](https://github.com/reactive-swift/Future), etc.)\n\t* Wrapped libevent as an [ExecutionContext](https://github.com/reactive-swift/ExecutionContext)\n\t* Dropped [Carthage](https://github.com/Carthage/Carthage) support\n\n* v0.3: linux support\n\t* Runs on linux with and without [Dispatch](https://swift.org/core-libraries/#libdispatch) support (see [installation section](./doc/gettingstarted/installing.md#linux-) and [building in production](./doc/gettingstarted/buildrun.md#production-build))\n\t* FormUrlEncoded ContentType support\n\t* Merged Query (params from both query string and form-url-encoded body merged together)\n\t* Utility methods (redirect, status, etc)\n\t* [Stencil](https://github.com/kylef/Stencil) Templete Engine Support\n\t* Replaced [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON) with [TidyJSON](https://github.com/benloong/TidyJSON)\n\t* [Typesafe Error Handlers](./doc/gettingstarted/errorhandling.md)\n\t* Better Demo app\n* v0.2.1: minor changes\n\t* Swift modules are installed via Carthage\n\t* Enabled binary builds on OS X\n* v0.2: Solid OS X release\n\t* Much better routing APIs\n\t* Advanced routing path patterns\n\t* Possibility to use Regex for routing\n\t* Greately improved README\n\t* Some bugfixes\n* v0.1: Initial Public Release\n\t* basic routing\n\t* views and view engines (supports [Mustache](https://mustache.github.io/))\n\t* JSON rendering as a view\n\t* query parsing\n\t* static files serving\n\n## Contributing\n\nTo get started, \u003ca href=\"https://www.clahub.com/agreements/crossroadlabs/Express\"\u003esign the Contributor License Agreement\u003c/a\u003e.\n\n## [![Crossroad Labs](http://i.imgur.com/iRlxgOL.png?1) by Crossroad Labs](http://www.crossroadlabs.xyz/)\n","funding_links":[],"categories":["Server","HarmonyOS","Libs"],"sub_categories":["Keychain","Windows Manager","Other free courses","Network"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrossroadlabs%2FExpress","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrossroadlabs%2FExpress","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrossroadlabs%2FExpress/lists"}