All Projects → kevin0571 → Dratini

kevin0571 / Dratini

Licence: mit
Dratini is a neat network abstraction layer.

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Dratini

Hp Socket
High Performance TCP/UDP/HTTP Communication Component
Stars: ✭ 4,420 (+11531.58%)
Mutual labels:  network, networking
Bmon
bandwidth monitor and rate estimator
Stars: ✭ 787 (+1971.05%)
Mutual labels:  network, networking
Gns3 Server
GNS3 server
Stars: ✭ 477 (+1155.26%)
Mutual labels:  network, networking
Xdp
Package xdp allows one to use XDP sockets from the Go programming language.
Stars: ✭ 36 (-5.26%)
Mutual labels:  network, networking
Librg
🚀 Making multi-player gamedev simpler since 2017
Stars: ✭ 813 (+2039.47%)
Mutual labels:  network, networking
Cocoadebug
iOS Debugging Tool 🚀
Stars: ✭ 3,769 (+9818.42%)
Mutual labels:  network, networking
Grassmarlin
Provides situational awareness of Industrial Control Systems (ICS) and Supervisory Control and Data Acquisition (SCADA) networks in support of network security assessments. #nsacyber
Stars: ✭ 621 (+1534.21%)
Mutual labels:  network, networking
P2p Graph
Real-time P2P network visualization with D3
Stars: ✭ 245 (+544.74%)
Mutual labels:  network, networking
Diffios
Cisco IOS diff tool
Stars: ✭ 23 (-39.47%)
Mutual labels:  network, networking
P2p
Practice project to demonstrate p2p file sharing.
Stars: ✭ 16 (-57.89%)
Mutual labels:  network, networking
Game Networking Resources
A Curated List of Game Network Programming Resources
Stars: ✭ 4,208 (+10973.68%)
Mutual labels:  network, networking
Bash Toolkit
Este proyecto esá destinado a ayudar a los sysadmin
Stars: ✭ 13 (-65.79%)
Mutual labels:  network, networking
Exscript
A Python module making Telnet and SSH easy
Stars: ✭ 337 (+786.84%)
Mutual labels:  network, networking
Ceras
Universal binary serializer for a wide variety of scenarios https://discord.gg/FGaCX4c
Stars: ✭ 374 (+884.21%)
Mutual labels:  network, networking
React Native Network Info
React Native library for getting information about the devices network
Stars: ✭ 313 (+723.68%)
Mutual labels:  network, networking
Fast Android Networking
🚀 A Complete Fast Android Networking Library that also supports HTTP/2 🚀
Stars: ✭ 5,346 (+13968.42%)
Mutual labels:  network, networking
Golden Gate
Framework to connect wearables and other IoT devices to mobile phones, tablets and PCs with an IP-based protocol stack over Bluetooth Low Energy
Stars: ✭ 223 (+486.84%)
Mutual labels:  network, networking
Fire
🔥A delightful HTTP/HTTPS networking framework for iOS/macOS/watchOS/tvOS platforms written in Swift.
Stars: ✭ 243 (+539.47%)
Mutual labels:  network, networking
Nexer
Content based network multiplexer or redirector made with love and Go
Stars: ✭ 7 (-81.58%)
Mutual labels:  network, networking
Metta
An information security preparedness tool to do adversarial simulation.
Stars: ✭ 867 (+2181.58%)
Mutual labels:  network, networking

Dratini CI Status codecov CocoaPods Carthage Swift Pacakge Manager License

Dratini is a neat network abstraction layer.
If you are looking for a solution to make your network layer neat, Dratini is your choice.
Dratini uses protocols to define network request, parameters and response, which makes your network layer more readable and testable.

Features

  • Protocol base design.
  • Auto serialization for parameters.
  • Response is observable by request id or response type.
  • UI non-blocking since request and response handling happen in background thread.
  • Request and response are interceptable by using delegate.
  • RxSwift extension is available: RxDratini

Requirements

  • Xcode 8.0+
  • Swift 3.0

Dependencies

  • Ditto: it's used for serializing Swift object into JSON compatible dictionary, mainly used for impelmenting DefaultQueryString, URLEncodedBodyData and JSONBodyData.

Usage

CocoaPods

pod 'Dratini'

Carthage

github "kevin0571/Dratini"

Swift Package Manager

dependencies: [
    .Package(url: "https://github.com/kevin0571/Dratini.git", majorVersion: 1)
]

Overview

Here are some basic steps to send out a request and observe for its response.

Setup RequestQueue:

let requestQueue = RequestQueue(baseURL: URL(string: "http://example.com"))
// Delegate and configuration are not required.
// Set the delegate(RequestQueueDelegate) if you wish to get callbacks for each step.
// RequestQueueConfiguration.default is used if configuration is not specified.

Keep a shared RequestQueue is recommended:

extension RequestQueue {
    static let shared = RequestQueue(baseURL: URL(string: "http://example.com"))
}

Describe your request, parameters and response:

struct LogInRequest: Request {
    typealias ParametersType = LogInParameters
    typealias ResponseType = LogInResponse
    
    var parameters: LogInParameters
    
    func path() -> String {
        return "/login"
    }
    
    func method() -> HTTPMethod {
        return .post
    }
}

// There are several built-in Parameters types:
// - DefaultQueryString for query string, it will mostly be used in GET request.
// - URLEncodedBodyData for URL encoded body data.
// - JSONBodyData for JSON format body data.
// - MultipartFormData for multipart form data, it will mostly be used for uploading file.
//
// In order to allow you to keep the naming convention of different platforms,
// property name of DefaultQueryString, URLEncodedBodyData and JSONBodyData will be mapped to other naming convention.
// By default property will be converted to lowercase name separated by underscore,
// e.g. accessToken will be converted to access_token. 
// You can set the mapping by overriding "serializableMapping" function.
// See more details in Ditto project's README.
struct LogInParameters: URLEncodedBodyData {
    let username: String
    let password: String
}

struct LogInResponse: Response {
    let username: String
    let name: String
    init?(data: ResponseData, response: URLResponse) {
        // - Use data.data to access raw response data.
        // - Use data.jsonObject to access JSON format dictionary.
        // - Use data.jsonArray to access JSON format array.
        // - Use data.string to access UTF8 string.
        guard let username = data.jsonObject["username"] as? String,
            let name = data.jsonObject["name"] as? String else {
            return nil
        }
        self.username = username
        self.name = name
    }
}

Send the request and observe for response:

let request = LogInRequest(parameters: LogInParameters(username: username,
                                                       password: password))
let requestID = RequestQueue.shared.add(request)
// Observe by using requestID.
// The observer will be removed by RequestQueue after the request is finished.
requestQueue.addObserver(for: requestID) { (result: Result<LogInResponse>) in
    guard let response = result.response else {
        // Show error message
        return
    }
    // Update UI by using response.username and response.name
}
// Observe a specific response type. 
// The observer is owned by an owner. The owner is held weakly by RequestQueue,
// thus the observer will be removed if owner is released.
requestQueue.addObserver(ownedBy: self) { [weak self] (result: Result<LogInResponse>) in
    // ...
}
// NOTE: observer callback is called in main thread.

Do More with Dratini

Sometimes you need to do more with Dratini, here are some features you might need, e.g. upload file, intercept different states of request and response.

Upload file:

let data = MultipartFormData()
// Append file with fileURL
data.append(fileURL: fileURL, withName: name, fileName: fileName, mimeType: "application/x-plist")  
// Append raw file data
data.append(data: fileData, withName: name, fileName: fileName, mimeType: "application/x-plist")

// Assume we've created UploadFileRequest
let request = UploadFileRequest(parameters: data)
// Send out request
// ...

Intercept states of request:

// Conform to Request with RequestDelegate to get callbacks of different states.
struct LogInRequest: Request, RequestDelegate {
    // ...
    
    func requestWillSend(_ urlRequest: inout URLRequest) {
        // Called before request is sent out.
        // You are able to modify the URLRequest: update HTTP header for example.
    }
    
    func requestDidSend(_ urlRequest: URLRequest) {
        // Called after request is sent out.
    }
    
    func request(_ urlRequest: URLRequest, didFailWith error: DRError) {
        // Called when request is failed to be sent out or response is failed to be created.
    }
}

Validate response before creating response and intercept states of response:

struct LogInResponse: Response, ResponseDelegate {
    // ...
    
    // Validate the response before it's created.
    static func validate(_ response: URLResponse) -> Bool {
        guard let httpResponse = response as? HTTPURLResponse else {
            return true
        }
        return httpResponse.statusCode >= 200 &&
            httpResponse.statusCode < 300 &&
            httpResponse.allHeaderFields["Token"] != nil
    }
    
    // Called after response is created.
    func responseDidReceive(_ response: URLResponse) {
        guard let httpResponse = response as? HTTPURLResponse,
            let token = httpResponse.allHeaderFields["Token"] else {
            return nil
        }
        // Save your token
    }
}

Having common logic for all requests and response are sometimes necessary, RequestQueueDelegate is here for you:

class MyRequestQueueDelegate: RequestQueueDelegate {
    public func requestQueue(_ requestQueue: RequestQueue, willSend request: inout URLRequest) {
        // Called before each request is sent out.
    }
    
    public func requestQueue(_ requestQueue: RequestQueue, didSend request: URLRequest) {
        // Called after each request is sent out.
    }
    
    public func requestQueue(_ requestQueue: RequestQueue, didFailWith request: URLRequest, error: DRError) {
        // Called when request is failed to be sent out or response is failed to be created.
    }
    
    public func requestQueue(_ requestQueue: RequestQueue, didReceive response: URLResponse) {
        // Called after response is created.
    }
}

extension RequestQueue {
    // Set delegate when creating RequestQueue.
    static let shared = RequestQueue(delegate: MyRequestQueueDelegate(), baseURL: URL(string: "http://example.com")!)
}

Check if request is finished and cancel it:

let isFinished = RequestQueue.shared.isFinished(requestID)
RequestQueue.shared.cancel(requestID)

Helpers

When you don't really need a Parameters or Response, you can use:

EmptyParameters
EmptyResponse

Customization

If you wish to customize query string or body data encoding, you can implement your own by adpoting QueryString or BodyData protocol.

struct MyBodyData: BodyData {
    let string: String
    
    var contentType: String {
        return "my-content-type"
    }
    
    func encode() throws -> Data {
        return string.data(using: .utf8)!
    }
}
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].