Skip to content

Commit

Permalink
split to requests and responses
Browse files Browse the repository at this point in the history
  • Loading branch information
eed3si9n committed Apr 12, 2014
1 parent 58bb149 commit 531b5a4
Show file tree
Hide file tree
Showing 7 changed files with 680 additions and 614 deletions.
243 changes: 168 additions & 75 deletions README.md
Expand Up @@ -3,127 +3,220 @@ repatch-github

this is a dispatch plugin for github API v3.

## setup

### using source deps

use source dependency to point to a commit hash of this project.

```scala
import sbt._, Keys._

object build extends Build{
lazy val root = Project(
"project_name",
file(".")
) settings (
scalaVersion := "2.9.2"
) dependsOn (
uri("git://github.com/eed3si9n/repatch-github#hash")
)
}
```

## authentication

you can choose one from the four authenticating clients:

- automatic (`Client`)
- Local Github Config (`LocalConfigClient`)
- OAuth (`OAuthClient`)
- BasicAuth (`BasicAuthClient`)
- none (`NoAuthClient`)

the automatic client uses OAuth token stored in the environment varable `GITHUB_TOKEN` or git config `github.token`.
Local Github Config client uses OAuth token stored in the environment varable `GITHUB_TOKEN` or git config `github.token`.

### setting OAuth token to git config

create token:

```
$ curl -u 'username' -d '{"scopes":[]}' https://api.github.com/authorizations
Enter host password for user 'username': [type password]
{
"app": {
"url": "http://developer.github.com/v3/oauth/#oauth-authorizations-api",
"name": "GitHub API"
},
"token": "your_token",
"updated_at": "2012-12-08T22:13:41Z",
"url": "https://api.github.com/authorizations/123456",
"note_url": null,
"scopes": [
],
"note": null,
"created_at": "2012-12-08T22:13:41Z",
"id": 123456,
}
```
1. [Account settings > Applications](https://github.com/settings/applications)
2. Personal access tokens > Generate new token


then save that token:

```
$ git config --global --add github.token your_token
```

## request builders and response handlers

repatch-github provides two categories of classes: request builders and response handlers.
now we can hit the GitHub API using the token:

request builders, when used in conjunction with authenticating client, build a `dispatch.Req` object. to distinguish from response case classes, these classes ends with `s` like `Repos`.

response handlers helps you parse the response from github.

### repos API using case class handler

```scala
scala> import dispatch._, repatch._, repatch.github._
scala> import dispatch._, Defaults._, repatch.github.request._
import dispatch._
import repatch._
import repatch.github._
import Defaults._
import repatch.github.request._

scala> val http = new Http
http: dispatch.Http = Http(com.ning.http.client.AsyncHttpClient@70e54515)

scala> Http(Client(Repos("dispatch", "dispatch")) > as_github.Repo)
res0: dispatch.Promise[dispatch.github.Repo] = Promise(-incomplete-)
scala> val client = LocalConfigClient
client: repatch.github.request.LocalConfigClient.type = <function1>

scala> http(client(repo("dispatch", "reboot")) > as.json4s.Json)
res0: dispatch.Future[org.json4s.JValue] = scala.concurrent.impl.Promise$DefaultPromise@136e6221

scala> res0()
res1: repatch.github.Repo = Repo(408372,Owner(1115066,Organization,dispatch,...
res1: org.json4s.JValue = JObject(List((id,JInt(2960515)), (name,JString(reboot)), (full_name,JString(dispatch/reboot))...
```

### repos API using json handler
## general design

following the ethos of Dispatch Reboot, repatch-github splits request hander and response handler apart. the request handler is generally responsible for constructing the request URL sometimes with additional parameters or HTTP headers.

you can choose what format you would like Dispatch to return the response in. if you want raw string, you specify `as.String`. if you want json, you say `as.json4s.Json`. to assist the json parsing, repatch-github provides known field names as extractors under the companion object of the response classes.

if you just want a case classes of commonly used fields, you say `as.repatch.github.response.Repo` etc, and it would give you `Repo` case class.

## [repositories](https://developer.github.com/v3/repos/)

here's to querying for a repository as Json.

```scala
scala> Http(Client(Repos("dispatch", "dispatch")) > as_github.Json)
res2: dispatch.Promise[net.liftweb.json.package.JValue] = Promise(-incomplete-)
scala> val x = http(client(repo("dispatch", "reboot")) > as.json4s.Json)
x: dispatch.Future[org.json4s.JValue] = scala.concurrent.impl.Promise$DefaultPromise@2be9d442

scala> res2 map { js =>
import Repo._
full_name(js)
scala> val json = x()
json: org.json4s.JValue = JObject(List((id,JInt(2960515)), (name,JString(reboot)), (full_name,JString(dispatch/reboot)), (owner,JObject(List((login,JString(dispatch)), (id,JInt(1115066)), ....

scala> {
import repatch.github.response.Repo._
import Owner._
login(owner(json))
}
res3: dispatch.Promise[Option[String]] = Promise(Some(dispatch/dispatch))
res0: String = dispatch
```

here's the same query using case class response handler.


```scala
scala> val x = http(client(repo("dispatch", "reboot")) > as.repatch.github.response.Repo)
x: dispatch.Future[repatch.github.response.Repo] = scala.concurrent.impl.Promise$DefaultPromise@15447f19

scala> x()
res5: repatch.github.response.Repo = Repo(2960515,Owner(1115066,Organization,dispatch,https://avatars.githubusercontent.com/u/1115066?,c4050b114966f021d1d91d0b5baabd5c,...
```

## [references](https://developer.github.com/v3/git/refs/)

scala> res3().head
res4: String = dispatch/dispatch
> This will return an array of all the references on the system, including things like notes and stashes if they exist on the server.
```scala
scala> val refs = http(client(repo("dispatch", "reboot").git_refs) > as.repatch.github.response.GitRefs)
refs: dispatch.Future[Seq[repatch.github.response.GitRef]] = scala.concurrent.impl.Promise$DefaultPromise@24a3332a

scala> refs()
res1: Seq[repatch.github.response.GitRef] = List(GitRef(refs/heads/0.9.x,https://api.github.com/repos/dispatch/reboot/git/refs/heads/0.9.x,GitObject(e547dd41a38e5d3c40576d00c929b25fc6d333a6,....
```

### git blob API using string hander
> The ref in the URL must be formatted as `heads/branch`, not just `branch`.
```scala
scala> val ref = http(client(repo("dispatch", "reboot").git_refs.heads("master")) > as.repatch.github.response.GitRef)
ref: dispatch.Future[repatch.github.response.GitRef] = scala.concurrent.impl.Promise$DefaultPromise@7e955067

scala> ref()
res2: repatch.github.response.GitRef = GitRef(refs/heads/master,https://api.github.com/repos/dispatch/reboot/git/refs/heads/master,...
```

## [commits](https://developer.github.com/v3/git/commits/)

> `GET /repos/:owner/:repo/git/commits/:sha`
```scala
scala> val blob_sha = "fb4c8b459f05bcc5296d9c13a3f6757597786f1d"
blob_sha: java.lang.String = fb4c8b459f05bcc5296d9c13a3f6757597786f1d
scala> val commit = http(client(repo("dispatch", "reboot").git_commit("bcf6d255317088ca1e32c6e6ecd4dce1979ac718")) > as.repatch.github.response.GitCommit)
commit: dispatch.Future[repatch.github.response.GitCommit] = scala.concurrent.impl.Promise$DefaultPromise@34110e6b

scala> Http(Client(Repos("dispatch", "dispatch").git_blob(blob_sha).raw) > as.String)
res5: dispatch.Promise[String] = Promise(-incomplete-)
scala> commit()
res0: repatch.github.response.GitCommit = GitCommit(bcf6d255317088ca1e32c6e6ecd4dce1979ac718,https://api.github.com/repos/dispatch/reboot/git/commits/bcf6d255317088ca1e32c6e6ecd4dce1979ac718
```

git reference can also be passed in.

```scala
scala> val commit = for {
master <- http(client(repo("dispatch", "reboot").git_refs.heads("master")) > as.repatch.github.response.GitRef)
x <- http(client(repo("dispatch", "reboot").git_commit(master)) > as.repatch.github.response.GitCommit)
} yield x
commit: scala.concurrent.Future[repatch.github.response.GitCommit] = scala.concurrent.impl.Promise$DefaultPromise@39439e65

scala> commit()
res1: repatch.github.response.GitCommit =
GitCommit(28dbd9265dd9780124c1412f7f530684dab020ae,https://api.github.com/repos/dispatch/reboot/git/commits/28dbd9265dd9780124c1412f7f530684dab020ae,
```

## [trees](https://developer.github.com/v3/git/trees/)

> `GET /repos/:owner/:repo/git/trees/:sha`
```scala
scala> val trees = http(client(repo("dispatch", "reboot").git_trees("b1193d20d761654b7fc35a48cd64b53aedc7a697")) > as.repatch.github.response.GitTrees)
trees: dispatch.Future[Seq[repatch.github.response.GitTree]] = scala.concurrent.impl.Promise$DefaultPromise@73259adf

scala> trees()
res8: Seq[repatch.github.response.GitTree] = List(GitTree(3baebe52555bc73ad1c9a94261c4552fb8d771cd,https://api.github.com/repos/dispatch/reboot/git/blobs/3baebe52555bc73ad1c9a94261c4552fb8d771cd,.gitignore,100644,blob,Some(93)), ...
```

> Get a tree recursively
```scala
scala> val trees = http(client(repo("dispatch", "reboot").git_trees("b1193d20d761654b7fc35a48cd64b53aedc7a697").recursive(10)) > as.repatch.github.response.GitTrees)
trees: dispatch.Future[Seq[repatch.github.response.GitTree]] = scala.concurrent.impl.Promise$DefaultPromise@b6c8874

scala> trees()
res9: Seq[repatch.github.response.GitTree] = List(GitTree(3baebe52555bc73ad1c9a94261c4552fb8d771cd,https://api.github.com/repos/dispatch/reboot/git/blobs/3baebe52555bc73ad1c9a94261c4552fb8d771cd,.gitignore,100644,blob,Some(93)), ...
```

here's how to get a tree from a git commit.

```scala
scala> val trees = for {
master <- http(client(repo("dispatch", "reboot").git_refs.heads("master")) > as.repatch.github.response.GitRef)
commit <- http(client(repo("dispatch", "reboot").git_commit(master)) > as.repatch.github.response.GitCommit)
x <- http(client(repo("dispatch", "reboot").git_trees(commit)) > as.repatch.github.response.GitTrees)
} yield x
trees: scala.concurrent.Future[Seq[repatch.github.response.GitTree]] = scala.concurrent.impl.Promise$DefaultPromise@3d333b3e

scala> trees()
res10: Seq[repatch.github.response.GitTree] = List(GitTree(3baebe52555bc73ad1c9a94261c4552fb8d771cd,https://api.github.com/repos/dispatch/reboot/git/blobs/3baebe52555bc73ad1c9a94261c4552fb8d771cd,.gitignore,100644,blob,Some(93)), ...
```

## [blobs](https://developer.github.com/v3/git/blobs/)

> `GET /repos/:owner/:repo/git/blobs/:sha`
```scala
scala> val blob = http(client(repo("dispatch", "reboot").git_blob(blob_sha)) > as.repatch.github.response.GitBlob)
blob: dispatch.Future[repatch.github.response.GitBlob] = scala.concurrent.impl.Promise$DefaultPromise@3943a8f9

scala> blob()
res11: repatch.github.response.GitBlob =
GitBlob(3baebe52555bc73ad1c9a94261c4552fb8d771cd,https://api.github.com/repos/dispatch/reboot/git/blobs/3baebe52555bc73ad1c9a94261c4552fb8d771cd,base64,LmNsYXNzcGF0aAoucHJvamVjdAouc2V0dGluZ3MKdGFyZ2V0CnNjcmF0Y2gu
c2NhbGEKc3JjX21hbmFnZWQKKi50ZXN0LnByb3BlcnRpZXMKLmlkZWEKKi5p
bWwK
,93)

scala> res11.as_utf8
res12: String =
".classpath
.project
.settings
target
scratch.scala
src_managed
*.test.properties
.idea
*.iml
"
```

git the blob as raw.

```scala
scala> http(client(repo("dispatch", "reboot").git_blob(blob_sha).raw) > as.String)
res13: dispatch.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@522c7ab9

scala> res5()
res6: String =
scala> res13()
res14: String =
".classpath
.project
.settings
target
scratch.scala
lib_managed
project/boot
project/plugins/project
src_managed
*.test.properties
.idea
*.iml
"
```
45 changes: 13 additions & 32 deletions core/src/main/scala/as/package.scala
@@ -1,33 +1,14 @@
package repatch.as_github

import dispatch._
import repatch.github
import net.liftweb.json.{JsonParser, JValue}

object Json extends (Res => JValue) {
def apply(r: Res) = (dispatch.as.String andThen JsonParser.parse)(r)
}

object Repo extends (Res => github.Repo) {
def apply(r: Res) = (Json andThen github.Repo.fromJson)(r)
}

object GitRef extends (Res => github.GitRef) {
def apply(r: Res) = (Json andThen github.GitRef.fromJson)(r)
}

object GitRefs extends (Res => Seq[github.GitRef]) {
def apply(r: Res) = (Json andThen github.GitRefs.fromJson)(r)
}

object GitCommit extends (Res => github.GitCommit) {
def apply(r: Res) = (Json andThen github.GitCommit.fromJson)(r)
}

object GitTrees extends (Res => Seq[github.GitTree]) {
def apply(r: Res) = (Json andThen github.GitTrees.fromJson)(r)
}

object GitBlob extends (Res => github.GitBlob) {
def apply(r: Res) = (Json andThen github.GitBlob.fromJson)(r)
package dispatch.as.repatch.github

package object response {
import com.ning.http.client.Response
import repatch.github.{response => res}
import dispatch.as.json4s.Json

val Repo: Response => res.Repo = Json andThen res.Repo.apply
val GitRefs: Response => Seq[res.GitRef] = Json andThen res.GitRefs.apply
val GitRef: Response => res.GitRef = Json andThen res.GitRef.apply
val GitCommit: Response => res.GitCommit = Json andThen res.GitCommit.apply
val GitTrees: Response => Seq[res.GitTree] = Json andThen res.GitTrees.apply
val GitBlob: Response => res.GitBlob = Json andThen res.GitBlob.apply
}

0 comments on commit 531b5a4

Please sign in to comment.