Try it out in your browser! (REPL)
Octokat.js provides a minimal higher-level wrapper around GitHub's API. It is being developed in the context of an EPUB3 Textbook editor for GitHub and a simple serverless kanban board (demo).
This package can be used in nodejs
or in the browser as an AMD module or using browserify.
Octokat runs in node or a browser and is available in npm.
npm install --save octokat
- Works in
nodejs
, an AMD module in the browser, and as a bower library - Handles text and binary files
- Exposes everything available via the GitHub API (repos, teams, events, hooks, emojis, etc.)
- Supports
ETag
caching - Paged results
- Node-style callbacks as well as optional Promises (to avoid those debates)
- 100% of the GitHub API
- Starring and Following repositories, users, and organizations
- Editing Team and Organization Membership
- User/Org/Repo events and notifications
- Listeners for rate limit changes
- Public Keys
- Hooks (commit, comment, etc.)
- Uses native Promises if available
- Markdown generation
- Preview APIs (Deployments, Teams, Licenses, etc)
- Enterprise APIs
For the full list of supported methods see ./src/grammar/, ./examples/, Travis tests, or the ./test directory.
This library closely mirrors the https://developer.github.com/v3 documentation.
For example:
// `GET /repos/:owner/:repo` in the docs becomes:
octo.repos(owner, repo).fetch()
// `POST /repos/:owner/:repo/issues/:number/comments` becomes:
octo.repos(owner, repo).issues(number).comments.create(params)
The last method should be a verb method. The verb method makes the async call and should either have a callback as the last argument or it returns a Promise (see Promises or Callbacks).
The basic structure of the verb method is:
.foos.fetch({optionalStuff:...})
yields a list of items (possibly paginated).foos(id).fetch(...)
yields a single item (issue, repo, user).foos.create(...)
creates a newfoo
.foos(id).update(...)
updates an existingfoo
.foos(id).add()
adds an existing User/Repo (id
) to the list.foos(id).remove()
removes a member from a list or deletes the object and yields a boolean indicating success.foos.contains(id)
tests membership in a list (yields true/false).foos(id).read()
is similar to.fetch()
but yields the text contents without the wrapper JSON.foos(id).readBinary()
is similar to.read()
but yields binary data
Below are some examples for using the library. For a semi-autogenerated list of more examples see ./examples/.
You construct the URL by chaining properties and methods together and an async call is made once a verb method is called (see below).
octo = new Octokat()
repo = octo.repos('philschatz', 'octokat.js')
// Check if the current user is a collaborator on a repo
repo.collaborators.contains(USER)
.then((isCollaborator) => {
// If not, then star the Repo
if (!isCollaborator) {
repo.star.add()
.then(() => {
// Done!
})
}
})
Or, update a specific comment:
octo = new Octokat({token: ...})
octo.repos('philschatz', 'octokat.js').issues(1).comments(123123).update({body: 'Hello'})
.then(() => {
// Done!
})
This library supports Node.js-style callbacks as well as Promises.
To use a callback, just specify it as the last argument to a method. To use a Promise, do not specify a callback and the return value will be a Promise.
Example (get information on a repo):
// Using callbacks
octo.repos('philschatz', 'octokat.js').fetch((err, repo) => {
if (err) console.error(err)
// Do fancy stuff...
})
// Using Promises
octo.repos('philschatz', 'octokat.js').fetch()
.then((repo) => {
// Do fancy stuff
}).then(null, (err) => console.error(err))
To read the contents of a file:
var octo = new Octokat()
var repo = octo.repos('philschatz', 'octokat.js')
repo.contents('README.md').read() // Use `.read` to get the raw file.
.then((contents) => { // `.fetch` is used for getting JSON
console.log(contents)
});
To read the contents of a binary file:
var octo = new Octokat()
var repo = octo.repos('philschatz', 'octokat.js')
repo.contents('README.md').readBinary() // Decodes the Base64-encoded content
.then((contents) => {
console.log(contents)
})
To read the contents of a file and JSON metadata:
var octo = new Octokat()
var repo = octo.repos('philschatz', 'octokat.js')
repo.contents('README.md').fetch()
.then((info) => {
console.log(info.sha, info.content)
})
To update a file you need the blob SHA of the previous commit:
var octo = new Octokat({token: 'API_TOKEN'})
var repo = octo.repos('philschatz', 'octokat.js')
var config = {
message: 'Updating file',
content: base64encode('New file contents'),
sha: '123456789abcdef', // the blob SHA
// branch: 'gh-pages'
}
repo.contents('README.md').add(config)
.then((info) => {
console.log('File Updated. new sha is ', info.commit.sha)
})
Creating a new file is the same as updating a file but the sha
field in the config is omitted.
To remove a file:
var octo = new Octokat({token: 'API_TOKEN'})
var repo = octo.repos('philschatz', 'octokat.js')
var config = {
message: 'Removing file',
sha: '123456789abcdef',
// branch: 'gh-pages'
}
repo.contents('README.md').remove(config)
.then(() => {
console.log('File Updated')
});
All asynchronous methods accept a Node.js-style callback and return a Common-JS Promise.
Create an Octokat instance.
var octo = new Octokat({
username: "USER_NAME",
password: "PASSWORD"
})
var cb = function (err, val) { console.log(val) }
octo.zen.read(cb)
octo.repos('philschatz', 'octokat.js').fetch(cb) // Fetch repo info
octo.me.starred('philschatz', 'octokat.js').add(cb) // Star a repo
Or if you prefer OAuth:
var octo = new Octokat({
token: "OAUTH_TOKEN"
})
define(['octokat'], (Octokat) => {
var octo = new Octokat({
username: "YOU_USER",
password: "YOUR_PASSWORD"
})
})
Install instructions:
npm install octokat --save
var Octokat = require('octokat')
var octo = new Octokat({
username: "YOU_USER",
password: "YOUR_PASSWORD"
})
// You can omit `cb` and use Promises instead
var cb = function (err, val) { console.log(val) }
octo.zen.read(cb)
octo.repos('philschatz', 'octokat.js').fetch(cb) // Fetch repo info
octo.me.starred('philschatz', 'octokat.js').add(cb) // Star a repo
octo.me.starred('philschatz', 'octokat.js').remove(cb) // Un-Star a repo
This file can be included using the bower package manager:
bower install octokat --save
This is all you need to get up and running:
<script src="../dist/octokat.js"></script>
<script>
var octo = new Octokat()
octo.zen.read((err, message) => {
if (err) { throw new Error(err) }
alert(message)
})
</script>
GitHub provides URL patterns in its JSON responses. These are automatically converted into methods.
You can disable this by setting disableHypermedia: true
in the options when creating a new Octokat(...)
.
For example:
octo.repos('philschatz', 'octokat.js').fetch()
.then((repo) => {
// GitHub returns a JSON which contains something like compare_url: 'https://..../compare/{head}...{base}
// This is converted to a method that accepts 2 arguments
repo.compare(sha1, sha2).fetch()
.then((comparison) => console.log('Done!'))
})
If a .fetch()
returns paged results then nextPage()
, previousPage()
, firstPage()
and lastPage()
are added to the returned Object. For example:
octo.repos('philschatz', 'octokat.js').commits.fetch()
.then((someCommits) => {
someCommits.nextPage()
.then((moreCommits) => {
console.log('2nd page of results', moreCommits)
})
})
As standard with the Github API, passing a per_page
parameter allows you to control the number of results per page. For example:
octo.repos('philschatz', 'octokat.js').issues.fetch({per_page: 100})
.then(...)
Octokat will send the Preview Accept header by default for several Preview APIs.
If you want to change this behavior you can force an acceptHeader
when instantiating Octokat.
For example:
var octo = new Octokat({
token: 'API_TOKEN',
acceptHeader: 'application/vnd.github.cannonball-preview+json'
})
To use the Enterprise APIs add the root URL when instantiating Octokat:
var octo = new Octokat({
token: 'API_TOKEN',
rootURL: 'https://example.com/api/v3'
})
This requires Node.js 0.11 with the --harmony-generators
flag:
var Octokat = require('octokat')
var octo = new Octokat()
var zen = yield octo.zen.read()
var info = yield octo.repos('philschatz', 'octokat.js').fetch()
console.log(zen)
console.log(info)
Uploading release assets requires a slightly different syntax because it involves setting a custom contentType and providing a possibly binary payload.
To upload (tested using nodejs) you can do the following:
var contents = fs.readFileSync('./build.js')
repo.releases(123456).fetch()
.then((release) => {
release.upload('build.js', 'application/javascript', contents)
.then((resp) => {
// Success!
})
})
If you are using webhooks, the JSON returned by GitHub can be parsed using
octo.parse(json)
to yield a rich object with all the methods Octokat provides.
octo.parse(json)
is asynchronous and can take either a callback or returns a promise.
Instead of using Octokat to construct URLs, you can construct them yourself and still use Octokat for sending authentication information, caching, pagination, and parsing Hypermedia.
// Specify the entire URL
octo.fromUrl('https://api.github.com/repos/philschatz/octokat.js/issues/1').fetch(cb)
// Or, just the path
octo.fromUrl('/repos/philschatz/octokat.js/issues').fetch({state: 'open'}, cb)
If the URL is a Hypermedia Template then you can fill in the fields by passing them in as an additional argument.
params = {
owner: 'philschatz'
repo: 'octokat.js'
name: 'dist.js'
}
octo.fromUrl('https://uploads.github.com/repos/{owner}/{repo}/releases{/id}/assets{?name}', params)
// returns https://uploads.github.com/repos/philschatz/octokat.js/releases/assets?name=dist.js
- Run
npm install
- Run
npm test
to run Mocha tests for Node.js and the browser - Run
grunt dist
to generate the files in the./dist
directory
The unit tests are named to illustrate examples of using the API.
See Travis tests or run npm test
to see them.
fetch-vcr is used to generate recorded HTTP fixtures from GitHub. If you are adding tests be sure to include the updated fixtures in the Pull Request.
- Add Option for Two factor authentication
- Add option to pass header as cache control: no cache