All Projects → envoy → Ambassador

envoy / Ambassador

Licence: mit
Super lightweight web framework in Swift based on SWSGI

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Ambassador

Embassy
Super lightweight async HTTP server library in pure Swift runs in iOS / MacOS / Linux
Stars: ✭ 440 (+189.47%)
Mutual labels:  asynchronous, webserver
Tascalate Concurrent
Implementation of blocking (IO-Bound) cancellable java.util.concurrent.CompletionStage and related extensions to java.util.concurrent.ExecutorService-s
Stars: ✭ 144 (-5.26%)
Mutual labels:  asynchronous
Goserv
A lightweight toolkit for web applications in Go
Stars: ✭ 132 (-13.16%)
Mutual labels:  webserver
Pure Http
✨ The simple web framework for Node.js with zero dependencies.
Stars: ✭ 139 (-8.55%)
Mutual labels:  webserver
Hippo
💨A well crafted go packages that help you build robust, reliable, maintainable microservices.
Stars: ✭ 134 (-11.84%)
Mutual labels:  asynchronous
Gofast
gofast is a FastCGI "client" library written purely in go
Stars: ✭ 140 (-7.89%)
Mutual labels:  webserver
Pokeapi Js Wrapper
PokeAPI browser wrapper, fully async with built-in cache
Stars: ✭ 129 (-15.13%)
Mutual labels:  asynchronous
Uhttpsharp
A very lightweight & simple embedded http server for c#
Stars: ✭ 151 (-0.66%)
Mutual labels:  webserver
Tokio
A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...
Stars: ✭ 14,278 (+9293.42%)
Mutual labels:  asynchronous
Easystarjs
An asynchronous A* pathfinding API written in Javascript.
Stars: ✭ 1,743 (+1046.71%)
Mutual labels:  asynchronous
Dhooks
A simple python Discord webhook API wrapper
Stars: ✭ 136 (-10.53%)
Mutual labels:  asynchronous
Octane
A web server modeled after express in Rust.
Stars: ✭ 136 (-10.53%)
Mutual labels:  webserver
Qtpromise
Promises/A+ implementation for Qt/C++
Stars: ✭ 137 (-9.87%)
Mutual labels:  asynchronous
Rubico
[a]synchronous functional programming
Stars: ✭ 133 (-12.5%)
Mutual labels:  asynchronous
Kubernetes asyncio
Python asynchronous client library for Kubernetes http://kubernetes.io/
Stars: ✭ 147 (-3.29%)
Mutual labels:  asynchronous
Spotify.py
🌐 API wrapper for Spotify 🎶
Stars: ✭ 131 (-13.82%)
Mutual labels:  asynchronous
Webserver
A C++ Lightweight Web Server based on Linux epoll
Stars: ✭ 135 (-11.18%)
Mutual labels:  webserver
Owasp Mth3l3m3nt Framework
OWASP Mth3l3m3nt Framework is a penetration testing aiding tool and exploitation framework. It fosters a principle of attack the web using the web as well as pentest on the go through its responsive interface.
Stars: ✭ 139 (-8.55%)
Mutual labels:  webserver
Gulp Server Io
Standalone / gulp (stream) / delivery server setup with Proxy options remote debugger and more
Stars: ✭ 152 (+0%)
Mutual labels:  webserver
Nginx
A fairly flexible and feature full Ansible role for the NGINX web server.
Stars: ✭ 151 (-0.66%)
Mutual labels:  webserver

Ambassador

Build Status CocoaPods Code Climate Issue Count GitHub license

Super lightweight web framework in Swift based on SWSGI

Features

  • Super lightweight
  • Easy to use, designed for UI automatic testing API mocking
  • Based on SWSGI, can run with HTTP server other than Embassy
  • Response handlers designed as middlewares, easy to composite
  • Async friendly

Example

Here's an example how to mock API endpoints with Ambassador and Embassy as the HTTP server.

import Embassy
import EnvoyAmbassador

let loop = try! SelectorEventLoop(selector: try! KqueueSelector())
let router = Router()
let server = DefaultHTTPServer(eventLoop: loop, port: 8080, app: router.app)

router["/api/v2/users"] = DelayResponse(JSONResponse(handler: { _ -> Any in
    return [
        ["id": "01", "name": "john"],
        ["id": "02", "name": "tom"]
    ]
}))

// Start HTTP server to listen on the port
try! server.start()

// Run event loop
loop.runForever()

Then you can visit http://[::1]:8080/api/v2/users in the browser, or use HTTP client to GET the URL and see

[
  {
    "id" : "01",
    "name" : "john"
  },
  {
    "id" : "02",
    "name" : "tom"
  }
]

Router

Router allows you to map different path to different WebApp. Like what you saw in the previous example, to route path /api/v2/users to our response handler, you simply set the desired path with the WebApp as the value

let router = Router()
router["/api/v2/users"] = DelayResponse(JSONResponse(handler: { _ -> Any in
    return [
        ["id": "01", "name": "john"],
        ["id": "02", "name": "tom"]
    ]
}))

and pass router.app as the SWSGI interface to the HTTP server. When the visit path is not found, router.notFoundResponse will be used, it simply returns 404. You can overwrite the notFoundResponse to customize the not found behavior.

You can also map URL with regular expression. For example, you can write this

let router = Router()
router["/api/v2/users/([0-9]+)"] = DelayResponse(JSONResponse(handler: { environ -> Any in
    let captures = environ["ambassador.router_captures"] as! [String]
    return ["id": captures[0], "name": "john"]
}))

Then all requests with URL matching /api/v2/users/([0-9]+) regular expression will be routed here. For all match groups, they will be passed into environment with key ambassador.router_captures as an array of string.

DataResponse

DataResponse is a helper for sending back data. For example, say if you want to make an endpoint to return status code 500, you can do

router["/api/v2/return-error"] = DataResponse(statusCode: 500, statusMessage: "server error")

Status is 200 OK, and content type is application/octet-stream by default, they all can be overwritten via init parameters. You can also provide custom headers and a handler for returning the data. For example:

router["/api/v2/xml"] = DataResponse(
    statusCode: 201,
    statusMessage: "created",
    contentType: "application/xml",
    headers: [("X-Foo-Bar", "My header")]
) { environ -> Data in
    return Data("<xml>who uses xml nowadays?</xml>".utf8)
}

If you prefer to send body back in async manner, you can also use another init that comes with extra sendData function as parameter

router["/api/v2/xml"] = DataResponse(
    statusCode: 201,
    statusMessage: "created",
    contentType: "application/xml",
    headers: [("X-Foo-Bar", "My header")]
) { (environ, sendData) in
    sendData(Data("<xml>who uses xml nowadays?</xml>".utf8))
}

Please notice, unlike sendBody for SWSGI, sendData only expects to be called once with the whole chunk of data.

JSONResponse

Almost identical to DataResponse, except it takes Any instead of bytes and dump the object as JSON format and response it for you. For example:

router["/api/v2/users"] = JSONResponse() { _ -> Any in
    return [
        ["id": "01", "name": "john"],
        ["id": "02", "name": "tom"]
    ]
}

DelayResponse

DelayResponse is a decorator response that delays given response for a while. In real-world, there will always be network latency, to simulte the latency, DelayResponse is very helpful. To delay a response, just do

router["/api/v2/users"] = DelayResponse(JSONResponse(handler: { _ -> Any in
    return [
        ["id": "01", "name": "john"],
        ["id": "02", "name": "tom"]
    ]
}))

By default, it delays the response randomly. You can modify it by passing delay parameter. Like, say if you want to delay it for 10 seconds, then here you do

router["/api/v2/users"] = DelayResponse(JSONResponse(handler: { _ -> Any in
    return [
        ["id": "01", "name": "john"],
        ["id": "02", "name": "tom"]
    ]
}), delay: .delay(10))

The available delay options are

  • .random(min: TimeInterval, max: TimeInterval) delay random, it's also the default one as .random(min: 0.1, max: 3)
  • .delay(seconds: TimeInterval) delay specific period of time
  • .never delay forever, the response will never be returned
  • .none no delay, i.e. the response will be returned immediately

DataReader

To read POST body or any other HTTP body from the request, you need to use swsgi.input function provided in the environ parameter of SWSGI. For example, you can do it like this

router["/api/v2/users"] = JSONResponse() { environ -> Any in
    let input = environ["swsgi.input"] as! SWSGIInput
    input { data in
        // handle the data stream here
    }
}

It's not too hard to do so, however, the data comes in as stream, like

  • "first chunk"
  • "second chunk"
  • ....
  • "" (empty data array indicates EOF)

In most cases, you won't like to handle the data stream manually. To wait all data received and process them at once, you can use DataReader. For instance

router["/api/v2/users"] = JSONResponse() { environ -> Any in
    let input = environ["swsgi.input"] as! SWSGIInput
    DataReader.read(input) { data in
        // handle the whole data here
    }
}

JSONReader

Like DataReader, besides reading the whole chunk of data, JSONReader also parses it as JSON format. Herer's how you do

router["/api/v2/users"] = JSONResponse() { environ -> Any in
    let input = environ["swsgi.input"] as! SWSGIInput
    JSONReader.read(input) { json in
        // handle the json object here
    }
}

URLParametersReader

URLParametersReader waits all data to be received and parses them all at once as URL encoding parameters, like foo=bar&eggs=spam. The parameters will be passed as an array key value pairs as (String, String).

router["/api/v2/users"] = JSONResponse() { environ -> Any in
    let input = environ["swsgi.input"] as! SWSGIInput
    URLParametersReader.read(input) { params in
        // handle the params object here
    }
}

You can also use URLParametersReader.parseURLParameters to parse the URL encoded parameter string if you want. Just do it like

let params = URLParametersReader.parseURLParameters("foo=bar&eggs=spam")

Install

CocoaPods

To install with CocoaPod, add Embassy to your Podfile:

pod 'EnvoyAmbassador', '~> 4.0'

Carthage

To install with Carthage, add Ambassador to your Cartfile:

github "envoy/Ambassador" ~> 4.0

Please notice that you should import Ambassador instead of EnvoyAmbassador. We use EnvoyAmbassador for Cocoapods simply because the name Ambassador was already taken.

Package Manager

To do this, add the repo to Package.swift, like this:

import PackageDescription

let package = Package(
    name: "AmbassadorExample",
    dependencies: [
        .package(url: "https://github.com/envoy/Ambassador.git",
                 from: "4.0.0"),
    ]
)
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].