All Projects → thecatalinstan → Criollo

thecatalinstan / Criollo

Licence: mit
A powerful Cocoa web framework and HTTP server for macOS, iOS and tvOS.

Projects that are alternatives of or similar to Criollo

Orsserialport
Serial port library for Objective-C and Swift macOS apps
Stars: ✭ 609 (+165.94%)
Mutual labels:  framework, osx, cocoapods, cocoa
Fire
🔥A delightful HTTP/HTTPS networking framework for iOS/macOS/watchOS/tvOS platforms written in Swift.
Stars: ✭ 243 (+6.11%)
Mutual labels:  osx, cocoapods, https
Kvantum
An intellectual (HTTP/HTTPS) web server with support for server side templating (Crush, Apache Velocity and JTwig)
Stars: ✭ 17 (-92.58%)
Mutual labels:  webserver, https, http-server
Pode
Pode is a Cross-Platform PowerShell web framework for creating REST APIs, Web Sites, and TCP/SMTP servers
Stars: ✭ 329 (+43.67%)
Mutual labels:  framework, https, webserver
Octane
A web server modeled after express in Rust.
Stars: ✭ 136 (-40.61%)
Mutual labels:  https, http-server, webserver
Pure Http
✨ The simple web framework for Node.js with zero dependencies.
Stars: ✭ 139 (-39.3%)
Mutual labels:  framework, http-server, webserver
Libhv
🔥 比libevent、libuv更易用的国产网络库。A c/c++ network library for developing TCP/UDP/SSL/HTTP/WebSocket client/server.
Stars: ✭ 3,355 (+1365.07%)
Mutual labels:  https, http-server, webserver
Restana
Super fast and minimalist framework for building REST micro-services.
Stars: ✭ 341 (+48.91%)
Mutual labels:  framework, http-server, webserver
Beetlex
high performance dotnet core socket tcp communication components, support TLS, HTTP, HTTPS, WebSocket, RPC, Redis protocols, custom protocols and 1M connections problem solution
Stars: ✭ 802 (+250.22%)
Mutual labels:  https, http-server, webserver
Cppwebframework
​The C++ Web Framework (CWF) is a MVC web framework, Open Source, under MIT License, using C++ with Qt to be used in the development of web applications.
Stars: ✭ 348 (+51.97%)
Mutual labels:  framework, http-server, webserver
Danode
Small and flexible web server written using the D 2.0 language
Stars: ✭ 50 (-78.17%)
Mutual labels:  standalone, framework, webserver
Webcpp
用C++开发web服务器框架
Stars: ✭ 23 (-89.96%)
Mutual labels:  framework, http-server, webserver
Proxy.py
⚡⚡⚡Fast, Lightweight, Pluggable, TLS interception capable proxy server focused on Network monitoring, controls & Application development, testing, debugging
Stars: ✭ 1,291 (+463.76%)
Mutual labels:  framework, http-server, webserver
Gofast
gofast is a FastCGI "client" library written purely in go
Stars: ✭ 140 (-38.86%)
Mutual labels:  webserver, fastcgi
Platypus
Create native Mac applications from command line scripts.
Stars: ✭ 1,893 (+726.64%)
Mutual labels:  osx, cocoa
Buymeacoffee
Buy Me a Coffee framework for iOS
Stars: ✭ 145 (-36.68%)
Mutual labels:  framework, cocoapods
Httpp
Micro http server and client written in C++
Stars: ✭ 144 (-37.12%)
Mutual labels:  https, http-server
Siris
DEPRECATED: The community driven fork of Iris. The fastest web framework for Golang!
Stars: ✭ 146 (-36.24%)
Mutual labels:  framework, https
Haproxy
HAProxy Load Balancer's development branch (mirror of git.haproxy.org)
Stars: ✭ 2,463 (+975.55%)
Mutual labels:  https, fastcgi
Cheroot
Cheroot is the high-performance, pure-Python HTTP server used by CherryPy. Docs -->
Stars: ✭ 128 (-44.1%)
Mutual labels:  https, http-server

Criollo

A powerful Cocoa web framework and HTTP server for macS, iOS and tvOS.

Build Status Version Status Platform Carthage compatible MIT License Twitter Gitter

Criollo helps create fast standalone or embedded web apps that deliver content directly over HTTP or FastCGI. You can write code in Swift or Objective-C and you can use the Cocoa technologies you already know.

It's as easy as this:

let server = CRHTTPServer()
server.get("/") { (req, res, next) in
  res.send("Hello world!")
}
server.startListening()

... and in Objective-C:

CRServer* server = [[CRHTTPServer alloc] init];
[server get:@"/" block:^(CRRequest *req, CRResponse *res, CRRouteCompletionBlock next) {
  [res send:@"Hello world!"];
}];
[server startListening];

Key Features

Criollo is designed with speed, security and flexibility in mind, that's why it comes with a few very useful features out of the box, thus allowing you to focus on the actual job your project needs to do, without having to jump through hoops in order to make it happen.

HTTPS

Criollo fully supports HTTPS on all platforms. You can pass the credentials as a PKCS#12 identity and password, or an X509 certificate and private key pair, either PEM or DER encoded.

server.isSecure = true

// Credentials: PKCS#12 Identity and password
server.identityPath = Bundle.main.path(forResource: "identity", ofType: "p12")
server.password = "123456"

// Credentials: PEM-encoded certificate and public key
server.certificatePath = Bundle.main.path(forResource: "certificate", ofType: "pem")
server.privateKeyPath = Bundle.main.path(forResource: "key", ofType: "pem")

// Credentials: DER-encoded certificate and public key
server.certificatePath = Bundle.main.path(forResource: "certificate", ofType: "der")
server.privateKeyPath = Bundle.main.path(forResource: "key", ofType: "der")

... and in Objective-C:

server.isSecure = YES;
        
// Credentials: PKCS#12 Identity and password
server.identityPath = [NSBundle.mainBundle pathForResource:@"identity" ofType:@"p12"];
server.password = @"password";
        
// Credentials: PEM-encoded certificate and public key
server.certificatePath = [NSBundle.mainBundle pathForResource:@"certificate" ofType:@"pem"];
server.privateKeyPath = [NSBundle.mainBundle pathForResource:@"key" ofType:@"pem"];
        
// Credentials: DER-encoded certificate and public key
server.certificatePath = [NSBundle.mainBundle pathForResource:@"certificate" ofType:@"der"];
server.privateKeyPath = [NSBundle.mainBundle pathForResource:@"key" ofType:@"der"];

Routing

When defining routes, paths can be specified in three ways:

  • Fixed string (ex. /api). This will match the string exactly.
  • Placeholders (ex. /posts/:pid). The next path component after /posts, will be matched and added to request.query under the pid key.
  • Regex patterns (ex. /[0-9]{4}/[0-9]{1,2}/[a-zA-Z0-9-]+). When the three patterns are matched, they are added to request.query, under the keys 0, 1 and 2 respectively.
server.add("/api") { (req, res, next) in
  // /api/?pid=12345
  res.send(req.query)
}

server.add("/posts/:pid") { (req, res, next) in
  // /posts/12345
  res.send(req.query)
}

server.add("/[0-9]{4}/[0-9]{1,2}/[a-zA-Z0-9-]+") { (req, res, next) in
  // /2017/10/my-first-criollo-app
  res.send(req.query)
}

... and in Objective-C:

[server add:@"/api" block:^(CRRequest *req, CRResponse *res, CRRouteCompletionBlock next) {
  // /api/?pid=12345
  [res send:req];
}];

[server add:@"/posts/:pid" block:^(CRRequest *req, CRResponse *res, CRRouteCompletionBlock next) {
  // /posts/12345
  [res send:req];
}];

[server add:@"/[0-9]{4}/[0-9]{1,2}/[a-zA-Z0-9-]+" block:^(CRRequest *req, CRResponse *res, CRRouteCompletionBlock next) {
  // /2017/10/my-first-criollo-app
  [res send:req];
}];

Controllers

Controllers provide a very simple way of grouping functionality into one semantical unit. They function as routers and allow you to define routes based on paths relative to the path they are themselves attached to.

// The controller class
class APIController : CRRouteController {
  override init(prefix: String) {
    super.init(prefix: prefix)
    
    self.add("/status") { (req, res, next) in
      res.send(["status": true])
    }
    
  }
}

// Add the controller to the server
server.add("/api", controller:APIController.self)

... and in Objective-C:

// The controller class
@interface APIController : CRRouteController
@end

@implementation APIController

- (instancetype)initWithPrefix:(NSString *)prefix {
  self = [super initWithPrefix:prefix];
  if ( self != nil ) {
    
    [self add:@"/status" block:^(CRRequest *req, CRResponse *res, CRRouteCompletionBlock next) {
      [res send:@{@"status": @YES}];
    }];
         
  }
}

@end

// Add the controller to the server
[server add:@"/api" controller:APIController.class];

Views and View Controllers

View controllers render view objects, constructed from HTML resource files by calling the view's render method. This is achieved by the CRViewConroller, CRView and CRNib APIs respectively.

View controllers are powerful objects that allow you to easily standardise an app's appearance and group functionality together into a coherent unit.

HTML template file:

<!-- Define some placeholders -->
<!DOCTYPE html>
  <html lang="en">
  <head>
    <title>{{title}}</title>
  </head>
  <body>
    <h1>{{title}}</h1>
    <p>{{content}}</p>
  </body>
</html>

Source code:

// The view controller class
class HelloWorldViewController: CRViewController {
  
  override func present(with request: CRRequest, response: CRResponse) -> String {
    self.vars["title"] = String(describing: type(of: self))
    self.vars["content"] = "Hello from the view controller."

    return super.present(with: request, response: response)
  }
  
}

// Add the view controller to server
server.add("/controller", viewController: HelloWorldViewController.self, withNibName: "HelloWorldViewController", bundle: nil)

... and in Objective-C:

// The view controller class
@interface HelloWorldViewController : CRViewController
@end

@implementation HelloWorldViewController

- (NSString *)presentViewControllerWithRequest:(CRRequest *)request response:(CRResponse *)response {
    self.vars[@"title"] = NSStringFromClass(self.class);
    self.vars[@"content"] = @"Hello from the view controller.";

    return [super presentViewControllerWithRequest:request response:response];
}

@end

// Add the view controller to server
[server add:@"/controller" viewController:HelloWorldViewController.class withNibName:@"HelloWorldViewController" bundle:nil];

Static File/Directory Serving

Criollo comes with built-in support for exposing both directories and individual over HTTP. The CRStaticFileManager and CRStaticDirectoryManager APIs enable you to do this.

// Expose the home directory (with auto-indexing)
server.mount("/pub", directoryAtPath: "~", options: [.autoIndex])

// Serve a single static file at a path
server.mount("/info.plist", fileAtPath:  Bundle.main.bundlePath.appending("/Info.plist"))

... and in Objective-C

// Expose the home directory (with auto-indexing)
[server mount:@"/pub" directoryAtPath:@"~" options:CRStaticDirectoryServingOptionsAutoIndex];
   
// Serve a single static file at a path 
[server mount:@"/info.plist" fileAtPath:[NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"/Contents/Info.plist"]];

Multipart File Uploads

Criollo comes with builtin support for handling multipart/form-data POST requests, so that you can handle HTML file uploads out of the box. Uploaded files are provided in request.files, as an array of CRUploadedFile objects.

// Serve the first uploaded file back to the client
self.server.post("/image") { (req, res, next) in
  do {
    let data = try Data.init(contentsOf: (req.files!["0"]?.temporaryFileURL)!)
    res.setValue(req.env["HTTP_CONTENT_TYPE"]!, forHTTPHeaderField: "Content-type")
    res.setValue("\(data.count)", forHTTPHeaderField: "Content-Length")
    res.send(data)
  } catch {
    res.setValue("text/plain", forHTTPHeaderField: "Content-type")
    res.setValue("\(error.localizedDescription.count)", forHTTPHeaderField: "Content-length")
    res.send(error.localizedDescription)
  }
}

... and in Objective-C

// Serve the first uploaded file back to the client
[server post:@"/image" block:^(CRRequest *req, CRResponse *res, CRRouteCompletionBlock next) {
  NSError *error;
  NSData *data = [NSData dataWithContentsOfURL:req[0].temporaryFileURL options:0 error:&error];
  if ( error ) {
    [res setValue:@"text/plain" forHTTPHeaderField:@"Content-type"];
    [res setValue:@(error.description.length).stringValue forHTTPHeaderField:@"Content-length"];
    [res sendString:error.description];
  } else {
    [res setValue:request.env[@"HTTP_CONTENT_TYPE"] forHTTPHeaderField:@"Content-type"];
    [res setValue:@(data.length).stringValue forHTTPHeaderField:@"Content-length"];
    [res sendData:data];
  }
}];

Why?

Criollo was created in order to take advantage of the truly awesome tools and APIs that the Apple stack provides and serve content produced with them over the web.

It incorporates an HTTP web server and a FastCGI application server that are used to deliver content. The server is built on Grand Central Dispatch and designed for speed.

How to Use

Criollo can easily be embedded as a web-server inside your macOS, iOS or tvOS app, should you be in need of such a feature, however it was designed to create standalone, long-lived daemon style apps. It is fully launchd compatible and replicates the lifecycle and behavior of NSApplication, so that the learning curve should be as smooth as possible.

For a more real-world example, check out the criollo.io website, made using Criollo and available for your cloning pleasure at https://github.com/thecatalinstan/Criollo-Web.

See the Hello World Multi Target example for a demo of the two usage patterns.

Getting Started

Installing

The preferred way of installing Criollo is through CocoaPods. However, you can also embed the framework in your projects manually.

Installing with CocoaPods

  1. Create the Podfile if you don’t already have one. You can do so by running pod init in the folder of the project.
  2. Add Criollo to your Podfile. pod 'Criollo', '~> 0.5'
  3. Run pod install

Please note that Criollo will download CocoaAsyncSocket as a dependency.

Cloning the repo

Criollo uses CocoaAsyncSocket which is included as a git submodule

git clone --recursive https://github.com/thecatalinstan/Criollo.git

Get in Touch

If you have any questions regarding the project or how to do anything with it, please feel free to get in touch either on Twitter @criolloio or by plain old email [email protected].

I really encourage you to submit an issue, as your input is really and truly appreciated.


Check out the Criollo Blog for news, ideas and updates on Criollo.

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].