blackfish alternatives and similar libraries
Based on the "Server" category.
Alternatively, view Blackfish alternatives based on common mentions on social networks and blogs.
-
Perfect
Server-side Swift. The Perfect core toolset and framework for Swift Developers. (For mobile back-end development, website and API development, and moreโฆ) -
GCDWebServer
DISCONTINUED. The #1 HTTP server for iOS, macOS & tvOS (also includes web based uploader & WebDAV server) -
Zewo
Lightweight library for web server applications in Swift on macOS and Linux powered by coroutines. -
smoke-framework
A light-weight server-side service framework written in the Swift programming language.
SaaSHub - Software Alternatives and Reviews
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of blackfish or a related project?
README

Blackfire
๐ฅ Getting Started
If you're familiar with express.js then Blackfire will be known to you. The most simple example of how to use can be seen below:
main.swift
import Blackfire
// Create a nice new ๐ฅ app for us to play with.
let app = Flame()
// Let's add a route to begin with.
app.get("/") { (req, res) in
res.send(text: "Hello World")
}
app.start(port: 3000) { result in
switch result {
case .success:
print("Server started on port 3000")
case .failure(let error):
ย ย ย print("Server failed with error: \(error)")
ย }
}
$ curl localhost:3000
Hello World%
๐ Features
Blackfire has all the standard features of a typical minimal Web Framework, let's take a look at some of these.
๐ฑ Routing
Routing, as seen in the above example, takes place by assigning a handler to a method in your App
app.get("/") { (req, res) in
res.send(text: "I'm a GET request")
}
app.post("/users") { (req, res) in
res.send(text: "I'm a POST request to /users")
}
app.delete("/all/files") { (req, res) in
res.send(text: "I'm a DELETE request to /all/files ...wait")
}
app.put("/em/up") { (req, res) in
res.send(text: "I'm a PUT request to /em/up Am I being robbed?")
}
This can become tedious if you have a lot of /users/<something> routes however, so we created the........
๐ Router
The router object allows you to group routes together. For example
let users = Router()
users.get("/") { req, res in
res.send(text: "Get me all the users")
}
users.post("/") { req, res in
res.send(text: "Creating a new user")
}
users.get("/favourites") { req, res in
ย res.send(json: ["food": "๐"])
}
// Let's use the router to match for /users
app.use("/users", users)
$ curl localhost:3000/users
Get me all the users%
$ curl localhost:3000/users/favourites
{"food":"๐"}%
Powerful stuff.
๐ซ Request
The request or req object contains a bunch of helpful information that your handler may want to use:
These include:
request.paramsA key value pair ofStringsthat are matched in the routerequest.bodyThe raw body of the recieved request, in the form of aStringrequest.headersA key value pair ofStringsof the headers that appeared in the routerequest.methodThe method of this request, formed from theHTTPMethodenum.request.pathThe path of this requestrequest.httpProtocolThe protocol for this request.
๐ฃ Response
The response or res object contains everything you need to return data back to the consumer
res.send(text: String)Send back a basic text response in the form ofContent-Type: text/plainres.send(json: Any)Send back some JSON, takes in a JSON parseable object. This method can fail if the object is not parseableres.send(status: Int)Send back a HTTP status with no bodyres.send(html: String)Send back some html with the header ofContent-Type: text/htmlres.send(error: String)Sends back an error, setting the status to500.res.headersSet some headers to send back to the client
๐ Threading
Threading is a contentious issue when it comes to web frameworks, the age old question of Single vs Multithreaded is enough to start a flame war.
So let's fight the fire with fire and solve it once and for all.
๐ธ Queue Types
A Flame app can take a type of either .serial or .concurrent. These do exactly as they say on the tin and allow for either all requests to be handled via DispatchQueue.main or DispatchQueue.global().
Why did we do this?
We think that giving you the power to choose which type you want for your app is a good thing. We're not sorry.
Just as an FYI, we chose to go with .serial as the default setting. It was a 50/50 chance we got it right. Good thing it can be changed.
Example
// An app which handles only on the main thread.
let app = Flame(type: .serial)
// An app which handles on multiple concurrent threads.
let app = Flame(type: .concurrent)
*Note that all licence references and agreements mentioned in the blackfish README section above
are relevant to that project's source code only.