Web Framework
Key features:
.package(url:"https://github.com/swiftstack/web.git",.branch("dev"))About 80k rps on single core (i7 4gen, docker) using Fiber.
(docker) wrk -t1 -c128 -d5 http://0.0.0.0:8080/plaintext
Running 5s test @ http://0.0.0.0:8080/plaintext
1 threads and 128 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.64ms 310.35us 3.70ms 83.52%
Req/Sec 78.43k 8.95k 93.04k 76.00%
390020 requests in 5.10s, 28.64MB read
Requests/sec: 76500.26
Transfer/sec: 5.62MBHTTP.Application - Simple API with minimum overhead
MVC.Application - Convenience API: Controller, Context, DependencyInjector
Both API levels have built-in Request->Model, Model->Response coders.
Bootstrap.swift
import HTTP
import Web
structWikiApplication:Bootstrap{func configure(services:Services)throws{try services.register(
singleton:InMemoryWikiRepository.self,
as:WikiRepository.self)}func configure(application:MVC.Application)throws{try application.addController(WikiController.self)}func configure(application:HTTP.Application)throws{
application.addHelloWorldRoute()}}WikiController.swift
import HTTP
import Web
publicfinalclassWikiController:Controller,InjectService{letrepository:WikiRepositorypublicinit(_ repository:WikiRepository){self.repository = repository
}publicstaticfunc setup(router:ControllerRouter<WikiController>)throws{
router.route(get:"/:lang/:word", to: getDescription)}structGetDescription:Decodable{letlang,work:String}structDescription:Encodable{lettitle,body:String}func getDescription(request:GetDescription)throws->Description{guardlet description = repository.search(request)else{throwHTTP.Error.notFound
}return description
}}HelloWorld.swift
import HTTP
extensionApplication{func addHelloWorldRoute(){route(get:"/plaintext"){ request inreturnResponse(string:"Hello, World")}}}All the modules built on top of Async which allows us to code without callbacks.
The API is easy to use, easy to read and easy to update to async/await in the future.
main.swift
import Async
import Web
import Log
async{do{letapplication=tryWebHost(bootstrap:WikiApplication())try application.run(at:"0.0.0.0", on:8080)}catch{Log.critical(String(describing: error))}}
loop.run()You can inject up to 6 services (out of the box).
The service can be either Context or :Injectable.
NOTE: the ininializer arguments must have no labels.
import Web
finalclassSimpleController:Controller,Inject2Services{letcontext:Contextletrepository:SomeRepositoryinit(_ context:Context, _ repository:SomeRepository){self.context = context
self.repository = repository
}}singleton - shared instance per application
transient - new instance per request
letservices=Servises.shared
services.register(
singleton:MyImplementation.self,
as:SomeProtocol.self)
services.register(
transient:MyImplementation.self,
as:SomeProtocol.self)
services.register(singleton:SomeProtocol.self){returnMyImplementation()}
services.register(transient:SomeProtocol.self){returnMyImplementation()}