Latest 1.3.0
License MIT
Platforms ios 10.0
Dependencies SDWebImage, PromiseKit




Spider is an easy-to-use web framework built for speed & readability. Spider’s modern syntax & response handling makes working with web services fun again.



Spider is integrated with CocoaPods!

  1. Add the following to your Podfile:
    pod 'Spider-Web'
  2. In your project directory, run pod install
  3. Import the Spider module wherever you need it
  4. Profit


You can also manually add the source files to your project.

  1. Clone this git repo
  2. Add all the Swift files in the Spider/ subdirectory to your project
  3. Profit

The Basics

Spider can be used in many different ways. Many times, a shared (one-off) approach is all that’s needed.

Spider.web.get("https://path/to/endpoint") { (response) in
    print("We got a response!")

This simply makes a GET request with a given path & parameters, and returns a SpiderResponse object.


The SpiderResponse object is a fancy object that encapsulates relevant properties of an HTTP response. It contains 4 properties: the SpiderRequest request (req), URLResponse object (res), response data (data), and an error object (err). Easy to use & understand, plus it helps keep our code readable! Hooray!

Base URLs

Because we typically make more than one request to a given API, using base URLs just makes sense. This is also useful when we need to switch between versions of API’s (i.e. dev, pre-prod, prod, etc…).

let spider = Spider.web(withBaseUrl: "https://base.url/v1")

spider.get("/users") { (response) in
    print("We got a response!")

spider.get("/locations") { (response) in
    print("We got another response!")

Notice how we can now make requests to specific endpoints with the same shared base url. The above requests would hit the endpoints:


If a base url is not specified, Spider will assume the path of your request is a fully qualified url (as seen in the first example).

Request Parameters

All variations of SpiderRequest instantiation have a means for you to pass in request parameters. For example:

let params = ["user_id": "123456789"]
Spider.web.get("https://path/to/endpoint", parameters: params) { (response) in
    print("We got a response!")

This will take your parameters and pass them along in the request’s body.

Spider Instances

So far, we have been working with the shared (global) instance of Spider. This is usually all you need. Just in case you need more control, Spider also supports a more typical instantiation flow.

let tarantula = Spider()
tarantula.get("https://path/to/endpoint") { (response) in
    print("Tarantula got a response!")

Instead of using the shared Spider instance, we created our own instance named tarantuala and made a request with it. Spooky! Naturally, Spider instances created like this also support base urls:

let blackWidow = Spider(baseUrl: "https://base.url/v1")
blackWidow.get("/users") { (response) in
    print("Black Widow got a response!")

Advanced & Multipart Requests

Spider also supports more fine-tuned request options. You can configure and perform a SpiderRequest manually:

let request = SpiderRequest(method: "GET", path: "https://path/to/endpoint", parameters: nil)
request.header.accept = [.image_jpeg, .custom("custom_accept_type")]
request.header.set(value: "12345", forHeaderField: "user_id")

Spider.web.perform(request) { (response) in
    print("We got a response!")

Multipart data requests can also be constructed & executed in a similar fashion:

let data = UIImagePNGRepresentation(image)!
let file = MultipartFile(data: data, key: "image", name: "image.png", type: .image_png)
let request = SpiderMultipartRequest(method: "PUT",
                                     path: "https://path/to/upload",
                                     parameters: nil,
                                     files: [file],
                                     auth: nil)

Spider.web.perform(request) { (response) in
    print("We got a response!")

SpiderMultipartRequest is a SpiderRequest subclass that is initialized with an array of MultipartFile objects. Everything else works the exact same as a normal (non-multipart) request.


Currently, Spider supports the following authorization types:

  • Basic (user:pass base64 encoded)
  • Token

Authorization can be added on a per-request or instance-based basis. Typically we would want to provide our Spider instance authorization that all requests would be sent with:

let token = TokenAuth(value: "0123456789")
let bigHairySpider = Spider.web(withBaseUrl: "https://base.url/v1", auth: token)
bigHairySpider.get("/topSecretData") { (response) in
    print("Big hairy spider got a response!")

However, authorization can also be provided on a per-request basis if it better fits your situation:

let token = TokenAuth(value: "0123456789")
let aSpider = Spider.web(withBaseUrl: "https://base.url/v1")
aSpider.get("/topSecretData", auth: token) { (response) in
    print("Spider got a response!")

Advanced requests can also provide authorization:

let token = TokenAuth(value: "0123456789")

let request = SpiderRequest(method: "GET", path: "https://path/to/endpoint")
request.header.accept = [.image_jpeg, .custom("custom_accept_type")]
request.header.set(value: "12345", forHeaderField: "user_id")
request.auth = token

Spider.web.perform(request) { (response) in
    print("We got a response!")

By default, auth is added to the "Authorization" header field of your request. This can be changed by passing in a custom field when creating the auth:

let basic = BasicAuth(username: "root", password: "pa55w0rd", headerField: "Credentials")
let charlotte = Spider.web(withBaseUrl: "https://base.url/v1", auth: basic)
charlotte.get("/topSecretData") { (response) in
    print("Charlotte got a response!")

The authorization type can also be customized if needed. For example, BasicAuth generates the following for the credentials root:pa55w0rd

Basic cm9vdDpwYTU1dzByZA==

In this case the "Basic" prefix before the encoded credentials is the authorization type. This can be customized as follows:

let basic = BasicAuth(username: "root", password: "pa55w0rd")
basic.type = "Login"

let spider = Spider.web(withBaseUrl: "https://base.url/v1", auth: basic)
spider.get("/topSecretData") { (response) in
    print("Got a response!")

Likewise, the TokenAuth "Bearer" type can be modified in the same way.

Working with Responses

As mentioned above, SpiderResponse objects are clean & easy to work with. A typical data response might look something like this:

Spider.web.get("https://some/data/endpoint") { (response) in

    guard let data =, response.err == nil else {

        var message = "There was an error fetching the data"
        if let error = response.err {
            message = error



    print("Successfully fetched the data: (data)")


A lot of the time the data we’re interested in is JSON formatted. Spider makes this kind of response easy to work with.

Spider.web.get("https://some/json/endpoint") { (response) in

    guard let json = response.json(), response.err == nil else {

        var message = "There was an error fetching the json object"
        if let error = response.err {
            message = error



    print("Successfully fetched the json object: (json)")


Notice how we call json() on our response. This nifty little function attempts to serialize our response data into a JSON object. Likewise, jsonArray() will attempt to serialize our response data into an array of JSON objects.

Spider.web.get("https://list/of/users") { (response) in

    guard let users = response.jsonArray(), response.err == nil else {

        var message = "There was an error fetching the json object"
        if let error = response.err {
            message = error



    for dict in users {
        print("Fetched user: (dict["name"] as! String)")



Response serialization is handled on the SpiderResponse object. The functions json() & jsonArray() are provided via an extension on SpiderResponse. Likewise, to implement custom response serialization, simply extend the SpiderResponse object as needed. For example, UIImage response serialization might look something like this:

extension SpiderResponse {

    func image() -> UIImage? {

        guard let data = else { return nil }

        if let image = UIImage(data: data) {
            return image

        return nil



With that implemented, working with an image serialized response would work as follows:

Spider.web.get("https://path/to/image.png") { (response) in

    guard let image = response.image(), response.err == nil else {

        var message = "There was an error fetching the image"
        if let error = response.err {
            message = error



    print("Fetched image: (image)")


Spider has built-in support for the following object serialization types:

  • JSON & [JSON]
  • UIImage


Image downloading & caching is supported via SpiderImageDownloader & SpiderImageCache. Spider uses the excellent SDWebImage library to manage image downloading & caching behind-the-scenes.


Downloading images with SpiderImageDownloader is easy!

SpiderImageDownloader.getImage("") { (image, isCachedImage, error) in

    guard let image = image, error == nil else {
        // Handle error

    // Do something with the image!


The above getImage() function returns a discardable token that can be used to cancel the image download if needed:

let token = SpiderImageDownloader.getImage("") { (image, isCachedImage, error) in

SpiderImageDownloader.cancel(for: token)

By default, SpiderImageDownloader does not cache downloaded images. If you want images to be cached, simply set the cache flag to true when calling the getImage() function.


Caching, fetching, & removing images from the cache:

let image: UIImage = ...
let key = "my_image_key"

// Add an image to the cache
SpiderImageCache.shared.cache(image, forKey: key)

// Fetch an image from the cache
if let image = SpiderImageCache.shared.image(forKey: key) {
    // Do something with the image!

// Remove an image from the cache
SpiderImageCache.shared.removeImage(forKey: key)

You can also clean the cache:

// Clean the disk cache

// Clean the memory cache

// Clean all caches

UIKit Integration

Spider also has some nifty UIKit integrations, like UIImageView image downloading!


Currently, Spider has integrations for the following UIKit components:

  • UIImageView


Spider has basic object mapping features via it’s Weaver class. Objects wishing to integrate with Spider’s mapping features simply need to conform to Swift 4’s built-in Codable protocol:

struct User: Codable {

    var name: String
    var age: Int

Spider.web.get("https://get/user/123") { (response) in

    guard let userDict = response.json(), response.err == nil else {

        var message = "There was an error fetching the json object"
        if let error = response.err {
            message = error



    if let user = Weaver<User>(userDict).map() {
        print("Fetched user: (")


Array mapping:

Spider.web.get("https://list/of/users") { (response) in

    guard let userArray = response.jsonArray(), response.err == nil else {

        var message = "There was an error fetching the json array"
        if let error = response.err {
            message = error



    if let users = Weaver<User>(userArray).arrayMap() {
        print("Fetched (users.count) users")



Spider has built-in support for PromiseKit. Promises help keep your codebase clean & readable by eliminating pesky nested callbacks.

Spider.web.get("").then { (response) -> Promise<SpiderResponse> in

    guard let photos = response.jsonArray(), response.err == nil && photos.count > 0 else {
        throw SpiderError.badResponse

    return Spider.web.get(path: photos[0]["url"] as! String)

}.then { (response) -> Void in

    guard let image = response.image() else {
        throw SpiderError.badResponse


}.catch { (error) in



This is just a basic example of how promises can help organize your code. For more information, please visit PromiseKit. I highly encourage you to consider using promises whenever possible.


Some useful additions are also included to help cut down on development & debugging time.

Debug Mode

Enabling Spider’s isDebugModeEnabled flag will print all debug information (including all outgoing requests) to the console.

cURL Generation

SpiderRequest includes a printCURL() function that, as the name implies, prints the cURL command for a given request.

let request = SpiderRequest(method: "GET", path: "https://path/to/endpoint", parameters: ["user_id": "1234"])
request.header.set(value: "bar", forField: "foo")


curl https://path/to/endpoint 
-H "foo: bar" 
-d "user_id=1234"

NOTE: If your request is dependent on a Spider instance’s baseUrl or authorization properties,
cURL information will not be accurate until after the request is performed.


  • Better error handling for Weaver object mapping
  • Objective-C compatibility
  • Test coverage


Pull-requests are more than welcome. Bug fix? Feature? Open a PR and we’ll get it merged in!

Latest podspec

    "name": "Spider-Web",
    "module_name": "Spider",
    "version": "1.3.0",
    "summary": "Creepy web framework for Swift.",
    "description": "Spider is an easy-to-use web framework built fornspeed & readability. Spider's modern syntax & response handlingnmakes working with web services fun again.",
    "homepage": "",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    "authors": {
        "Mitch Treece": "[email protected]"
    "source": {
        "git": "",
        "tag": "1.3.0"
    "social_media_url": "",
    "platforms": {
        "ios": "10.0"
    "source_files": "Spider/Classes/**/*",
    "dependencies": {
        "SDWebImage": [
            "~> 4.0"
        "PromiseKit": [
            "~> 4.4"
    "pushed_with_swift_version": "3.0"

Pin It on Pinterest

Share This