Home

Awesome

<img src="Hyperdrive.png" width=51 height=49 alt="Hyperdrive Logo" />

Hyperdrive Build Status

Hyperdrive is a generic Hypermedia API client in Swift. Hyperdrive allows you to build an application which can evolve at run-time and does not hard-code implementation details such as URIs and HTTP methods into your application. You simply enter your API using the root URI and explore it's funcitonality at run-time by understanding the semantics of the domain instead of knowledge about the implementation.

Usage

Below is a short example of using Hyperdrive to communicate with a Hypermedia API. An API that offers information about how it works at run-time using hyperlinks.

We're going to connect to a Polls API, an API which allows you to view questions, vote for them and create new questions with multiple-choice answers.

let hyperdrive = Hyperdrive()

To get started, we will enter the API from its root URI. We will pass it an asynchronous function to be executed with a result from the API.

hyperdrive.enter("https://polls.apiblueprint.org/") { result in
  switch result {
    case .Success(let representor):
      print("The API has offered us the following transitions: \(representor.transitions)")

    case .Failure(let error):
      print("Unfortunately there was an error: \(error)")
  }
}

On success, we have a Representor, this is a structure representing the API resource. It includes relations to other resources along with information about how we can transition from the current state to another.

Our client understands the semantics behind “questions” and explicitly looks for a transition to them on our API.

if let questions = representor.transitions["questions"] {
  print("Our API has a transition to a questions resource.")
} else {
  print("Looks like this API doesn’t support questions, or " +
          "the feature was removed.")
}

Since our API has a transition to a collection of questions, let’s retrieve them and take a look:

hyperdrive.request(questions) { result in
  switch result {
    case .Success(let representor):
      print("We’ve received a representor for the questions.")

    case .Failure(let error):
      print("There was a problem retreiving the questions: \(error)")
  }
}

On success, we have another representor representing the questions resource in our API.

if let questions = representor.representors["questions"] {
  // Our representor includes a collection of Question resources.
  // Let’s use map to call viewQuestion for each one
  map(questions, viewQuestion)
} else {
  print("Looks like there are no questions yet.")
  print("Perhaps the API offers us the ability to create a question?")
}

With every question in this resource, we will call our viewQuestion function:

func viewQuestion(question:Representor<HTTPTransition>) {
  print(question.attributes["question"])

  if let choices = question.representors["choices"] {
    for choice in choices {
      let text = choice.attributes["choice"]
      let votes = choice.attributes["votes"]
      print('-> \(text) (\(votes))')
    }
  } else {
    print("-> This question does not have any choices.")
  }
}

Transitioning from one state to another

A representor includes information on how to transition from one state to another. For example, we might be presented with the ability to delete one of our questions:

if let delete = question.transitions["delete"] {
  // We can perform this transition with Hyperdrive
  hyperdrive.request(delete)
} else {
  print("The API doesn’t offer us the ability to delete a question.")
  print("Let’s gracefully handle the lack of this feature and " +
          "remove deletion from our user interface.")
}

We may also be presented with an option to vote on a choice:

if let vote = choice.transitions["vote"] {
  hyperdrive.request(vote)
}

Transitions with attributes

A transition may also provide attributes for performing the transition. For example, our API may afford us to perform a transition to create a new question.

if let create = questions.transitions["create"] {
  let attributes = [
    "question": "Favourite programming language?",
    "choices": [
      "Swift",
      "Python",
      "Ruby",
    ]
  ]

  hyperdrive.request(create, attributes)
} else {
  // Our API doesn’t allow us to create a question. We should remove the
  // ability to create a question in our user interface.
  // This transition may only be available to certain users.
}

Transitions also include the available attributes you can send for run-time introspection.

create.attributes

This allows you to generate user interface that can adapt to changes from the API. You can also use validation for an attribute.

Content Types

Hyperdrive supports the following Hypermedia content-types:

For APIs which do not support Hypermedia content types, you may use an API description in form of an API Blueprint to load these controls.

Installation

CocoaPods is the recommended installation method.

pod 'Hyperdrive'

Elsehwere

License

Hyperdrive is released under the MIT license. See LICENSE.