Lightweight, flexible HTTP server framework written in Swift

Overview

Hummingbird

Lightweight, flexible server framework written in Swift.

Hummingbird consists of three main components, the core HTTP server, a minimal web application framework and the extension modules.

HummingbirdCore

HummingbirdCore contains a Swift NIO based HTTP server. You will find the code for it in the hummingbird-core repository. The HTTP server is initialized with a object conforming to protocol HBHTTPResponder which defines how your server responds to an HTTP request. The HTTP server can be extended to support TLS and HTTP2 via the HummingbirdTLS and HummingbirdHTTP2 libraries also available in the hummingbird-core repository.

HummingbirdCore can be used separately from Hummingbird if you want to write your own web application framework.

Hummingbird

Hummingbird is a lightweight and flexible web application framework that runs on top of HummingbirdCore. It is designed to require the minimum number of dependencies: swift-backtrace, swift-log, swift-nio, swift-nio-extras, swift-service-lifecycle and swift-metrics and makes no use of Foundation.

It provides a router for directing different endpoints to their handlers, middleware for processing requests before they reach your handlers and processing the responses returned, support for adding channel handlers to extend the HTTP server, extending the core HBApplication, HBRequest and HBResponse classes and providing custom encoding/decoding of Codable objects.

The interface is fairly standard. Anyone who has had experience of Vapor, Express.js etc will recognise most of the APIs. Simple setup is as follows

String in return "Hello" } try app.start() app.wait() ">
import Hummingbird

let app = HBApplication(configuration: .init(address: .hostname("127.0.0.1", port: 8080)))
app.router.get("hello") { request -> String in
    return "Hello"
}
try app.start()
app.wait()

Hummingbird Extensions

Hummingbird is designed to require the least number of dependencies possible, but this means many features are unavailable to the core libraries. Additional features are provided through extensions. The Hummingbird repository comes with a HummingbirdFoundation library that contains a number of features that can only really be implemented with the help of Foundation. This include JSON encoding/decoding, URLEncodedForms, static file serving, and cookies.

Extensions provided in other repositories include

Extension Description
HummingbirdAuth Authentication framework and various support libraries
HummingbirdCompress Request decompression and response compression (uses CompressNIO)
HummingbirdFluent Interface to the Vapor database ORM (uses FluentKit)
HummingbirdRedis Interface to Redis (uses RediStack)
HummingbirdWebSocket Adds support for WebSocket upgrade to server
HummingbirdMustache Mustache templating engine
HummingbirdLambda Run hummmingbird inside an AWS Lambda

Documentation

You can find reference documentation and user guides for Hummingbird here. The hummingbird-examples repository has a number of examples of different uses of the library.

Comments
  • Failing to start on Mac due to in-use port fails to return

    Failing to start on Mac due to in-use port fails to return

    Not sure if I'm right about this. I have a Mac command line target that's starting a Hummingbird server.

    What appears to be happening is that if the port I ask it to start on is already taken, Hummingbird fail and hangs at this point:

    Screen Shot 2022-07-20 at 10 35 03 pm

    This doesn't seem to occur when running the same startup code on an iOS simulator, just when running via a Mac command.

    Any clues how I might resolve this?

    opened by drekka 12
  • `HBRequest.endpointPath` not set while applying middleware

    `HBRequest.endpointPath` not set while applying middleware

    Within the context of middleware, the request's endpointPath property will always be nil. This is due to the endpointPath being set by the TrieRouter after all middleware was applied, as shown in the following call tree:

    image

    In this call tree "0" refers to the following line:

    https://github.com/hummingbird-project/hummingbird/blob/434fdd8d96e1ac2661c1150aefa95e127f2d942f/Sources/Hummingbird/Router/TrieRouter.swift#L53

    I also checked the built-in HBMetricsMiddleware and it resulted in the same lack of an endpointPath while it was being applied. For Distributed Tracing support however the endpoint path is more or less required since it should be used as the span name.

    opened by slashmo 11
  • 0.16.2, compilation error - HBLogRequestsMiddleware 32: Argument HBURL does not conform to expected type 'Sendable'

    0.16.2, compilation error - HBLogRequestsMiddleware 32: Argument HBURL does not conform to expected type 'Sendable'

    Hi, I just updated to 0.16.2 and I'm getting a compilation error on lines 32 & 38 of HBLogRequestsMiddleware where it's attempting to log request.uri:

    if self.includeHeaders {
        request.logger.log(
            level: self.logLevel,
            "\(request.headers)",
            metadata: ["hb_uri": .stringConvertible(request.uri), "hb_method": .string(request.method.rawValue)] <-- Error!
        )
    } else {
        request.logger.log(
            level: self.logLevel,
            "",
            metadata: ["hb_uri": .stringConvertible(request.uri), "hb_method": .string(request.method.rawValue)] <-- Error!
        )
    }
    

    Not sure why this is coming up now as it hasn't changed for some time and neither has the code in .stringConvertable(...).

    opened by drekka 7
  • Change HBRequest/HBResponse to struct

    Change HBRequest/HBResponse to struct

    Made HBRequest and HBResponse structs. This should make moving to a full async/await implementation a little easier as they become automatically Sendable as long as all their members are Sendable.

    For most situations, code changes related to HBResponse becoming a struct involves making a mutable instance of the response.

    It is slightly more complex for HBRequest. HBRequest is large enough such that converting it to a struct actually reduces performance. To fix this I have moved all the parameters of HBRequest that are read only into an internal class. There is no point copying all this data through all the response generators. Storing it in a class means only a reference to the data is passed through.

    Having HBRequest as a struct also means some APIs that would have edited the request have had to change. You can see this in changes to hummingbird-auth

    opened by adam-fowler 7
  • Handling incoming request with stream body

    Handling incoming request with stream body

    Hi, I've setup my server to look at the request.body as a ByteBuffer to get the contents of the incoming request. However I'm receiving an unexpected request from the app (not under my control) that is returning a stream instead of a byte buffer. I'm trying to figure out how to read this stream and have been digging through the Hummingbird code base to try and figure it out but not having much luck so far.

    For byte buffers I've been doing

    let buffer = request.body.buffer
    let data = buffer.getData(at: 0, length: buffer.readableBytes)
    

    But this crashes when the body is set to a stream.

    Any ides how to read the data?

    opened by drekka 6
  • Use ComponentLifecycle in HBApplication

    Use ComponentLifecycle in HBApplication

    In my server applications I usually have two servers running, one for the public API of a service and one for the admin API (e.g. to expose a /metrics route), but I still want them to run in the same process/container. I'd like to be able to use ServiceLifecycle to pull them all together but that's currently not possible since HBApplication creates its own top-level lifecycle. If we were to use ComponentLifecycle instead, an HBApplication and all its lifecycle tasks could be registered as a subcomponent of a larger lifecycle, which could look like this:

    let lifecycle = ServiceLifecycle()
    
    let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
    lifecycle.registerShutdown(label: "event-loop-group", .async(eventLoopGroup.shutdownGracefully))
    
    let publicApp = HBApplication(
        configuration: .init(
            address: .hostname(options.host, port: Int(options.publicPort)),
            serverName: "Example API",
            logLevel: options.logLevel
        ),
        eventLoopGroupProvider: .shared(eventLoopGroup)
    )
    lifecycle.register(publicApp.lifecycle)
    
    let adminApp = HBApplication(
        configuration: .init(
            address: .hostname(options.host, port: Int(options.adminPort)),
            serverName: "Example API [Admin]",
            logLevel: options.logLevel
        ),
        eventLoopGroupProvider: .shared(eventLoopGroup)
    )
    lifecycle.register(adminApp.lifecycle)
    
    try lifecycle.startAndWait()
    
    opened by slashmo 6
  • Adds 'errorResponseHandler' to HBApplication to allow HBHTTPResponseErrors to be intercepted and a custom response returned

    Adds 'errorResponseHandler' to HBApplication to allow HBHTTPResponseErrors to be intercepted and a custom response returned

    As promised, this is the second PR. It introduces the ability to handle a HBHTTPResponseError and provide a custom response, falling back to the default implementation in HTTPResponder using HBHTTPResponseError if the errorResponseHandler is not provided.

    The reason for this PR is that I wanted to continue using standard HBHTTPErrors e.g. HBHTTPError(.notFound) at the higher-levels of the application, but have the ability to create/manipulate a custom response in-place of the ones provided by HBHTTPResponseError itself at a global level.

    opened by SoftwareEngineerChris 6
  • Hummingbird dependency swift-service-lifecycle won't compile on iOS

    Hummingbird dependency swift-service-lifecycle won't compile on iOS

    Trying to add Hummingbird to a project but I'm getting errors compiling swift-service-lifecycle. It appears that classes in there use Task which is iOS13 and above, whilst Hummingbird's package indicates it's minimum version as iOS12 and regardless of the iOS version I set on the project, it won't compile.

    Any idea how to fix this?

    See comment below for more info from a package project I was trying to use. Have since also tried in a single screen iOS app and got the same compilation error.

    opened by drekka 5
  • HBParameters doesn't handle repeating query parameters.

    HBParameters doesn't handle repeating query parameters.

    Just came across some API calls here with repeating query parameters. Things like ...?category=cars&category=engines (a bit contrived but still possible). I looked in the code for HBParameters and it's coded like I would have done it in that it's baed on a dictionary. But with this new information it needs to be able to handle repeating keys with different values. So I'm thinking more like an array of tuples or some simple struct type.

    opened by drekka 4
  • Replacing future wait with run loop

    Replacing future wait with run loop

    Pursuant to the discussion in https://github.com/hummingbird-project/hummingbird/issues/132 I messed about to see if I could come up with something that would allow the future to resolve and the current thread to release.

    The NIO API doco actually suggests that using .wait() might not be a good idea so I decided to try replacing the promise/future with run loop execution. It worked, allowing the .start() function to throw an error if the port was not available both iOS and OSX.

    However, I'm not an expert in the the NIO code or all the depths of multithreading at that level so whilst this solutions works, it may not be the best one.

    All tests were run and green with this code.

    opened by drekka 3
  • Adjust file handling to handle loading from bundles

    Adjust file handling to handle loading from bundles

    I was trying to load files from a bundle of files passed to a test suite. In my server setup I had this middleware:

    let configuration = HBApplication.Configuration()
    let server = HBApplication(configuration: configuration)
    server.middleware.add(HBFileMiddleware(Bundle.testData.filePath.absoluteString, application: server))
    try server.start()
    

    However whenever I requested a file from the testData bundle HBFileMiddleware failed to find it.

    I debugged through and found that the string based root folder was being set to a file:///... path which was not understood by the file code attempting to load the file.

    This PR:

    • Converts rootFolder to be a file URL instead of a string.
    • Updates usage of rootFolder based on it now being a URL. ie. rootFolder.relativePath.
    • Removes checking for a trailing / which is no longer needed.

    Testing

    After the code change all Hummingbird test ran green without change.

    opened by drekka 3
Releases(1.0.0-alpha.2)
  • 1.0.0-alpha.2(Dec 7, 2022)

    Major release changes

    • EventLoopStorage has been removed. The one use case for it has been removed.

    Minor release changes

    • Hummingbird now requires Swift 5.5 (inline with SwiftNIO)
    • HBRequest, HBResponse and related types conform to Sendable

    Patch release changes

    • Use new NIOAsyncTestingChannel.waitForOutboundWrite in HBXCTAsyncTesting
    • Add new HBHTTPConvertChannel to convert from HTTPServerResponsePart to Sendable type

    Other changes

    • Fix integration test compilation
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0-alpha.1(Nov 17, 2022)

    Major version changes

    • Add ServiceLifecycleProvider which allows you to pass in a lifecycle to the HBApplication, or create a new one. PR #142 from @slashmo
    • Remove backLog and tcpNoDelay configuration settings when using Network framework
    • Stop exporting so many symbols from dependencies.
    • Move XCTTestingSetup outside of HBApplication

    Minor version changes

    • Add new XCT test setup .asyncTest for testing code using Swift Concurrency. PR #144
    • Add HBRequest.CollateBody which can be used in middleware to collate the request body. PR #147
    • Make HBApplication.Persist.driver public

    Patch version changes

    • Use NIOLock instead of Lock. PR #143
    Source code(tar.gz)
    Source code(zip)
  • 0.16.3(Sep 27, 2022)

  • 0.16.2(Jul 31, 2022)

  • 0.16.1(Jul 11, 2022)

  • 0.16.0(Feb 19, 2022)

    • Add HBConnectionPoolGroup connection manager. Used to manage connections to external services on a per EventLoop basis. Use HBConnectionSource to generate connections to service (HBConnection).
    • Add Swift concurrency APIs for HBConnectionPoolGroup
    • Use hummingbird-core v0.13.5
    Source code(tar.gz)
    Source code(zip)
  • 0.15.3(Dec 13, 2021)

  • 0.15.2(Dec 4, 2021)

  • 0.15.1(Dec 2, 2021)

  • 0.15.0(Nov 29, 2021)

  • 0.14.4(Nov 26, 2021)

    Patch release changes

    • Fix crash in HBParser when creating a sub parser at the end of a string. Caused a crash when parsing URL test?.

    Other changes

    • Renamed sanity.sh to validate.sh
    Source code(tar.gz)
    Source code(zip)
  • 0.14.3(Nov 1, 2021)

    Minor release changes

    • Added async versions of HBFileIO apis

    Patch release changes

    • Don't run job if application is shutting down

    Other changes

    Upgrade to Swift Format v0.48.17

    Source code(tar.gz)
    Source code(zip)
  • 0.14.2(Oct 22, 2021)

  • 0.14.1(Oct 22, 2021)

    Minor Release changes

    • Added async version of HBJobQueue.enqueue
    • Added HBAsyncJob protocol
    • Remove default value for numWorkers in HBJobQueueHandler.registerQueue and HBApplication.addJobs

    Patch release changes

    • Minor optimisation in HBURL.init for when path does not include scheme and host.

    Other changes

    • Added memory allocation counter integration tests
    Source code(tar.gz)
    Source code(zip)
  • 0.14.0(Oct 16, 2021)

    Minor version changes

    • Add new HummingbirdJobs library that allows you to offload work to another server. PR #104

    Patch version changes

    • Apply application log level to lifecycle
    • Only patch responses on routes flagged .editResponse in async-await code
    Source code(tar.gz)
    Source code(zip)
  • 0.13.3(Oct 6, 2021)

    Minor release changes

    • Added HBMediaType.withParameter to create new media type with a parameter.

    Patch release changes

    • Optimisations
      • Don't capture all of HBRequest in HTTPResponder.respond closures.
      • Don't patch HBResponse if no patch has been setup
      • Added final to class definitions
    Source code(tar.gz)
    Source code(zip)
  • 0.13.2(Sep 30, 2021)

  • 0.13.1(Sep 24, 2021)

    Patch release changes

    • Ensure concurrency code is only compiled when _Concurrency framework is available
    • Remove _NIOConcurrency imports as NIO functions have been moved into NIOCore
    • URLEncodedForm.NodeValue is now a struct

    Other changes

    • Use swift:5.5 docker images in CI
    Source code(tar.gz)
    Source code(zip)
  • 0.13.0(Sep 21, 2021)

    Breaking changes

    • HBRequest and HBResponse have been changed from classes to structs. This is in a bid to reduce race conditions during async calls. This will impact any code where you are mutating either of these, but should make it clearer where edits are being made.
    • bodyCollation parameter in route handler functions has been changed into a set of options which include .streamBody.
    • Added option .editResponse which indicates you are going to edit a route response via HBRequest.response. Not setting this will cause a crash.

    Minor release changes

    • Added support for async/await in Swift 5.5
      • Added async route handlers
      • Added HBAsyncMiddleware protocol
      • Added HBAsyncRouteHandler for async versions of HBRouteHandler
      • Added async versions of persist framework functions.
    • Added HBApplication.Configuration.with() to generate new configuration with edited change.
    • XCT test framework binds to port zero by default.

    Patch release changes

    • Add more informative messaging for when an extension doesn’t exist.
    • HBRequest.cookies returns a temporary object instead of caching the cookies in an ‘HBRequest` extension.
    • Replace import NIO with NIOCore or NIOPosix where applicable.
    Source code(tar.gz)
    Source code(zip)
  • 0.12.1(Aug 24, 2021)

  • 0.12.0(Jun 24, 2021)

  • 0.11.4(Jun 7, 2021)

    • Minor optimization: Remove one unnecessary EventLoopFuture.map for routes that return an EventLoopFuture
    • Minor optimization: Metrics middleware uses whenComplete instead of flatMap/map
    Source code(tar.gz)
    Source code(zip)
  • 0.11.3(May 21, 2021)

    • Use HBXCTClient from HummingbirdCoreXCT for testing instead of AsyncHTTPClient
    • Fix memory leaks associated with HBDateCache and HBXCTLive
    Source code(tar.gz)
    Source code(zip)
  • 0.11.2(May 18, 2021)

    • HBRequest.Persist.create throws an error if the key already exists.
    • XCT calls run on EmbeddedEventLoop to ensure all submit and execute calls are run
    • HBRequest logger stores id as .stringConvertible instead of .string
    • Setup up a performance executable for testing framework performance
    Source code(tar.gz)
    Source code(zip)
  • 0.11.1(May 7, 2021)

    • HBXCTLive shutdowns down the AyncHTTPClient if server start fails to allow the correct error to be reported
    • HBApplication.Configuration is now initialized with a TSTLSOptions instead of NWProtocolTLS.Options?
    Source code(tar.gz)
    Source code(zip)
  • 0.11.0(Apr 26, 2021)

    • Add support for iOS. Networking for iOS builds is implemented through NIO Transport Services. TLS should be setup using HBApplication.Configuration.tlsOptions when using NIO Transport Services. PR #71
    • Add context object to supply HBRequest with current EventLoop, ByteBufferAllocator and remoteAddress instead of copying these values into HBRequest. PR #75
    • Allow HBApplication.start() to throw errors. PR #73
    Source code(tar.gz)
    Source code(zip)
  • 0.10.0(Apr 16, 2021)

    • Added persist framework for storing key/value pairs across requests
    • Can replace headers set in HBResponseGenerator using request.header.replaceOrAdd. Previously this would output both headers
    • Added HBRequest.remoteAddress
    Source code(tar.gz)
    Source code(zip)
  • 0.9.0(Apr 7, 2021)

    • Using hummingbird-core v0.8.0
    • Add HBRouterMethods.group to create a new HBRouterGroup off current setup of methods.
    • Add HBRouterHandler type for encapsulating everything a route needs along with its handle function.
    • Add HBParameters.require that throws an error if parameter does not exist.
    • Create HBRequest.parameters object if it doesn't already exist
    • Add HBEnvironment.shared for global access to environment variables
    • Fix parsing of multiple cookies, previously only the first cookie was parsed
    Source code(tar.gz)
    Source code(zip)
  • 0.8.1(Apr 1, 2021)

  • 0.8.0(Mar 30, 2021)

    • Uses v0.7.0 of hummingbird-core
    • Logging changes. Errors are logged as either debug or warning depending on whether they are recognised by Hummingbird
    • Add logLevel to HBApplication.Configuration
    • logLevel if not set explicitly will use LOG_LEVEL environment variable
    Source code(tar.gz)
    Source code(zip)
Owner
Hummingbird
Lightweight, flexible HTTP server framework written in Swift
Hummingbird
FlyingFox - a lightweight HTTP server built using Swift Concurrency

Usage Credits Introduction FlyingFox is a lightweight HTTP server built using Swift Concurrency. The server uses non blocking BSD sockets, handling ea

Simon Whitty 262 Dec 24, 2022
Tiny http server engine written in Swift programming language.

What is Swifter? Tiny http server engine written in Swift programming language. Branches * stable - lands on CocoaPods and others. Supports the latest

null 3.6k Dec 31, 2022
A simple GCD based HTTP client and server, written in 'pure' Swift

SwiftyHTTP Note: I'm probably not going to update this any further - If you need a Swift networking toolset for the server side, consider: Macro.swift

Always Right Institute 116 Aug 6, 2022
A simple HTTP server written in Swift

http4swift http4swift is a tiny HTTP server library for Nest-compatible applications. This project is unstable, and the API might be changed at anytim

Shun Takebayashi 27 Jun 29, 2022
A Swift web framework and HTTP server.

A Swift Web Framework and HTTP Server Summary Kitura is a web framework and web server that is created for web services written in Swift. For more inf

Kitura 7.6k Jan 6, 2023
libuv base Swift web HTTP server framework

Notice Trevi now open a Trevi Community. Yoseob/Trevi project split up into respective Trevi, lime, middlewares and sys packages at our community. If

leeyoseob 46 Jan 29, 2022
Http - Demo for Http Layer

http Example To run the example project, clone the repo, and run pod install fro

null 0 Jan 24, 2022
Swift HTTP server using the pre-fork worker model

Curassow Curassow is a Swift Nest HTTP Server. It uses the pre-fork worker model and it's similar to Python's Gunicorn and Ruby's Unicorn. It exposes

Kyle Fuller Archive 397 Oct 30, 2022
A very basic proof-of-concept Swift HTTP server that does not require Foundation

Swift Server Introduction This is very rough and basic HTTP server written in Swift without using Foundation. This is partially based on the Swifter r

Cezary Wojcik 55 Apr 27, 2022
A lightweight library for writing HTTP web servers with Swift

Taylor Disclaimer: Not actively working on it anymore. You can check out some alternatives Swift 2.0 required. Working with Xcode 7.1. Disclaimer: It

Jorge Izquierdo 925 Nov 17, 2022
📡 RealHTTP is a lightweight yet powerful client-side HTTP library.

RealHTTP RealHTTP is a lightweight yet powerful client-side HTTP library. Our goal is make an easy to use and effortless http client for Swift. Featur

Immobiliare Labs 233 Jan 7, 2023
QwikHttp is a robust, yet lightweight and simple to use HTTP networking library for iOS, tvOS and watchOS

QwikHttp is a robust, yet lightweight and simple to use HTTP networking library. It allows you to customize every aspect of your http requests within a single line of code, using a Builder style syntax to keep your code super clean.

Logan Sease 2 Mar 20, 2022
Lightweight lib around NSURLSession to ease HTTP calls

AeroGear iOS HTTP Thin layer to take care of your http requests working with NSURLSession. Project Info License: Apache License, Version 2.0 Build: Co

AeroGear 44 Sep 27, 2022
Lightweight library for web server applications in Swift on macOS and Linux powered by coroutines.

Why Zewo? • Support • Community • Contributing Zewo Zewo is a lightweight library for web applications in Swift. What sets Zewo apart? Zewo is not a w

Zewo 1.9k Dec 22, 2022
Http Request wrapper written in Swift

Net Net is a HttpRequest wrapper written in Swift Features GET, POST, PUT, DELETE method Powerful request params: nested params, number, string, dic,

Le Van Nghia 304 Jun 29, 2022
ServiceData is an HTTP networking library written in Swift which can download different types of data.

ServiceData Package Description : ServiceData is an HTTP networking library written in Swift which can download different types of data. Features List

Mubarak Alseif 0 Nov 11, 2021
Swift/Obj-C HTTP framework with a focus on REST and JSON

Now Archived and Forked PMHTTP will not be maintained in this repository going forward. Please use, create issues on, and make PRs to the fork of PHMT

Postmates Inc. 509 Sep 4, 2022
A Concise HTTP Framework in Swift

NetKit A Concise HTTP Framework in Swift. Requirements NetKit requires Swift 5.0 and Xcode 10.2 Installation CocoaPods You can use CocoaPods to integr

Aziz Uysal 4 Apr 23, 2019
A little and powerful iOS framework for intercepting HTTP/HTTPS Traffic.

A little and powerful iOS framework for intercepting HTTP/HTTPS Traffic.

Proxyman 867 Dec 29, 2022