All Projects → freshOS → Ws

freshOS / Ws

Licence: mit
⚠️ Deprecated - (in favour of Networking) ☁️ Elegantly connect to a JSON api. (Alamofire + Promises + JSON Parsing)

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Ws

Networking
⚡️ Elegantly connect to a REST JSON Api. URLSession + Combine + Decodable + Generics = <3
Stars: ✭ 499 (+41.76%)
Mutual labels:  rest-api, rest, json, networking, httpclient
Restclient
🦄 Simple HTTP and REST client for Unity based on Promises, also supports Callbacks! 🎮
Stars: ✭ 675 (+91.76%)
Mutual labels:  rest-api, rest, json, httpclient
Rest Assured
Java DSL for easy testing of REST services
Stars: ✭ 5,646 (+1503.98%)
Mutual labels:  rest-api, rest, json
Imbo
Imbo is an image "server" that can be used to add/get/delete images using a RESTful interface.
Stars: ✭ 312 (-11.36%)
Mutual labels:  rest-api, rest, json
Generator Http Fake Backend
Yeoman generator for building a fake backend by providing the content of JSON files or JavaScript objects through configurable routes.
Stars: ✭ 49 (-86.08%)
Mutual labels:  rest-api, rest, json
Node Rest Client
REST API client from node.js
Stars: ✭ 365 (+3.69%)
Mutual labels:  rest-api, rest, json
Spyke
Interact with REST services in an ActiveRecord-like manner
Stars: ✭ 591 (+67.9%)
Mutual labels:  rest-api, rest, json
Rest Api Examples
Test and Prototype with Fake Online REST/OAuth 2 APIs Examples
Stars: ✭ 13 (-96.31%)
Mutual labels:  rest-api, rest, json
Swagger Express Ts
Generate and serve swagger.json
Stars: ✭ 102 (-71.02%)
Mutual labels:  rest-api, rest, json
Json Serverless
Transform a JSON file into a serverless REST API in AWS cloud
Stars: ✭ 108 (-69.32%)
Mutual labels:  rest-api, rest, json
Poloniex Api Node
Poloniex API client for REST and WebSocket API
Stars: ✭ 138 (-60.8%)
Mutual labels:  rest-api, rest, promise
Api Client Generator
Angular REST API client generator from Swagger YAML or JSON file with camel case settigs
Stars: ✭ 92 (-73.86%)
Mutual labels:  rest, json, httpclient
Pmhttp
Swift/Obj-C HTTP framework with a focus on REST and JSON
Stars: ✭ 509 (+44.6%)
Mutual labels:  rest, json, networking
Netclient Ios
Versatile HTTP Networking in Swift
Stars: ✭ 117 (-66.76%)
Mutual labels:  json, networking, alamofire
Http Fake Backend
Build a fake backend by providing the content of JSON files or JavaScript objects through configurable routes.
Stars: ✭ 253 (-28.12%)
Mutual labels:  rest-api, rest, json
Json Api Dart
JSON:API client for Dart/Flutter
Stars: ✭ 53 (-84.94%)
Mutual labels:  rest-api, rest, json
Grafanajsondatasource
Grafana datasource to load JSON data over your arbitrary HTTP backend
Stars: ✭ 146 (-58.52%)
Mutual labels:  rest-api, rest, json
Httpie
As easy as /aitch-tee-tee-pie/ 🥧 Modern, user-friendly command-line HTTP client for the API era. JSON support, colors, sessions, downloads, plugins & more. https://twitter.com/httpie
Stars: ✭ 53,052 (+14971.59%)
Mutual labels:  rest-api, rest, json
Restyped
End-to-end typing for REST APIs with TypeScript
Stars: ✭ 287 (-18.47%)
Mutual labels:  rest-api, rest
Korio
Korio: Kotlin cORoutines I/O : Virtual File System + Async/Sync Streams + Async TCP Client/Server + WebSockets for Multiplatform Kotlin 1.3
Stars: ✭ 282 (-19.89%)
Mutual labels:  json, httpclient

ws

⚠ Important Notice: Farewell ws... hello Networking !

Networking is the next generation of the ws project. Think of it as ws 2.0 built for iOS13. It uses Combine native Apple's framework over Then Promise Library, removes Arrow dependency to favour Codable (Arrow can still be adapted easily though) and removes the Alamofire dependency in favour of a simpler purely native URLSession implementation. In essence, less dependencies and more native stuff with an almost identical api. If your app supports iOS13 and up, it is strongly advised to migrate to Networking. WS will be "maintained" for backwards compatibility reasons but consider it deprected starting iOS13.

ws

Language: Swift 5 Platform: iOS 8+ Carthage compatible Cocoapods compatible License: MIT Build Status codebeat badge Release version

Reason - Example - Installation

let ws = WS("http://jsonplaceholder.typicode.com")

ws.get("/users").then { json in
    // Get back some json \o/
}

Because JSON apis are used in 99% of iOS Apps, this should be simple.
We developers should focus on our app logic rather than boilerplate code .
Less code is better code

Try it!

ws is part of freshOS iOS toolset. Try it in an example App ! Download Starter Project

How

By providing a lightweight client that automates boilerplate code everyone has to write.
By exposing a delightfully simple api to get the job done simply, clearly, quickly.
Getting swift models from a JSON api is now a problem of the past

What

  • [x] Build concise Apis
  • [x] Automatically maps your models
  • [x] Built-in network logger
  • [x] Stands on the shoulder of giants (Alamofire & Promises)
  • [x] Pure Swift, Simple & Lightweight

Usage

Bare JSON

import ws // Import ws at the top of your file
import Arrow // Import Arrow to get access to the JSON type

class ViewController: UIViewController {

    // Set webservice base URL
    let ws = WS("http://jsonplaceholder.typicode.com")

    override func viewDidLoad() {
        super.viewDidLoad()

       // Get back some json instantly \o/
       ws.get("/users").then { (json:JSON) in
           print(json)
       }
    }
}

Set up Model parsing

Create a User+JSON.swift file and map the JSON keys to your model properties

import Arrow

extension User: ArrowParsable {

    mutating func deserialize(_ json: JSON) {
        identifier <-- json["id"]
        username <-- json["username"]
        email <-- json["email"]
    }
}

Note: ws uses Arrow for JSON Parsing https://github.com/freshOS/Arrow

Choose what you want back

Here you are going to create a function that wraps your request. There are different ways of writing that function depending on what you want back. An empty block, the JSON, the model or the array of models.

func voidCall() -> Promise<Void> {
    return ws.get("/users")
}

func jsonCall() -> Promise<JSON> {
    return ws.get("/users")
}

func singleModelCall() -> Promise<User> {
    return ws.get("/users/3")
}

func modelArrayCall() -> Promise<[User]> {
    return ws.get("/users")
}

As you can notice, only by changing the return type, ws automatically knows what to do, for instance, try to parse the response into User models.

This enables us to stay concise without having to write extra code. \o/

Note: ws uses then for Promises https://github.com/freshOS/then

Get it!

voidCall().then {
    print("done")
}

jsonCall().then { json in
    print(json)
}

singleModelCall().then { user in
    print(user) // Strongly typed User \o/
}

modelArrayCall().then { users in
    print(users) // Strongly typed [User] \o/
}

Settings

Want to log all network calls and responses?

ws.logLevels = .debug

Want to hide network activity indicator?

ws.showsNetworkActivityIndicator = false

Want to override the default session manager to customize trust policies?

import Alamofire

ws.sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(
  policies: ["myspecialhostname.com" : .disableEvaluation]
))

Api Example

Here is a Typical CRUD example for Articles :

extension Article {

    static func list() -> Promise<[Article]> {
        return ws.get("/articles")
    }

    func save() -> Promise<Article> {
        return ws.post("/articles", params: ["name":name])
    }

    func fetch() -> Promise<Article> {
        return ws.get("/articles/\(id)")
    }

    func update() -> Promise<Void> {
        return ws.put("/articles/\(id)", params: ["name":name])
    }

    func delete() -> Promise<Void> {
        return ws.delete("/articles/\(id)")
    }

}

Here is how we use it in code :

// List Articles
Article.list().then { articles in

}

// Create Article
var newArticle = Article(name:"Cool story")
newArticle.save().then { createdArticle in

}

// Fetch Article
var existingArticle = Article(id:42)
existingArticle.fetch().then { fetchedArticle in

}

// Edit Article
existingArticle.name = "My new name"
existingArticle.update().then {

}

// Delete Article
existingArticle.delete().then {

}

HTTP Status code

When a request fails, we often want to know the reason thanks to the HTTP status code. Here is how to get it :

ws.get("/users").then {
    // Do something
}.onError { e in
    if let wsError = e as? WSError {
        print(wsError.status)
        print(wsError.status.rawValue) // RawValue for Int status
    }
}

You can find the full WSError enum here -> https://github.com/freshOS/ws/blob/master/ws/WSError.swift

Bonus - Load More pattern

Very often we deal we lists and the ability to load more items. Here we are going to see an example implementation of this pattern using ws. This is not included because the logic itself depends on your backend implementation. This will give you an example for you to roll out your own version.

Implementation

import ws
import then
import Arrow


class LoadMoreRequest<T:ArrowParsable> {

    var limit = 12

    private var params = [String:Any]()
    private var offset = 0
    private var call: WSRequest!
    private var canLoadMore = true
    private var aCallback:((_ ts: [T]) -> [T])? = nil

    init(_ aCall: WSRequest) {
        call = aCall
    }

    func resetOffset() {
        offset = 0
        canLoadMore = true
    }

    func hasMoreItemsToload() -> Bool {
        return canLoadMore
    }

    func fetchNext() -> Promise<[T]> {
        params = call.params
        params["limit"] = limit
        params["offset"] = offset
        call.params = params
        offset += limit
        return call.fetch()
                .registerThen(parseModels)
                .resolveOnMainThread()
    }

    private func parseModels(_ json: JSON) -> [T] {
        let mapper = WSModelJSONParser<T>()
        let models = mapper.toModels(json)
        if models.count < limit {
            canLoadMore = false
        }
        return models
    }
}

As you can see, we have a strongly typed request.
The limit is adjustable.
It encapsulates a WSRequest.
It handles the offset logic and also wether or not there are more items to load.

And that's all we need!

Now, this is how we build a LoadMoreRequest

func loadMoreUsersRequest() -> LoadMoreRequest<User> {
    return LoadMoreRequest(ws.getRequest("/users"))
}

Usage

And here is how we use it in our controllers :

class ViewController: UIViewController {

    // Get a request
    let request = api.loadMoreUsersRequest()

    override func viewDidLoad() {
        super.viewDidLoad()
        request.limit = 5 // Set a limit if needed
    }

    func refresh() {
      // Resets the request, usually plugged with
      // the pull to refresh feature of a tableview
      request.resetOffset()
    }

    func loadMore() {
      // Get the next round of users
      request.fetchNext().then { users in
          print(users)
      }
    }

    func shouldDisplayLoadMoreSpinner() -> Bool {
      // This asks the requests if there are more items to come
      // This is useful to know if we show the "load more" spinner
      return request.hasMoreItemsToload()
    }
}

Here you go you now have a simple way to deal with load more requests in your App 🎉

Bonus - Simplifying restful routes usage

When working with a RESTFUL api, we can have fun and go a little further.

By introducing a RestResource protocol

public protocol RestResource {
    static func restName() -> String
    func restId() -> String
}

We can have a function that builds our REST URL

public func restURL<T:RestResource>(_ r:T) -> String {
    return "/\(T.restName())/\(r.restId())"
}

We conform our User Model to the protocol

extension User:RestResource {
    static func restName() -> String { return "users" }
    func restId() -> String { return "\(identifier)" }
}

And we can implement a version of get that takes our a RestResource

public func get<T:ArrowParsable & RestResource>(_ restResource:T, params:[String:Any] = [String:Any]()) -> Promise<T> {               
    return get(restURL(restResource), params: params)
}

then

ws.get("/users/\(user.identifier)")

Can be written like :

ws.get(user)

Of course, the same logic can be applied to the all the other ws functions (post, put delete etc) ! 🎉

Installation

Swift Package Manager (SPM)

Due to the challenge of supporting all package manager at once, SPM support is availlable on a separate branch spm-only.

Carthage

In your Cartfile

github "freshOS/ws"
  • Run carthage update
  • Drag and drop ws.framework from Carthage/Build/iOS to Linked Frameworks and Libraries (“General” settings tab)
  • Go to Project > Target > Build Phases + New run Script Phase

/usr/local/bin/carthage copy-frameworks

Add input files

$(SRCROOT)/Carthage/Build/iOS/ws.framework
$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework
$(SRCROOT)/Carthage/Build/iOS/Arrow.framework
$(SRCROOT)/Carthage/Build/iOS/then.framework

This links ws and its dependencies.

Manually

Carthage is pretty useful since it takes care of pulling dependencies such as Arrow, then and Alamofire. What's cool is that it really is transparent. What I mean is that you could just use carthage on the side to pull and build dependencies and manually link frameworks to your Xcode project.

Without Carthage, I'd see 2 solutions : 1 - Copy paste all the source code : ws / then / Arrow / Alamofire which doesn't sound like a lot of fun ;) 2 - Manually link the frameworks (ws + dependencies) by A grabbing .frameworks them on each repo, or B use Carthage to build them

Cocoapods

target 'MyApp'
pod 'ws'
use_frameworks!

Swift Version

Swift 2 -> version 1.3.0
Swift 3 -> version 2.0.4
Swift 4 -> version 3.0.0
Swift 4.1 -> version 3.1.0
Swift 4.2 -> version 3.2.0
Swift 5.0 -> version 5.0.0
Swift 5.1 -> version 5.1.0
Swift 5.1.3 -> version 5.1.1

Backers

Like the project? Offer coffee or support us with a monthly donation and help us continue our activities :)

Sponsors

Become a sponsor and get your logo on our README on Github with a link to your site :)

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