├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── package.json ├── presentation ├── code-slides │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ ├── 2.png │ ├── 20.png │ ├── 21.png │ ├── 22.png │ ├── 23.png │ ├── 24.png │ ├── 25.png │ ├── 26.png │ ├── 27.png │ ├── 28.png │ ├── 29.png │ ├── 3.png │ ├── 30.png │ ├── 31.png │ ├── 32.png │ ├── 33.png │ ├── 34.png │ ├── 35.png │ ├── 36.png │ ├── 37.png │ ├── 38.png │ ├── 39.png │ ├── 4.png │ ├── 40.png │ ├── 41.png │ ├── 42.png │ ├── 43.png │ ├── 44.png │ ├── 45.png │ ├── 46.png │ ├── 47.png │ ├── 48.png │ ├── 49.png │ ├── 5.png │ ├── 50.png │ ├── 51.png │ ├── 52.png │ ├── 53.png │ ├── 54.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ ├── 9.png │ └── thing.rb ├── config.vim ├── deck.md ├── gifs │ ├── graphql-validation.gif │ ├── star-unstar-repo.gif │ ├── typescript.gif │ └── user-search.gif └── images │ ├── app-demo.png │ ├── dan-abramov-redux-fetch-tweet.png │ ├── graphiql.png │ ├── graphql-logo-solo.png │ ├── graphql-logo-svg.svg │ ├── graphql-logo.png │ ├── graphql-spec.png │ ├── pbj.jpg │ ├── query-related-types.png │ ├── react-native-graphql-github.jpg │ ├── sample-query-and-response.png │ ├── separation-of-concerns.jpg │ ├── thoughtbot.png │ └── type-system-static.gif ├── queries ├── 01-original.graphql ├── 02-inlined.graphql ├── 03-rest-api.txt ├── gql-result.json └── rest │ ├── orgs.json │ ├── repos-10.json │ ├── repos.json │ └── user.json ├── src ├── components │ ├── Avatar.js │ ├── Button.js │ ├── Circle.js │ ├── DefaultQuery.js │ ├── Flex.js │ ├── Grid.js │ ├── Headings.js │ ├── Icon.js │ ├── Language.js │ ├── LoadMoreButton.js │ ├── Org.js │ ├── Page.js │ ├── Repo.js │ ├── RepoHeader.js │ ├── RepoStats.js │ ├── Tile.js │ ├── TitleLink.js │ ├── ToggleStarButton.js │ ├── UnstyledLink.js │ ├── UserHeader.js │ ├── UserList.js │ └── UserTile.js ├── gqlSchema.json ├── hocs │ └── withLoading.js ├── index.html ├── index.js ├── pages │ ├── SearchPage.js │ ├── UserPage.js │ └── index.js └── styles │ ├── index.js │ └── spacing.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-app"], 3 | "plugins": ["transform-class-properties"] 4 | } 5 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/gqlTypes.js 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const gqlSchemJson = require('./src/gqlSchema.json'); 2 | 3 | module.exports = { 4 | env: { 5 | browser: true, 6 | es6: true, 7 | node: true, 8 | }, 9 | plugins: ['react', 'graphql', 'import', 'filenames'], 10 | settings: { 11 | react: { 12 | version: '16.0', 13 | }, 14 | }, 15 | parserOptions: { 16 | ecmaVersion: 6, 17 | sourceType: 'module', 18 | ecmaFeatures: { 19 | jsx: true, 20 | }, 21 | }, 22 | extends: [ 23 | 'eslint:recommended', 24 | 'plugin:react/recommended', 25 | 'airbnb', 26 | 'prettier', 27 | 'prettier/react', 28 | ], 29 | rules: { 30 | 'filenames/match-regex': ['error', '^[.a-zA-Z0-9]+$'], 31 | 'filenames/match-exported': 'error', 32 | 'graphql/template-strings': [ 33 | 'error', 34 | { 35 | env: 'apollo', 36 | schemaJson: gqlSchemJson, 37 | }, 38 | ], 39 | 'graphql/required-fields': [ 40 | 'error', 41 | { 42 | env: 'apollo', 43 | schemaJson: gqlSchemJson, 44 | requiredFields: ['id'], 45 | }, 46 | ], 47 | 'graphql/named-operations': [ 48 | 'error', 49 | { 50 | schemaJson: gqlSchemJson, 51 | }, 52 | ], 53 | 'graphql/capitalized-type-name': [ 54 | 'error', 55 | { 56 | schemaJson: gqlSchemJson, 57 | }, 58 | ], 59 | 'import/default': 'error', 60 | 'import/extensions': ['error', 'never', {svg: 'always'}], 61 | 'import/first': 'error', 62 | 'import/named': 'error', 63 | 'import/namespace': 'error', 64 | 'import/no-commonjs': 'error', 65 | 'import/no-dynamic-require': 'error', 66 | 'import/no-extraneous-dependencies': [ 67 | 'error', 68 | { 69 | devDependencies: [ 70 | '**/*.test.js', 71 | 'src/setupTests.js', 72 | 'gql/**/*.js', 73 | 'cypress/**/*.js', 74 | ], 75 | optionalDependencies: false, 76 | }, 77 | ], 78 | 'import/no-named-as-default-member': 'error', 79 | 'import/no-named-as-default': 'off', 80 | 'import/no-named-default': 'error', 81 | 'import/no-namespace': 'error', 82 | 'import/no-unresolved': 'error', 83 | 'import/no-webpack-loader-syntax': 'error', 84 | 'import/order': 'error', 85 | 'jsx-a11y/anchor-is-valid': [ 86 | 'error', 87 | { 88 | components: ['Link', 'NavLink'], 89 | specialLink: ['to'], 90 | }, 91 | ], 92 | 'no-console': 'warn', 93 | 'no-extra-bind': 'error', 94 | 'no-implicit-globals': 'error', 95 | 'no-use-before-define': 'off', 96 | 'no-underscore-dangle': 'off', 97 | 'prefer-promise-reject-errors': 'error', 98 | 'react/jsx-key': 'error', 99 | 'react/jsx-filename-extension': 'off', 100 | 'react/no-array-index-key': 'off', 101 | 'react/no-danger': 'off', 102 | 'react/no-direct-mutation-state': 'error', 103 | 'react/prop-types': 'off', 104 | }, 105 | parser: 'babel-eslint', 106 | root: true, 107 | }; 108 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | dist 3 | .env 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 72, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "bracketSpacing": false 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React + GraphQL Sample App 2 | 3 | You can view the recording from Boston React Conf 2018 where I presented the 4 | talk associated with this repo: 5 | 6 | [![boston react conf talk video](https://img.youtube.com/vi/Qsoj4s_Ml6s/0.jpg)](https://www.youtube.com/watch?v=Qsoj4s_Ml6s) 7 | 8 | This sample app demonstrates how to integrate React app with a GraphQL API. The 9 | app uses the [Apollo framework][] along with its stellar [React bindings][] to 10 | interact with the [GitHub GraphQL API][]. In addition, the focus was on the 11 | pattern of collocating queries with components, specifically highlighting the 12 | use of `fragment`s within sub-components to allow each component to own its 13 | data, while allowing the application to compose queries from the fragments and 14 | efficiently interact with the GraphQL API. 15 | 16 | [apollo framework]: https://www.apollographql.com/docs/react/ 17 | [react bindings]: https://github.com/apollographql/react-apollo 18 | [github graphql api]: https://developer.github.com/v4/ 19 | 20 | ## Typescript 21 | 22 | The [master][] branch contains the default JS based implementation of the 23 | application. In the [typescript 24 | branch](https://github.com/christoomey/boston-react-conf-2018-graphql-talk/tree/typescript) 25 | all components are converted to [TypeScript][], and via the magic of [Apollo 26 | CLI][], relevant types are generated for each component with data needs. 27 | 28 | [typescript]: https://www.typescriptlang.org/ 29 | [apollo cli]: https://github.com/apollographql/apollo-cli 30 | [master]: https://github.com/christoomey/boston-react-conf-2018-graphql-talk 31 | 32 | ## Setup 33 | 34 | ### Dependencies 35 | 36 | This project uses [yarn][] to manage dependencies. 37 | 38 | yarn install 39 | 40 | ### GitHub Token 41 | 42 | You'll need to to generate a [GitHub personal access token][] with `repo` and `read:org` 43 | scopes. Once generated, add it to a `.env` file: 44 | 45 | ```sh 46 | GITHUB_TOKEN=abcdef-secret-token 47 | ``` 48 | 49 | **Note** - The app will be connected to live data and your account based on the 50 | token you provide. The only action built into the app is to Star & Unstar 51 | repositories, but just be super clear, those actions will be reflected on 52 | github.com. 53 | 54 | [yarn]: https://yarnpkg.com/en/ 55 | [github personal access token]: https://github.com/settings/tokens/new 56 | 57 | ### Starting the App 58 | 59 | The app can be started with: 60 | 61 | ```sh 62 | yarn start 63 | ``` 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-user-search-sample", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "Chris Toomey ", 6 | "license": "MIT", 7 | "scripts": { 8 | "start": "export $(cat .env) && parcel src/index.html", 9 | "lint": "eslint src", 10 | "gql:schema": "apollo-codegen introspect-schema https://api.github.com/graphql --output src/gqlSchema.json --header \"Authorization: Bearer $(cat .env | grep GITHUB_TOKEN | cut -d '=' -f 2)\"", 11 | "gql:types": "apollo-codegen generate src/**/*.js --schema src/gqlSchema.json --target typescript --output src/gqlTypes.ts", 12 | "gql:full": "yarn run gql:schema && yarn run gql:types" 13 | }, 14 | "devDependencies": { 15 | "apollo-codegen": "^0.19.1", 16 | "babel-eslint": "^8.2.2", 17 | "babel-plugin-transform-class-properties": "^6.24.1", 18 | "babel-preset-react-app": "^3.1.1", 19 | "babel-runtime": "^6.26.0", 20 | "eslint": "^4.18.2", 21 | "eslint-config-airbnb": "^16.1.0", 22 | "eslint-config-prettier": "^2.9.0", 23 | "eslint-plugin-filenames": "^1.2.0", 24 | "eslint-plugin-graphql": "^1.5.0", 25 | "eslint-plugin-import": "^2.9.0", 26 | "eslint-plugin-jsx-a11y": "^6.0.3", 27 | "eslint-plugin-react": "^7.7.0", 28 | "eslint_d": "^5.2.2", 29 | "parcel-bundler": "^1.6.2", 30 | "prettier": "^1.11.1" 31 | }, 32 | "dependencies": { 33 | "apollo-boost": "^0.1.4", 34 | "apollo-client": "^2.2.7", 35 | "graphql": "^0.13.1", 36 | "graphql-tag": "^2.8.0", 37 | "query-string": "^6.1.0", 38 | "react": "^16.2.0", 39 | "react-apollo": "^2.1.0", 40 | "react-dom": "^16.2.0", 41 | "react-octicons": "^0.2.0", 42 | "react-router-dom": "^4.2.2", 43 | "styled-components": "^3.2.5" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /presentation/code-slides/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/1.png -------------------------------------------------------------------------------- /presentation/code-slides/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/10.png -------------------------------------------------------------------------------- /presentation/code-slides/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/11.png -------------------------------------------------------------------------------- /presentation/code-slides/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/12.png -------------------------------------------------------------------------------- /presentation/code-slides/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/13.png -------------------------------------------------------------------------------- /presentation/code-slides/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/14.png -------------------------------------------------------------------------------- /presentation/code-slides/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/15.png -------------------------------------------------------------------------------- /presentation/code-slides/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/16.png -------------------------------------------------------------------------------- /presentation/code-slides/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/17.png -------------------------------------------------------------------------------- /presentation/code-slides/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/18.png -------------------------------------------------------------------------------- /presentation/code-slides/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/19.png -------------------------------------------------------------------------------- /presentation/code-slides/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/2.png -------------------------------------------------------------------------------- /presentation/code-slides/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/20.png -------------------------------------------------------------------------------- /presentation/code-slides/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/21.png -------------------------------------------------------------------------------- /presentation/code-slides/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/22.png -------------------------------------------------------------------------------- /presentation/code-slides/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/23.png -------------------------------------------------------------------------------- /presentation/code-slides/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/24.png -------------------------------------------------------------------------------- /presentation/code-slides/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/25.png -------------------------------------------------------------------------------- /presentation/code-slides/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/26.png -------------------------------------------------------------------------------- /presentation/code-slides/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/27.png -------------------------------------------------------------------------------- /presentation/code-slides/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/28.png -------------------------------------------------------------------------------- /presentation/code-slides/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/29.png -------------------------------------------------------------------------------- /presentation/code-slides/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/3.png -------------------------------------------------------------------------------- /presentation/code-slides/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/30.png -------------------------------------------------------------------------------- /presentation/code-slides/31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/31.png -------------------------------------------------------------------------------- /presentation/code-slides/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/32.png -------------------------------------------------------------------------------- /presentation/code-slides/33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/33.png -------------------------------------------------------------------------------- /presentation/code-slides/34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/34.png -------------------------------------------------------------------------------- /presentation/code-slides/35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/35.png -------------------------------------------------------------------------------- /presentation/code-slides/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/36.png -------------------------------------------------------------------------------- /presentation/code-slides/37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/37.png -------------------------------------------------------------------------------- /presentation/code-slides/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/38.png -------------------------------------------------------------------------------- /presentation/code-slides/39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/39.png -------------------------------------------------------------------------------- /presentation/code-slides/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/4.png -------------------------------------------------------------------------------- /presentation/code-slides/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/40.png -------------------------------------------------------------------------------- /presentation/code-slides/41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/41.png -------------------------------------------------------------------------------- /presentation/code-slides/42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/42.png -------------------------------------------------------------------------------- /presentation/code-slides/43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/43.png -------------------------------------------------------------------------------- /presentation/code-slides/44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/44.png -------------------------------------------------------------------------------- /presentation/code-slides/45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/45.png -------------------------------------------------------------------------------- /presentation/code-slides/46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/46.png -------------------------------------------------------------------------------- /presentation/code-slides/47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/47.png -------------------------------------------------------------------------------- /presentation/code-slides/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/48.png -------------------------------------------------------------------------------- /presentation/code-slides/49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/49.png -------------------------------------------------------------------------------- /presentation/code-slides/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/5.png -------------------------------------------------------------------------------- /presentation/code-slides/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/50.png -------------------------------------------------------------------------------- /presentation/code-slides/51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/51.png -------------------------------------------------------------------------------- /presentation/code-slides/52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/52.png -------------------------------------------------------------------------------- /presentation/code-slides/53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/53.png -------------------------------------------------------------------------------- /presentation/code-slides/54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/54.png -------------------------------------------------------------------------------- /presentation/code-slides/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/6.png -------------------------------------------------------------------------------- /presentation/code-slides/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/7.png -------------------------------------------------------------------------------- /presentation/code-slides/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/8.png -------------------------------------------------------------------------------- /presentation/code-slides/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/code-slides/9.png -------------------------------------------------------------------------------- /presentation/code-slides/thing.rb: -------------------------------------------------------------------------------- 1 | Dir.glob("*.png").each_with_index do |file, index| 2 | system("mv '#{file}' #{index + 1}.png") 3 | end 4 | 5 | Dir. 6 | glob("*.png"). 7 | select { |f| f.length == 5 }. 8 | each do |file| 9 | system("mv '#{file}' '0#{file}") 10 | end 11 | -------------------------------------------------------------------------------- /presentation/config.vim: -------------------------------------------------------------------------------- 1 | call VipRegister( 2 | \ { 3 | \ 'file_list': [ 4 | \ 'edit src/index.js', 5 | \ 'edit src/components/UserList.js', 6 | \ 'vsplit src/components/UserTile.js', 7 | \ 'Only src/pages/UserPage.js', 8 | \ 'vsplit src/components/UserHeader.js', 9 | \ 'Only src/pages/UserPage.js | vsplit src/components/Org.js', 10 | \ 'Only src/pages/UserPage.js | vsplit src/components/Repo.js', 11 | \ 'vsplit src/components/RepoStats.js', 12 | \ 'vsplit src/components/Language.js', 13 | \ 'Only src/components/RepoHeader.js', 14 | \ 'vsplit src/components/ToggleStarButton.js', 15 | \ 'Only queries/01-original.graphql', 16 | \ 'Only queries/02-inlined.graphql', 17 | \ 'vsplit queries/03-rest-api.txt', 18 | \ 'Only queries/02-inlined.graphql | vsplit queries/rest/repos-10.json', 19 | \ ], 20 | \ 'highlights': { 21 | \ 'src/index.js': [ 22 | \ { 'ranges': [[8, 17]], 'cursorLine': 8 }, 23 | \ { 'ranges': [[19, 29]], 'cursorLine': 19 }, 24 | \ { 'ranges': [[20, 20], [28, 28]], 'cursorLine': 20 }, 25 | \ ], 26 | \ 'src/components/UserList.js': [ 27 | \ { 'ranges': [[8, 24]], 'cursorLine': 8 }, 28 | \ { 'ranges': [[26, 42]], 'cursorLine': 26 }, 29 | \ { 'ranges': [[8, 24]], 'cursorLine': 9 }, 30 | \ { 'ranges': [[9, 9], [23, 23]], 'cursorLine': 9 }, 31 | \ { 'ranges': [[9, 10], [22, 23]], 'cursorLine': 10 }, 32 | \ { 'ranges': [[11, 21]], 'cursorLine': 11 }, 33 | \ { 'ranges': [[1, 99]], 'cursorLine': 10 }, 34 | \ { 'ranges': [[14, 14]], 'cursorLine': 14 }, 35 | \ ], 36 | \ 'src/components/UserTile.js': [ 37 | \ { 'ranges': [[28, 33]], 'cursorLine': 28 }, 38 | \ { 'ranges': [[27, 34]], 'cursorLine': 27 }, 39 | \ ], 40 | \ 'src/pages/UserPage.js': [ 41 | \ { 'ranges': [[31, 57]], 'cursorLine': 31 }, 42 | \ { 'ranges': [[34, 34], [38, 38], [48, 48], [54, 56]], 'cursorLine': 31 }, 43 | \ ], 44 | \ 'src/components/UserHeader.js': [ 45 | \ { 'ranges': [[19, 25]], 'cursorLine': 19 }, 46 | \ ], 47 | \ 'src/components/Org.js': [ 48 | \ { 'ranges': [[10, 14]], 'cursorLine': 10 }, 49 | \ ], 50 | \ 'src/components/Repo.js': [ 51 | \ { 'ranges': [[17, 26]], 'cursorLine': 17 }, 52 | \ { 'ranges': [[20, 21]], 'cursorLine': 20 }, 53 | \ { 'ranges': [[21, 21]], 'cursorLine': 21 }, 54 | \ ], 55 | \ 'src/components/RepoStats.js': [ 56 | \ { 'ranges': [[22, 33]], 'cursorLine': 22 }, 57 | \ { 'ranges': [[29, 29]], 'cursorLine': 29 }, 58 | \ ], 59 | \ 'src/components/Language.js': [ 60 | \ { 'ranges': [[13, 17]], 'cursorLine': 13 }, 61 | \ ], 62 | \ 'src/components/RepoHeader.js': [ 63 | \ { 'ranges': [[11, 11]], 'cursorLine': 11 }, 64 | \ { 'ranges': [[18, 25]], 'cursorLine': 18 }, 65 | \ { 'ranges': [[23, 23]], 'cursorLine': 23 }, 66 | \ ], 67 | \ 'src/components/ToggleStarButton.js': [ 68 | \ { 'ranges': [[6, 19]], 'cursorLine': 6 }, 69 | \ { 'ranges': [[21, 29]], 'cursorLine': 21 }, 70 | \ { 'ranges': [[22, 22], [28, 28]], 'cursorLine': 22 }, 71 | \ { 'ranges': [[22, 23], [27, 28]], 'cursorLine': 23 }, 72 | \ { 'ranges': [[24, 26]], 'cursorLine': 24 }, 73 | \ { 'ranges': [[31, 39]], 'cursorLine': 31 }, 74 | \ { 'ranges': [[41, 61]], 'cursorLine': 41 }, 75 | \ ], 76 | \ 'queries/rest/repos-10.json': [ 77 | \ { 'ranges': [[7, 26]], 'cursorLine': 7 }, 78 | \ { 'ranges': [[106, 125]], 'cursorLine': 106 }, 79 | \ { 'ranges': [[199, 218]], 'cursorLine': 199 }, 80 | \ { 'ranges': [[292, 311]], 'cursorLine': 292 }, 81 | \ { 'ranges': [[385, 404]], 'cursorLine': 385 }, 82 | \ { 'ranges': [[484, 503]], 'cursorLine': 484 }, 83 | \ ], 84 | \ }, 85 | \ }) 86 | 87 | nnoremap :VipOff 88 | nnoremap :VipNextHighlight 89 | nnoremap :VipNextHighlight 90 | nnoremap :VipPreviousHighlight 91 | nnoremap :VipOpenNextFile 92 | 93 | nnoremap :VipNextHighlight 94 | nnoremap :VipOpenNextFile 95 | 96 | VipEnableDimOnLeave 97 | -------------------------------------------------------------------------------- /presentation/deck.md: -------------------------------------------------------------------------------- 1 | # [fit] GraphQL & React 2 | 3 | ![](images/pbj.jpg) 4 | 5 | --- 6 | 7 | # Chris Toomey 8 | 9 | ![inline](images/thoughtbot.png) 10 | 11 | ## @christoomey 12 | 13 | ## @_bikeshed 14 | 15 | --- 16 | 17 | [.build-lists: true] 18 | 19 | ![inline](images/graphql-logo.png) 20 | 21 | # A Query Language for your API 22 | 23 | ^ 24 | * Similar to REST & SQL 25 | * Throws out all the normal REST stuff (status codes, verbs, etc) 26 | * JSON w/ a custom query language 27 | 28 | --- 29 | 30 | # You Get What You Ask For 31 | 32 | ![inline](images/sample-query-and-response.png) 33 | 34 | ^ 35 | * Avoid over / under-fetching 36 | * Client-centric 37 | * Ability to make changes to the server (monitor exactly what fields are used) 38 | 39 | --- 40 | 41 | # Get Related Resources in a Single Query 42 | 43 | ![inline](images/query-related-types.png) 44 | 45 | --- 46 | 47 | # Schema & Type System 48 | 49 | ![inline](images/type-system-static.gif) 50 | 51 | --- 52 | 53 | # [fit] [GraphiQL Demo](https://developer.github.com/v4/explorer/) 54 | 55 | ![](images/graphiql.png) 56 | 57 | [rest api for user]: https://api.github.com/users/christoomey 58 | 59 | --- 60 | 61 | # [fit] How Does GraphQL Fit with React? 62 | 63 | ![inline](images/separation-of-concerns.jpg) 64 | 65 | ^ 66 | comes from a 2017 talk by Cristiano Rastelli called Let There Be Peace On CSS 67 | https://speakerdeck.com/didoo/let-there-be-peace-on-css 68 | 69 | --- 70 | 71 | ![](images/app-demo.png) 72 | 73 | # [fit] [Sample App Demo](http://localhost:1234/users/) 74 | 75 | --- 76 | 77 | ![fit](images/react-native-graphql-github.jpg) 78 | 79 | --- 80 | 81 | ![](./code-slides/1.png) 82 | 83 | --- 84 | 85 | ![](./code-slides/2.png) 86 | 87 | --- 88 | 89 | ![](./code-slides/3.png) 90 | 91 | --- 92 | 93 | ![](./code-slides/4.png) 94 | 95 | --- 96 | 97 | ![](./code-slides/5.png) 98 | 99 | --- 100 | 101 | ![](./code-slides/6.png) 102 | 103 | --- 104 | 105 | ![](./code-slides/7.png) 106 | 107 | --- 108 | 109 | ![](./code-slides/8.png) 110 | 111 | --- 112 | 113 | ![](./code-slides/9.png) 114 | 115 | --- 116 | 117 | ![](./code-slides/10.png) 118 | 119 | --- 120 | 121 | ![](./code-slides/11.png) 122 | 123 | --- 124 | 125 | ![](./code-slides/12.png) 126 | 127 | --- 128 | 129 | ![](./code-slides/13.png) 130 | 131 | --- 132 | 133 | ![](./code-slides/14.png) 134 | 135 | --- 136 | 137 | ![](./code-slides/15.png) 138 | 139 | --- 140 | 141 | ![](./code-slides/16.png) 142 | 143 | --- 144 | 145 | ![](./code-slides/17.png) 146 | 147 | --- 148 | 149 | ![](./code-slides/18.png) 150 | 151 | --- 152 | 153 | ![](./code-slides/19.png) 154 | 155 | --- 156 | 157 | ![](./code-slides/20.png) 158 | 159 | --- 160 | 161 | ![](./code-slides/21.png) 162 | 163 | --- 164 | 165 | ![](./code-slides/22.png) 166 | 167 | --- 168 | 169 | ![](./code-slides/23.png) 170 | 171 | --- 172 | 173 | ![](./code-slides/24.png) 174 | 175 | --- 176 | 177 | ![](./code-slides/25.png) 178 | 179 | --- 180 | 181 | ![](./code-slides/26.png) 182 | 183 | --- 184 | 185 | ![](./code-slides/27.png) 186 | 187 | --- 188 | 189 | ![](./code-slides/28.png) 190 | 191 | --- 192 | 193 | ![](./code-slides/29.png) 194 | 195 | --- 196 | 197 | ![](./code-slides/30.png) 198 | 199 | --- 200 | 201 | ![](./code-slides/31.png) 202 | 203 | --- 204 | 205 | ![](./code-slides/32.png) 206 | 207 | --- 208 | 209 | ![](./code-slides/33.png) 210 | 211 | --- 212 | 213 | ![](./code-slides/34.png) 214 | 215 | --- 216 | 217 | ![](./code-slides/35.png) 218 | 219 | --- 220 | 221 | ![](./code-slides/36.png) 222 | 223 | --- 224 | 225 | ![](./code-slides/37.png) 226 | 227 | --- 228 | 229 | ![](./code-slides/38.png) 230 | 231 | --- 232 | 233 | ![](./code-slides/39.png) 234 | 235 | --- 236 | 237 | ![](./code-slides/40.png) 238 | 239 | --- 240 | 241 | ![](./code-slides/41.png) 242 | 243 | --- 244 | 245 | ![](./code-slides/42.png) 246 | 247 | --- 248 | 249 | ![](./code-slides/43.png) 250 | 251 | --- 252 | 253 | ![](./code-slides/44.png) 254 | 255 | --- 256 | 257 | ![](./code-slides/45.png) 258 | 259 | --- 260 | 261 | ![](./code-slides/46.png) 262 | 263 | --- 264 | 265 | ![](./code-slides/47.png) 266 | 267 | --- 268 | 269 | ![](./code-slides/48.png) 270 | 271 | --- 272 | 273 | ![](./code-slides/49.png) 274 | 275 | --- 276 | 277 | ![](./gifs/typescript.gif) 278 | 279 | --- 280 | 281 | ![fit](./code-slides/50.png) 282 | 283 | --- 284 | 285 | ![fit](./code-slides/51.png) 286 | 287 | --- 288 | 289 | ![fit](./code-slides/52.png) 290 | 291 | --- 292 | 293 | ![fit](./code-slides/53.png) 294 | 295 | --- 296 | 297 | ![fit](./code-slides/54.png) 298 | 299 | --- 300 | 301 | --- 302 | 303 | # [fit] What, Exactly, _is_ GraphQL? 304 | 305 | * [A Specification][] 306 | * Type System 307 | * Query Syntax 308 | * Execution sequence and algorithms (parsing, validation, resolution) 309 | * A reference implementation (GraphQL.js) 310 | 311 | ![right fit](images/graphql-spec.png) 312 | 313 | [a specification]: http://facebook.github.io/graphql/October2016/ 314 | 315 | --- 316 | 317 | Show where it fits in the stack (single route controller instead of typical 318 | many w/ REST API) 319 | 320 | Show where it fits in the client <-> server (small amoutn in client, bigger in 321 | server to parse, validate, resolve queries) 322 | 323 | --- 324 | 325 | # [fit] What about Redux? 326 | 327 | ![inline](images/dan-abramov-redux-fetch-tweet.png) 328 | -------------------------------------------------------------------------------- /presentation/gifs/graphql-validation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/gifs/graphql-validation.gif -------------------------------------------------------------------------------- /presentation/gifs/star-unstar-repo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/gifs/star-unstar-repo.gif -------------------------------------------------------------------------------- /presentation/gifs/typescript.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/gifs/typescript.gif -------------------------------------------------------------------------------- /presentation/gifs/user-search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/gifs/user-search.gif -------------------------------------------------------------------------------- /presentation/images/app-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/app-demo.png -------------------------------------------------------------------------------- /presentation/images/dan-abramov-redux-fetch-tweet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/dan-abramov-redux-fetch-tweet.png -------------------------------------------------------------------------------- /presentation/images/graphiql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/graphiql.png -------------------------------------------------------------------------------- /presentation/images/graphql-logo-solo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/graphql-logo-solo.png -------------------------------------------------------------------------------- /presentation/images/graphql-logo-svg.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /presentation/images/graphql-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/graphql-logo.png -------------------------------------------------------------------------------- /presentation/images/graphql-spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/graphql-spec.png -------------------------------------------------------------------------------- /presentation/images/pbj.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/pbj.jpg -------------------------------------------------------------------------------- /presentation/images/query-related-types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/query-related-types.png -------------------------------------------------------------------------------- /presentation/images/react-native-graphql-github.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/react-native-graphql-github.jpg -------------------------------------------------------------------------------- /presentation/images/sample-query-and-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/sample-query-and-response.png -------------------------------------------------------------------------------- /presentation/images/separation-of-concerns.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/separation-of-concerns.jpg -------------------------------------------------------------------------------- /presentation/images/thoughtbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/thoughtbot.png -------------------------------------------------------------------------------- /presentation/images/type-system-static.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christoomey/boston-react-conf-2018-graphql-talk/a79da20bb4a4b5e2749d3bf1e54bde22506e3a23/presentation/images/type-system-static.gif -------------------------------------------------------------------------------- /queries/01-original.graphql: -------------------------------------------------------------------------------- 1 | query UserQuery($login: String!) { 2 | user(login: $login) { 3 | ...UserHeader 4 | repositories( 5 | first: 10 6 | isFork: false 7 | orderBy: {field: STARGAZERS, direction: DESC} 8 | ) { 9 | nodes { 10 | ...Repo 11 | } 12 | } 13 | organizations(first: 10) { 14 | nodes { 15 | ...Org 16 | } 17 | } 18 | } 19 | } 20 | 21 | fragment UserHeader on User { 22 | id 23 | name 24 | bio 25 | login 26 | avatarUrl 27 | } 28 | 29 | fragment Repo on Repository { 30 | id 31 | ...RepoHeader 32 | ...RepoStats 33 | } 34 | 35 | fragment RepoStats on Repository { 36 | id 37 | forkCount 38 | stargazers { 39 | totalCount 40 | } 41 | primaryLanguage { 42 | ...Language 43 | } 44 | } 45 | 46 | fragment Language on Language { 47 | id 48 | name 49 | color 50 | } 51 | 52 | fragment RepoHeader on Repository { 53 | id 54 | url 55 | name 56 | description 57 | ...ToggleStarButton 58 | } 59 | 60 | fragment ToggleStarButton on Repository { 61 | id 62 | viewerHasStarred 63 | stargazers { 64 | totalCount 65 | } 66 | } 67 | 68 | fragment Org on Organization { 69 | id 70 | name 71 | avatarUrl 72 | } 73 | -------------------------------------------------------------------------------- /queries/02-inlined.graphql: -------------------------------------------------------------------------------- 1 | query UserQuery($login: String!) { 2 | user(login: $login) { 3 | id 4 | name 5 | bio 6 | login 7 | avatarUrl 8 | repositories( 9 | first: 10 10 | isFork: false 11 | orderBy: {field: STARGAZERS, direction: DESC} 12 | ) { 13 | nodes { 14 | id 15 | url 16 | name 17 | description 18 | viewerHasStarred 19 | forkCount 20 | stargazers { 21 | totalCount 22 | } 23 | primaryLanguage { 24 | id 25 | name 26 | color 27 | } 28 | } 29 | } 30 | organizations(first: 10) { 31 | nodes { 32 | id 33 | name 34 | avatarUrl 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /queries/03-rest-api.txt: -------------------------------------------------------------------------------- 1 | https://api.github.com/users/christoomey 2 | https://api.github.com/users/christoomey/orgs 3 | https://api.github.com/users/christoomey/repos 4 | -------------------------------------------------------------------------------- /queries/gql-result.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "user": { 4 | "repositories": { 5 | "nodes": [ 6 | { 7 | "__typename": "Repository", 8 | "id": "MDEwOlJlcG9zaXRvcnk5NDAwMjI5", 9 | "url": "https://github.com/christoomey/vim-tmux-navigator", 10 | "name": "vim-tmux-navigator", 11 | "description": 12 | "Seamless navigation between tmux panes and vim splits", 13 | "viewerHasStarred": true, 14 | "stargazers": { 15 | "totalCount": 2224, 16 | "__typename": "StargazerConnection" 17 | }, 18 | "forkCount": 133, 19 | "primaryLanguage": { 20 | "__typename": "Language", 21 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 22 | "name": "Vim script", 23 | "color": "#199f4b" 24 | } 25 | }, 26 | { 27 | "__typename": "Repository", 28 | "id": "MDEwOlJlcG9zaXRvcnkxMDMwNjM5", 29 | "url": "https://github.com/christoomey/dotfiles", 30 | "name": "dotfiles", 31 | "description": "My vim, bash, git, and other config files", 32 | "viewerHasStarred": false, 33 | "stargazers": { 34 | "totalCount": 241, 35 | "__typename": "StargazerConnection" 36 | }, 37 | "forkCount": 14, 38 | "primaryLanguage": { 39 | "__typename": "Language", 40 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 41 | "name": "Vim script", 42 | "color": "#199f4b" 43 | } 44 | }, 45 | { 46 | "__typename": "Repository", 47 | "id": "MDEwOlJlcG9zaXRvcnk2ODM0ODE4", 48 | "url": "https://github.com/christoomey/vim-tmux-runner", 49 | "name": "vim-tmux-runner", 50 | "description": "Vim and tmux, sittin' in a tree...", 51 | "viewerHasStarred": false, 52 | "stargazers": { 53 | "totalCount": 154, 54 | "__typename": "StargazerConnection" 55 | }, 56 | "forkCount": 23, 57 | "primaryLanguage": { 58 | "__typename": "Language", 59 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 60 | "name": "Vim script", 61 | "color": "#199f4b" 62 | } 63 | }, 64 | { 65 | "__typename": "Repository", 66 | "id": "MDEwOlJlcG9zaXRvcnkyMDU3MTE1MA==", 67 | "url": "https://github.com/christoomey/vim-system-copy", 68 | "name": "vim-system-copy", 69 | "description": 70 | "Vim plugin for copying to the system clipboard with text-objects and motions", 71 | "viewerHasStarred": false, 72 | "stargazers": { 73 | "totalCount": 124, 74 | "__typename": "StargazerConnection" 75 | }, 76 | "forkCount": 8, 77 | "primaryLanguage": { 78 | "__typename": "Language", 79 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 80 | "name": "Vim script", 81 | "color": "#199f4b" 82 | } 83 | }, 84 | { 85 | "__typename": "Repository", 86 | "id": "MDEwOlJlcG9zaXRvcnkyMDI2ODUyOQ==", 87 | "url": "https://github.com/christoomey/vim-sort-motion", 88 | "name": "vim-sort-motion", 89 | "description": "Vim mapping for sorting a range of text", 90 | "viewerHasStarred": false, 91 | "stargazers": { 92 | "totalCount": 112, 93 | "__typename": "StargazerConnection" 94 | }, 95 | "forkCount": 6, 96 | "primaryLanguage": { 97 | "__typename": "Language", 98 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 99 | "name": "Vim script", 100 | "color": "#199f4b" 101 | } 102 | }, 103 | { 104 | "__typename": "Repository", 105 | "id": "MDEwOlJlcG9zaXRvcnkxNTgzNzMwOA==", 106 | "url": "https://github.com/christoomey/vim-conflicted", 107 | "name": "vim-conflicted", 108 | "description": "Easy git merge conflict resolution in Vim", 109 | "viewerHasStarred": false, 110 | "stargazers": { 111 | "totalCount": 86, 112 | "__typename": "StargazerConnection" 113 | }, 114 | "forkCount": 4, 115 | "primaryLanguage": { 116 | "__typename": "Language", 117 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 118 | "name": "Vim script", 119 | "color": "#199f4b" 120 | } 121 | }, 122 | { 123 | "__typename": "Repository", 124 | "id": "MDEwOlJlcG9zaXRvcnkyMzEyNjY1NA==", 125 | "url": "https://github.com/christoomey/your-first-vim-plugin", 126 | "name": "your-first-vim-plugin", 127 | "description": 128 | "Samples and notes for my Aug 2014 'Your First Vim Plugin' talk", 129 | "viewerHasStarred": false, 130 | "stargazers": { 131 | "totalCount": 57, 132 | "__typename": "StargazerConnection" 133 | }, 134 | "forkCount": 7, 135 | "primaryLanguage": { 136 | "__typename": "Language", 137 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 138 | "name": "Vim script", 139 | "color": "#199f4b" 140 | } 141 | }, 142 | { 143 | "__typename": "Repository", 144 | "id": "MDEwOlJlcG9zaXRvcnkxNDgwNTA5Mg==", 145 | "url": "https://github.com/christoomey/vim-titlecase", 146 | "name": "vim-titlecase", 147 | "description": 148 | "Teach Vim about titlecase, with support for motions and text objects", 149 | "viewerHasStarred": false, 150 | "stargazers": { 151 | "totalCount": 40, 152 | "__typename": "StargazerConnection" 153 | }, 154 | "forkCount": 8, 155 | "primaryLanguage": { 156 | "__typename": "Language", 157 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 158 | "name": "Vim script", 159 | "color": "#199f4b" 160 | } 161 | }, 162 | { 163 | "__typename": "Repository", 164 | "id": "MDEwOlJlcG9zaXRvcnkxNzk4NDY5NQ==", 165 | "url": "https://github.com/gabebw/vim-spec-runner", 166 | "name": "vim-spec-runner", 167 | "description": 168 | ":runner: An efficient and intelligent spec runner for RSpec and JS unit tests", 169 | "viewerHasStarred": false, 170 | "stargazers": { 171 | "totalCount": 37, 172 | "__typename": "StargazerConnection" 173 | }, 174 | "forkCount": 10, 175 | "primaryLanguage": { 176 | "__typename": "Language", 177 | "id": "MDg6TGFuZ3VhZ2UxNDE=", 178 | "name": "Ruby", 179 | "color": "#701516" 180 | } 181 | }, 182 | { 183 | "__typename": "Repository", 184 | "id": "MDEwOlJlcG9zaXRvcnkyMjgxMDY4MQ==", 185 | "url": "https://github.com/christoomey/vim-quicklink", 186 | "name": "vim-quicklink", 187 | "description": 188 | "A Vim plugin for quickly looking up a topic in google and inserting the relevant link", 189 | "viewerHasStarred": false, 190 | "stargazers": { 191 | "totalCount": 34, 192 | "__typename": "StargazerConnection" 193 | }, 194 | "forkCount": 4, 195 | "primaryLanguage": { 196 | "__typename": "Language", 197 | "id": "MDg6TGFuZ3VhZ2U1Njk=", 198 | "name": "Vim script", 199 | "color": "#199f4b" 200 | } 201 | } 202 | ], 203 | "__typename": "RepositoryConnection" 204 | }, 205 | "organizations": { 206 | "nodes": [ 207 | { 208 | "__typename": "Organization", 209 | "id": "MDEyOk9yZ2FuaXphdGlvbjYxODM=", 210 | "name": "thoughtbot, inc.", 211 | "avatarUrl": "https://avatars3.githubusercontent.com/u/6183?v=4" 212 | } 213 | ], 214 | "__typename": "OrganizationConnection" 215 | }, 216 | "__typename": "User", 217 | "id": "MDQ6VXNlcjQyMDExMw==", 218 | "name": "Chris Toomey", 219 | "bio": "Developer @thoughtbot focused on Ruby, JS, Scala, and Elm.", 220 | "login": "christoomey", 221 | "avatarUrl": "https://avatars2.githubusercontent.com/u/420113?v=4" 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /queries/rest/orgs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "login": "thoughtbot", 4 | "id": 6183, 5 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjYxODM=", 6 | "url": "https://api.github.com/orgs/thoughtbot", 7 | "repos_url": "https://api.github.com/orgs/thoughtbot/repos", 8 | "events_url": "https://api.github.com/orgs/thoughtbot/events", 9 | "hooks_url": "https://api.github.com/orgs/thoughtbot/hooks", 10 | "issues_url": "https://api.github.com/orgs/thoughtbot/issues", 11 | "members_url": "https://api.github.com/orgs/thoughtbot/members{/member}", 12 | "public_members_url": "https://api.github.com/orgs/thoughtbot/public_members{/member}", 13 | "avatar_url": "https://avatars3.githubusercontent.com/u/6183?v=4", 14 | "description": "" 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /queries/rest/repos-10.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 13506432, 4 | "node_id": "MDEwOlJlcG9zaXRvcnkxMzUwNjQzMg==", 5 | "name": "alfred-trello-boards", 6 | "full_name": "christoomey/alfred-trello-boards", 7 | "owner": { 8 | "login": "christoomey", 9 | "id": 420113, 10 | "node_id": "MDQ6VXNlcjQyMDExMw==", 11 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 12 | "gravatar_id": "", 13 | "url": "https://api.github.com/users/christoomey", 14 | "html_url": "https://github.com/christoomey", 15 | "followers_url": "https://api.github.com/users/christoomey/followers", 16 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 17 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 18 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 19 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 20 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 21 | "repos_url": "https://api.github.com/users/christoomey/repos", 22 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 23 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 24 | "type": "User", 25 | "site_admin": false 26 | }, 27 | "private": false, 28 | "html_url": "https://github.com/christoomey/alfred-trello-boards", 29 | "description": "Alfred workflow for quick navigation to Trello boards", 30 | "fork": false, 31 | "url": "https://api.github.com/repos/christoomey/alfred-trello-boards", 32 | "forks_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/forks", 33 | "keys_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/keys{/key_id}", 34 | "collaborators_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/collaborators{/collaborator}", 35 | "teams_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/teams", 36 | "hooks_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/hooks", 37 | "issue_events_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/issues/events{/number}", 38 | "events_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/events", 39 | "assignees_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/assignees{/user}", 40 | "branches_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/branches{/branch}", 41 | "tags_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/tags", 42 | "blobs_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/git/blobs{/sha}", 43 | "git_tags_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/git/tags{/sha}", 44 | "git_refs_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/git/refs{/sha}", 45 | "trees_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/git/trees{/sha}", 46 | "statuses_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/statuses/{sha}", 47 | "languages_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/languages", 48 | "stargazers_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/stargazers", 49 | "contributors_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/contributors", 50 | "subscribers_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/subscribers", 51 | "subscription_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/subscription", 52 | "commits_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/commits{/sha}", 53 | "git_commits_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/git/commits{/sha}", 54 | "comments_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/comments{/number}", 55 | "issue_comment_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/issues/comments{/number}", 56 | "contents_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/contents/{+path}", 57 | "compare_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/compare/{base}...{head}", 58 | "merges_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/merges", 59 | "archive_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/{archive_format}{/ref}", 60 | "downloads_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/downloads", 61 | "issues_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/issues{/number}", 62 | "pulls_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/pulls{/number}", 63 | "milestones_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/milestones{/number}", 64 | "notifications_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/notifications{?since,all,participating}", 65 | "labels_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/labels{/name}", 66 | "releases_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/releases{/id}", 67 | "deployments_url": "https://api.github.com/repos/christoomey/alfred-trello-boards/deployments", 68 | "created_at": "2013-10-11T18:29:11Z", 69 | "updated_at": "2015-06-28T15:57:31Z", 70 | "pushed_at": "2014-05-19T14:05:34Z", 71 | "git_url": "git://github.com/christoomey/alfred-trello-boards.git", 72 | "ssh_url": "git@github.com:christoomey/alfred-trello-boards.git", 73 | "clone_url": "https://github.com/christoomey/alfred-trello-boards.git", 74 | "svn_url": "https://github.com/christoomey/alfred-trello-boards", 75 | "homepage": null, 76 | "size": 338, 77 | "stargazers_count": 8, 78 | "watchers_count": 8, 79 | "language": "Ruby", 80 | "has_issues": true, 81 | "has_projects": true, 82 | "has_downloads": true, 83 | "has_wiki": true, 84 | "has_pages": false, 85 | "forks_count": 4, 86 | "mirror_url": null, 87 | "archived": false, 88 | "open_issues_count": 1, 89 | "license": { 90 | "key": "mit", 91 | "name": "MIT License", 92 | "spdx_id": "MIT", 93 | "url": "https://api.github.com/licenses/mit", 94 | "node_id": "MDc6TGljZW5zZTEz" 95 | }, 96 | "forks": 4, 97 | "open_issues": 1, 98 | "watchers": 8, 99 | "default_branch": "master" 100 | }, 101 | { 102 | "id": 18596511, 103 | "node_id": "MDEwOlJlcG9zaXRvcnkxODU5NjUxMQ==", 104 | "name": "anchorlinks", 105 | "full_name": "christoomey/anchorlinks", 106 | "owner": { 107 | "login": "christoomey", 108 | "id": 420113, 109 | "node_id": "MDQ6VXNlcjQyMDExMw==", 110 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 111 | "gravatar_id": "", 112 | "url": "https://api.github.com/users/christoomey", 113 | "html_url": "https://github.com/christoomey", 114 | "followers_url": "https://api.github.com/users/christoomey/followers", 115 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 116 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 117 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 118 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 119 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 120 | "repos_url": "https://api.github.com/users/christoomey/repos", 121 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 122 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 123 | "type": "User", 124 | "site_admin": false 125 | }, 126 | "private": false, 127 | "html_url": "https://github.com/christoomey/anchorlinks", 128 | "description": "Chrome extension for copying the anchored link to a web page", 129 | "fork": false, 130 | "url": "https://api.github.com/repos/christoomey/anchorlinks", 131 | "forks_url": "https://api.github.com/repos/christoomey/anchorlinks/forks", 132 | "keys_url": "https://api.github.com/repos/christoomey/anchorlinks/keys{/key_id}", 133 | "collaborators_url": "https://api.github.com/repos/christoomey/anchorlinks/collaborators{/collaborator}", 134 | "teams_url": "https://api.github.com/repos/christoomey/anchorlinks/teams", 135 | "hooks_url": "https://api.github.com/repos/christoomey/anchorlinks/hooks", 136 | "issue_events_url": "https://api.github.com/repos/christoomey/anchorlinks/issues/events{/number}", 137 | "events_url": "https://api.github.com/repos/christoomey/anchorlinks/events", 138 | "assignees_url": "https://api.github.com/repos/christoomey/anchorlinks/assignees{/user}", 139 | "branches_url": "https://api.github.com/repos/christoomey/anchorlinks/branches{/branch}", 140 | "tags_url": "https://api.github.com/repos/christoomey/anchorlinks/tags", 141 | "blobs_url": "https://api.github.com/repos/christoomey/anchorlinks/git/blobs{/sha}", 142 | "git_tags_url": "https://api.github.com/repos/christoomey/anchorlinks/git/tags{/sha}", 143 | "git_refs_url": "https://api.github.com/repos/christoomey/anchorlinks/git/refs{/sha}", 144 | "trees_url": "https://api.github.com/repos/christoomey/anchorlinks/git/trees{/sha}", 145 | "statuses_url": "https://api.github.com/repos/christoomey/anchorlinks/statuses/{sha}", 146 | "languages_url": "https://api.github.com/repos/christoomey/anchorlinks/languages", 147 | "stargazers_url": "https://api.github.com/repos/christoomey/anchorlinks/stargazers", 148 | "contributors_url": "https://api.github.com/repos/christoomey/anchorlinks/contributors", 149 | "subscribers_url": "https://api.github.com/repos/christoomey/anchorlinks/subscribers", 150 | "subscription_url": "https://api.github.com/repos/christoomey/anchorlinks/subscription", 151 | "commits_url": "https://api.github.com/repos/christoomey/anchorlinks/commits{/sha}", 152 | "git_commits_url": "https://api.github.com/repos/christoomey/anchorlinks/git/commits{/sha}", 153 | "comments_url": "https://api.github.com/repos/christoomey/anchorlinks/comments{/number}", 154 | "issue_comment_url": "https://api.github.com/repos/christoomey/anchorlinks/issues/comments{/number}", 155 | "contents_url": "https://api.github.com/repos/christoomey/anchorlinks/contents/{+path}", 156 | "compare_url": "https://api.github.com/repos/christoomey/anchorlinks/compare/{base}...{head}", 157 | "merges_url": "https://api.github.com/repos/christoomey/anchorlinks/merges", 158 | "archive_url": "https://api.github.com/repos/christoomey/anchorlinks/{archive_format}{/ref}", 159 | "downloads_url": "https://api.github.com/repos/christoomey/anchorlinks/downloads", 160 | "issues_url": "https://api.github.com/repos/christoomey/anchorlinks/issues{/number}", 161 | "pulls_url": "https://api.github.com/repos/christoomey/anchorlinks/pulls{/number}", 162 | "milestones_url": "https://api.github.com/repos/christoomey/anchorlinks/milestones{/number}", 163 | "notifications_url": "https://api.github.com/repos/christoomey/anchorlinks/notifications{?since,all,participating}", 164 | "labels_url": "https://api.github.com/repos/christoomey/anchorlinks/labels{/name}", 165 | "releases_url": "https://api.github.com/repos/christoomey/anchorlinks/releases{/id}", 166 | "deployments_url": "https://api.github.com/repos/christoomey/anchorlinks/deployments", 167 | "created_at": "2014-04-09T12:35:03Z", 168 | "updated_at": "2014-04-10T17:46:52Z", 169 | "pushed_at": "2014-04-10T17:46:52Z", 170 | "git_url": "git://github.com/christoomey/anchorlinks.git", 171 | "ssh_url": "git@github.com:christoomey/anchorlinks.git", 172 | "clone_url": "https://github.com/christoomey/anchorlinks.git", 173 | "svn_url": "https://github.com/christoomey/anchorlinks", 174 | "homepage": null, 175 | "size": 184, 176 | "stargazers_count": 0, 177 | "watchers_count": 0, 178 | "language": "JavaScript", 179 | "has_issues": true, 180 | "has_projects": true, 181 | "has_downloads": true, 182 | "has_wiki": true, 183 | "has_pages": false, 184 | "forks_count": 1, 185 | "mirror_url": null, 186 | "archived": false, 187 | "open_issues_count": 10, 188 | "license": null, 189 | "forks": 1, 190 | "open_issues": 10, 191 | "watchers": 0, 192 | "default_branch": "master" 193 | }, 194 | { 195 | "id": 1782431, 196 | "node_id": "MDEwOlJlcG9zaXRvcnkxNzgyNDMx", 197 | "name": "conway", 198 | "full_name": "christoomey/conway", 199 | "owner": { 200 | "login": "christoomey", 201 | "id": 420113, 202 | "node_id": "MDQ6VXNlcjQyMDExMw==", 203 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 204 | "gravatar_id": "", 205 | "url": "https://api.github.com/users/christoomey", 206 | "html_url": "https://github.com/christoomey", 207 | "followers_url": "https://api.github.com/users/christoomey/followers", 208 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 209 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 210 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 211 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 212 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 213 | "repos_url": "https://api.github.com/users/christoomey/repos", 214 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 215 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 216 | "type": "User", 217 | "site_admin": false 218 | }, 219 | "private": false, 220 | "html_url": "https://github.com/christoomey/conway", 221 | "description": "jQuery & coffeescript implementation of Conway's Game of Life", 222 | "fork": false, 223 | "url": "https://api.github.com/repos/christoomey/conway", 224 | "forks_url": "https://api.github.com/repos/christoomey/conway/forks", 225 | "keys_url": "https://api.github.com/repos/christoomey/conway/keys{/key_id}", 226 | "collaborators_url": "https://api.github.com/repos/christoomey/conway/collaborators{/collaborator}", 227 | "teams_url": "https://api.github.com/repos/christoomey/conway/teams", 228 | "hooks_url": "https://api.github.com/repos/christoomey/conway/hooks", 229 | "issue_events_url": "https://api.github.com/repos/christoomey/conway/issues/events{/number}", 230 | "events_url": "https://api.github.com/repos/christoomey/conway/events", 231 | "assignees_url": "https://api.github.com/repos/christoomey/conway/assignees{/user}", 232 | "branches_url": "https://api.github.com/repos/christoomey/conway/branches{/branch}", 233 | "tags_url": "https://api.github.com/repos/christoomey/conway/tags", 234 | "blobs_url": "https://api.github.com/repos/christoomey/conway/git/blobs{/sha}", 235 | "git_tags_url": "https://api.github.com/repos/christoomey/conway/git/tags{/sha}", 236 | "git_refs_url": "https://api.github.com/repos/christoomey/conway/git/refs{/sha}", 237 | "trees_url": "https://api.github.com/repos/christoomey/conway/git/trees{/sha}", 238 | "statuses_url": "https://api.github.com/repos/christoomey/conway/statuses/{sha}", 239 | "languages_url": "https://api.github.com/repos/christoomey/conway/languages", 240 | "stargazers_url": "https://api.github.com/repos/christoomey/conway/stargazers", 241 | "contributors_url": "https://api.github.com/repos/christoomey/conway/contributors", 242 | "subscribers_url": "https://api.github.com/repos/christoomey/conway/subscribers", 243 | "subscription_url": "https://api.github.com/repos/christoomey/conway/subscription", 244 | "commits_url": "https://api.github.com/repos/christoomey/conway/commits{/sha}", 245 | "git_commits_url": "https://api.github.com/repos/christoomey/conway/git/commits{/sha}", 246 | "comments_url": "https://api.github.com/repos/christoomey/conway/comments{/number}", 247 | "issue_comment_url": "https://api.github.com/repos/christoomey/conway/issues/comments{/number}", 248 | "contents_url": "https://api.github.com/repos/christoomey/conway/contents/{+path}", 249 | "compare_url": "https://api.github.com/repos/christoomey/conway/compare/{base}...{head}", 250 | "merges_url": "https://api.github.com/repos/christoomey/conway/merges", 251 | "archive_url": "https://api.github.com/repos/christoomey/conway/{archive_format}{/ref}", 252 | "downloads_url": "https://api.github.com/repos/christoomey/conway/downloads", 253 | "issues_url": "https://api.github.com/repos/christoomey/conway/issues{/number}", 254 | "pulls_url": "https://api.github.com/repos/christoomey/conway/pulls{/number}", 255 | "milestones_url": "https://api.github.com/repos/christoomey/conway/milestones{/number}", 256 | "notifications_url": "https://api.github.com/repos/christoomey/conway/notifications{?since,all,participating}", 257 | "labels_url": "https://api.github.com/repos/christoomey/conway/labels{/name}", 258 | "releases_url": "https://api.github.com/repos/christoomey/conway/releases{/id}", 259 | "deployments_url": "https://api.github.com/repos/christoomey/conway/deployments", 260 | "created_at": "2011-05-22T01:34:43Z", 261 | "updated_at": "2015-02-09T01:42:25Z", 262 | "pushed_at": "2011-06-15T22:25:22Z", 263 | "git_url": "git://github.com/christoomey/conway.git", 264 | "ssh_url": "git@github.com:christoomey/conway.git", 265 | "clone_url": "https://github.com/christoomey/conway.git", 266 | "svn_url": "https://github.com/christoomey/conway", 267 | "homepage": "", 268 | "size": 100, 269 | "stargazers_count": 2, 270 | "watchers_count": 2, 271 | "language": "CoffeeScript", 272 | "has_issues": true, 273 | "has_projects": true, 274 | "has_downloads": true, 275 | "has_wiki": true, 276 | "has_pages": false, 277 | "forks_count": 0, 278 | "mirror_url": null, 279 | "archived": false, 280 | "open_issues_count": 3, 281 | "license": null, 282 | "forks": 0, 283 | "open_issues": 3, 284 | "watchers": 2, 285 | "default_branch": "master" 286 | }, 287 | { 288 | "id": 7523295, 289 | "node_id": "MDEwOlJlcG9zaXRvcnk3NTIzMjk1", 290 | "name": "ctrlp-generic", 291 | "full_name": "christoomey/ctrlp-generic", 292 | "owner": { 293 | "login": "christoomey", 294 | "id": 420113, 295 | "node_id": "MDQ6VXNlcjQyMDExMw==", 296 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 297 | "gravatar_id": "", 298 | "url": "https://api.github.com/users/christoomey", 299 | "html_url": "https://github.com/christoomey", 300 | "followers_url": "https://api.github.com/users/christoomey/followers", 301 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 302 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 303 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 304 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 305 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 306 | "repos_url": "https://api.github.com/users/christoomey/repos", 307 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 308 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 309 | "type": "User", 310 | "site_admin": false 311 | }, 312 | "private": false, 313 | "html_url": "https://github.com/christoomey/ctrlp-generic", 314 | "description": "A generic list selection extension to CtrlP for vim", 315 | "fork": false, 316 | "url": "https://api.github.com/repos/christoomey/ctrlp-generic", 317 | "forks_url": "https://api.github.com/repos/christoomey/ctrlp-generic/forks", 318 | "keys_url": "https://api.github.com/repos/christoomey/ctrlp-generic/keys{/key_id}", 319 | "collaborators_url": "https://api.github.com/repos/christoomey/ctrlp-generic/collaborators{/collaborator}", 320 | "teams_url": "https://api.github.com/repos/christoomey/ctrlp-generic/teams", 321 | "hooks_url": "https://api.github.com/repos/christoomey/ctrlp-generic/hooks", 322 | "issue_events_url": "https://api.github.com/repos/christoomey/ctrlp-generic/issues/events{/number}", 323 | "events_url": "https://api.github.com/repos/christoomey/ctrlp-generic/events", 324 | "assignees_url": "https://api.github.com/repos/christoomey/ctrlp-generic/assignees{/user}", 325 | "branches_url": "https://api.github.com/repos/christoomey/ctrlp-generic/branches{/branch}", 326 | "tags_url": "https://api.github.com/repos/christoomey/ctrlp-generic/tags", 327 | "blobs_url": "https://api.github.com/repos/christoomey/ctrlp-generic/git/blobs{/sha}", 328 | "git_tags_url": "https://api.github.com/repos/christoomey/ctrlp-generic/git/tags{/sha}", 329 | "git_refs_url": "https://api.github.com/repos/christoomey/ctrlp-generic/git/refs{/sha}", 330 | "trees_url": "https://api.github.com/repos/christoomey/ctrlp-generic/git/trees{/sha}", 331 | "statuses_url": "https://api.github.com/repos/christoomey/ctrlp-generic/statuses/{sha}", 332 | "languages_url": "https://api.github.com/repos/christoomey/ctrlp-generic/languages", 333 | "stargazers_url": "https://api.github.com/repos/christoomey/ctrlp-generic/stargazers", 334 | "contributors_url": "https://api.github.com/repos/christoomey/ctrlp-generic/contributors", 335 | "subscribers_url": "https://api.github.com/repos/christoomey/ctrlp-generic/subscribers", 336 | "subscription_url": "https://api.github.com/repos/christoomey/ctrlp-generic/subscription", 337 | "commits_url": "https://api.github.com/repos/christoomey/ctrlp-generic/commits{/sha}", 338 | "git_commits_url": "https://api.github.com/repos/christoomey/ctrlp-generic/git/commits{/sha}", 339 | "comments_url": "https://api.github.com/repos/christoomey/ctrlp-generic/comments{/number}", 340 | "issue_comment_url": "https://api.github.com/repos/christoomey/ctrlp-generic/issues/comments{/number}", 341 | "contents_url": "https://api.github.com/repos/christoomey/ctrlp-generic/contents/{+path}", 342 | "compare_url": "https://api.github.com/repos/christoomey/ctrlp-generic/compare/{base}...{head}", 343 | "merges_url": "https://api.github.com/repos/christoomey/ctrlp-generic/merges", 344 | "archive_url": "https://api.github.com/repos/christoomey/ctrlp-generic/{archive_format}{/ref}", 345 | "downloads_url": "https://api.github.com/repos/christoomey/ctrlp-generic/downloads", 346 | "issues_url": "https://api.github.com/repos/christoomey/ctrlp-generic/issues{/number}", 347 | "pulls_url": "https://api.github.com/repos/christoomey/ctrlp-generic/pulls{/number}", 348 | "milestones_url": "https://api.github.com/repos/christoomey/ctrlp-generic/milestones{/number}", 349 | "notifications_url": "https://api.github.com/repos/christoomey/ctrlp-generic/notifications{?since,all,participating}", 350 | "labels_url": "https://api.github.com/repos/christoomey/ctrlp-generic/labels{/name}", 351 | "releases_url": "https://api.github.com/repos/christoomey/ctrlp-generic/releases{/id}", 352 | "deployments_url": "https://api.github.com/repos/christoomey/ctrlp-generic/deployments", 353 | "created_at": "2013-01-09T15:21:31Z", 354 | "updated_at": "2018-07-20T18:35:16Z", 355 | "pushed_at": "2014-11-20T00:45:09Z", 356 | "git_url": "git://github.com/christoomey/ctrlp-generic.git", 357 | "ssh_url": "git@github.com:christoomey/ctrlp-generic.git", 358 | "clone_url": "https://github.com/christoomey/ctrlp-generic.git", 359 | "svn_url": "https://github.com/christoomey/ctrlp-generic", 360 | "homepage": null, 361 | "size": 103, 362 | "stargazers_count": 3, 363 | "watchers_count": 3, 364 | "language": "VimL", 365 | "has_issues": true, 366 | "has_projects": true, 367 | "has_downloads": true, 368 | "has_wiki": true, 369 | "has_pages": false, 370 | "forks_count": 0, 371 | "mirror_url": null, 372 | "archived": false, 373 | "open_issues_count": 1, 374 | "license": null, 375 | "forks": 0, 376 | "open_issues": 1, 377 | "watchers": 3, 378 | "default_branch": "master" 379 | }, 380 | { 381 | "id": 140022763, 382 | "node_id": "MDEwOlJlcG9zaXRvcnkxNDAwMjI3NjM=", 383 | "name": "DefinitelyTyped", 384 | "full_name": "christoomey/DefinitelyTyped", 385 | "owner": { 386 | "login": "christoomey", 387 | "id": 420113, 388 | "node_id": "MDQ6VXNlcjQyMDExMw==", 389 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 390 | "gravatar_id": "", 391 | "url": "https://api.github.com/users/christoomey", 392 | "html_url": "https://github.com/christoomey", 393 | "followers_url": "https://api.github.com/users/christoomey/followers", 394 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 395 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 396 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 397 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 398 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 399 | "repos_url": "https://api.github.com/users/christoomey/repos", 400 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 401 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 402 | "type": "User", 403 | "site_admin": false 404 | }, 405 | "private": false, 406 | "html_url": "https://github.com/christoomey/DefinitelyTyped", 407 | "description": "The repository for high quality TypeScript type definitions.", 408 | "fork": true, 409 | "url": "https://api.github.com/repos/christoomey/DefinitelyTyped", 410 | "forks_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/forks", 411 | "keys_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/keys{/key_id}", 412 | "collaborators_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/collaborators{/collaborator}", 413 | "teams_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/teams", 414 | "hooks_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/hooks", 415 | "issue_events_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/issues/events{/number}", 416 | "events_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/events", 417 | "assignees_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/assignees{/user}", 418 | "branches_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/branches{/branch}", 419 | "tags_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/tags", 420 | "blobs_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/git/blobs{/sha}", 421 | "git_tags_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/git/tags{/sha}", 422 | "git_refs_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/git/refs{/sha}", 423 | "trees_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/git/trees{/sha}", 424 | "statuses_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/statuses/{sha}", 425 | "languages_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/languages", 426 | "stargazers_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/stargazers", 427 | "contributors_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/contributors", 428 | "subscribers_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/subscribers", 429 | "subscription_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/subscription", 430 | "commits_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/commits{/sha}", 431 | "git_commits_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/git/commits{/sha}", 432 | "comments_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/comments{/number}", 433 | "issue_comment_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/issues/comments{/number}", 434 | "contents_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/contents/{+path}", 435 | "compare_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/compare/{base}...{head}", 436 | "merges_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/merges", 437 | "archive_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/{archive_format}{/ref}", 438 | "downloads_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/downloads", 439 | "issues_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/issues{/number}", 440 | "pulls_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/pulls{/number}", 441 | "milestones_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/milestones{/number}", 442 | "notifications_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/notifications{?since,all,participating}", 443 | "labels_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/labels{/name}", 444 | "releases_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/releases{/id}", 445 | "deployments_url": "https://api.github.com/repos/christoomey/DefinitelyTyped/deployments", 446 | "created_at": "2018-07-06T19:28:05Z", 447 | "updated_at": "2018-07-06T19:28:33Z", 448 | "pushed_at": "2018-07-06T19:44:03Z", 449 | "git_url": "git://github.com/christoomey/DefinitelyTyped.git", 450 | "ssh_url": "git@github.com:christoomey/DefinitelyTyped.git", 451 | "clone_url": "https://github.com/christoomey/DefinitelyTyped.git", 452 | "svn_url": "https://github.com/christoomey/DefinitelyTyped", 453 | "homepage": "http://definitelytyped.org/", 454 | "size": 336252, 455 | "stargazers_count": 0, 456 | "watchers_count": 0, 457 | "language": "TypeScript", 458 | "has_issues": false, 459 | "has_projects": true, 460 | "has_downloads": true, 461 | "has_wiki": true, 462 | "has_pages": false, 463 | "forks_count": 0, 464 | "mirror_url": null, 465 | "archived": false, 466 | "open_issues_count": 0, 467 | "license": { 468 | "key": "other", 469 | "name": "Other", 470 | "spdx_id": null, 471 | "url": null, 472 | "node_id": "MDc6TGljZW5zZTA=" 473 | }, 474 | "forks": 0, 475 | "open_issues": 0, 476 | "watchers": 0, 477 | "default_branch": "master" 478 | }, 479 | { 480 | "id": 1030639, 481 | "node_id": "MDEwOlJlcG9zaXRvcnkxMDMwNjM5", 482 | "name": "dotfiles", 483 | "full_name": "christoomey/dotfiles", 484 | "owner": { 485 | "login": "christoomey", 486 | "id": 420113, 487 | "node_id": "MDQ6VXNlcjQyMDExMw==", 488 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 489 | "gravatar_id": "", 490 | "url": "https://api.github.com/users/christoomey", 491 | "html_url": "https://github.com/christoomey", 492 | "followers_url": "https://api.github.com/users/christoomey/followers", 493 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 494 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 495 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 496 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 497 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 498 | "repos_url": "https://api.github.com/users/christoomey/repos", 499 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 500 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 501 | "type": "User", 502 | "site_admin": false 503 | }, 504 | "private": false, 505 | "html_url": "https://github.com/christoomey/dotfiles", 506 | "description": "My vim, bash, git, and other config files", 507 | "fork": false, 508 | "url": "https://api.github.com/repos/christoomey/dotfiles", 509 | "forks_url": "https://api.github.com/repos/christoomey/dotfiles/forks", 510 | "keys_url": "https://api.github.com/repos/christoomey/dotfiles/keys{/key_id}", 511 | "collaborators_url": "https://api.github.com/repos/christoomey/dotfiles/collaborators{/collaborator}", 512 | "teams_url": "https://api.github.com/repos/christoomey/dotfiles/teams", 513 | "hooks_url": "https://api.github.com/repos/christoomey/dotfiles/hooks", 514 | "issue_events_url": "https://api.github.com/repos/christoomey/dotfiles/issues/events{/number}", 515 | "events_url": "https://api.github.com/repos/christoomey/dotfiles/events", 516 | "assignees_url": "https://api.github.com/repos/christoomey/dotfiles/assignees{/user}", 517 | "branches_url": "https://api.github.com/repos/christoomey/dotfiles/branches{/branch}", 518 | "tags_url": "https://api.github.com/repos/christoomey/dotfiles/tags", 519 | "blobs_url": "https://api.github.com/repos/christoomey/dotfiles/git/blobs{/sha}", 520 | "git_tags_url": "https://api.github.com/repos/christoomey/dotfiles/git/tags{/sha}", 521 | "git_refs_url": "https://api.github.com/repos/christoomey/dotfiles/git/refs{/sha}", 522 | "trees_url": "https://api.github.com/repos/christoomey/dotfiles/git/trees{/sha}", 523 | "statuses_url": "https://api.github.com/repos/christoomey/dotfiles/statuses/{sha}", 524 | "languages_url": "https://api.github.com/repos/christoomey/dotfiles/languages", 525 | "stargazers_url": "https://api.github.com/repos/christoomey/dotfiles/stargazers", 526 | "contributors_url": "https://api.github.com/repos/christoomey/dotfiles/contributors", 527 | "subscribers_url": "https://api.github.com/repos/christoomey/dotfiles/subscribers", 528 | "subscription_url": "https://api.github.com/repos/christoomey/dotfiles/subscription", 529 | "commits_url": "https://api.github.com/repos/christoomey/dotfiles/commits{/sha}", 530 | "git_commits_url": "https://api.github.com/repos/christoomey/dotfiles/git/commits{/sha}", 531 | "comments_url": "https://api.github.com/repos/christoomey/dotfiles/comments{/number}", 532 | "issue_comment_url": "https://api.github.com/repos/christoomey/dotfiles/issues/comments{/number}", 533 | "contents_url": "https://api.github.com/repos/christoomey/dotfiles/contents/{+path}", 534 | "compare_url": "https://api.github.com/repos/christoomey/dotfiles/compare/{base}...{head}", 535 | "merges_url": "https://api.github.com/repos/christoomey/dotfiles/merges", 536 | "archive_url": "https://api.github.com/repos/christoomey/dotfiles/{archive_format}{/ref}", 537 | "downloads_url": "https://api.github.com/repos/christoomey/dotfiles/downloads", 538 | "issues_url": "https://api.github.com/repos/christoomey/dotfiles/issues{/number}", 539 | "pulls_url": "https://api.github.com/repos/christoomey/dotfiles/pulls{/number}", 540 | "milestones_url": "https://api.github.com/repos/christoomey/dotfiles/milestones{/number}", 541 | "notifications_url": "https://api.github.com/repos/christoomey/dotfiles/notifications{?since,all,participating}", 542 | "labels_url": "https://api.github.com/repos/christoomey/dotfiles/labels{/name}", 543 | "releases_url": "https://api.github.com/repos/christoomey/dotfiles/releases{/id}", 544 | "deployments_url": "https://api.github.com/repos/christoomey/dotfiles/deployments", 545 | "created_at": "2010-10-28T02:27:07Z", 546 | "updated_at": "2018-08-12T21:24:37Z", 547 | "pushed_at": "2018-05-08T15:23:08Z", 548 | "git_url": "git://github.com/christoomey/dotfiles.git", 549 | "ssh_url": "git@github.com:christoomey/dotfiles.git", 550 | "clone_url": "https://github.com/christoomey/dotfiles.git", 551 | "svn_url": "https://github.com/christoomey/dotfiles", 552 | "homepage": "", 553 | "size": 642, 554 | "stargazers_count": 241, 555 | "watchers_count": 241, 556 | "language": "Vim script", 557 | "has_issues": true, 558 | "has_projects": true, 559 | "has_downloads": true, 560 | "has_wiki": false, 561 | "has_pages": false, 562 | "forks_count": 14, 563 | "mirror_url": null, 564 | "archived": false, 565 | "open_issues_count": 42, 566 | "license": { 567 | "key": "mit", 568 | "name": "MIT License", 569 | "spdx_id": "MIT", 570 | "url": "https://api.github.com/licenses/mit", 571 | "node_id": "MDc6TGljZW5zZTEz" 572 | }, 573 | "forks": 14, 574 | "open_issues": 42, 575 | "watchers": 241, 576 | "default_branch": "master" 577 | }, 578 | { 579 | "id": 5198175, 580 | "node_id": "MDEwOlJlcG9zaXRvcnk1MTk4MTc1", 581 | "name": "emit", 582 | "full_name": "christoomey/emit", 583 | "owner": { 584 | "login": "christoomey", 585 | "id": 420113, 586 | "node_id": "MDQ6VXNlcjQyMDExMw==", 587 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 588 | "gravatar_id": "", 589 | "url": "https://api.github.com/users/christoomey", 590 | "html_url": "https://github.com/christoomey", 591 | "followers_url": "https://api.github.com/users/christoomey/followers", 592 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 593 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 594 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 595 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 596 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 597 | "repos_url": "https://api.github.com/users/christoomey/repos", 598 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 599 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 600 | "type": "User", 601 | "site_admin": false 602 | }, 603 | "private": false, 604 | "html_url": "https://github.com/christoomey/emit", 605 | "description": "Fun with canvas animation", 606 | "fork": false, 607 | "url": "https://api.github.com/repos/christoomey/emit", 608 | "forks_url": "https://api.github.com/repos/christoomey/emit/forks", 609 | "keys_url": "https://api.github.com/repos/christoomey/emit/keys{/key_id}", 610 | "collaborators_url": "https://api.github.com/repos/christoomey/emit/collaborators{/collaborator}", 611 | "teams_url": "https://api.github.com/repos/christoomey/emit/teams", 612 | "hooks_url": "https://api.github.com/repos/christoomey/emit/hooks", 613 | "issue_events_url": "https://api.github.com/repos/christoomey/emit/issues/events{/number}", 614 | "events_url": "https://api.github.com/repos/christoomey/emit/events", 615 | "assignees_url": "https://api.github.com/repos/christoomey/emit/assignees{/user}", 616 | "branches_url": "https://api.github.com/repos/christoomey/emit/branches{/branch}", 617 | "tags_url": "https://api.github.com/repos/christoomey/emit/tags", 618 | "blobs_url": "https://api.github.com/repos/christoomey/emit/git/blobs{/sha}", 619 | "git_tags_url": "https://api.github.com/repos/christoomey/emit/git/tags{/sha}", 620 | "git_refs_url": "https://api.github.com/repos/christoomey/emit/git/refs{/sha}", 621 | "trees_url": "https://api.github.com/repos/christoomey/emit/git/trees{/sha}", 622 | "statuses_url": "https://api.github.com/repos/christoomey/emit/statuses/{sha}", 623 | "languages_url": "https://api.github.com/repos/christoomey/emit/languages", 624 | "stargazers_url": "https://api.github.com/repos/christoomey/emit/stargazers", 625 | "contributors_url": "https://api.github.com/repos/christoomey/emit/contributors", 626 | "subscribers_url": "https://api.github.com/repos/christoomey/emit/subscribers", 627 | "subscription_url": "https://api.github.com/repos/christoomey/emit/subscription", 628 | "commits_url": "https://api.github.com/repos/christoomey/emit/commits{/sha}", 629 | "git_commits_url": "https://api.github.com/repos/christoomey/emit/git/commits{/sha}", 630 | "comments_url": "https://api.github.com/repos/christoomey/emit/comments{/number}", 631 | "issue_comment_url": "https://api.github.com/repos/christoomey/emit/issues/comments{/number}", 632 | "contents_url": "https://api.github.com/repos/christoomey/emit/contents/{+path}", 633 | "compare_url": "https://api.github.com/repos/christoomey/emit/compare/{base}...{head}", 634 | "merges_url": "https://api.github.com/repos/christoomey/emit/merges", 635 | "archive_url": "https://api.github.com/repos/christoomey/emit/{archive_format}{/ref}", 636 | "downloads_url": "https://api.github.com/repos/christoomey/emit/downloads", 637 | "issues_url": "https://api.github.com/repos/christoomey/emit/issues{/number}", 638 | "pulls_url": "https://api.github.com/repos/christoomey/emit/pulls{/number}", 639 | "milestones_url": "https://api.github.com/repos/christoomey/emit/milestones{/number}", 640 | "notifications_url": "https://api.github.com/repos/christoomey/emit/notifications{?since,all,participating}", 641 | "labels_url": "https://api.github.com/repos/christoomey/emit/labels{/name}", 642 | "releases_url": "https://api.github.com/repos/christoomey/emit/releases{/id}", 643 | "deployments_url": "https://api.github.com/repos/christoomey/emit/deployments", 644 | "created_at": "2012-07-26T22:37:54Z", 645 | "updated_at": "2014-04-27T17:20:09Z", 646 | "pushed_at": "2012-07-27T00:47:58Z", 647 | "git_url": "git://github.com/christoomey/emit.git", 648 | "ssh_url": "git@github.com:christoomey/emit.git", 649 | "clone_url": "https://github.com/christoomey/emit.git", 650 | "svn_url": "https://github.com/christoomey/emit", 651 | "homepage": null, 652 | "size": 256, 653 | "stargazers_count": 1, 654 | "watchers_count": 1, 655 | "language": "Ruby", 656 | "has_issues": true, 657 | "has_projects": true, 658 | "has_downloads": true, 659 | "has_wiki": true, 660 | "has_pages": false, 661 | "forks_count": 0, 662 | "mirror_url": null, 663 | "archived": false, 664 | "open_issues_count": 0, 665 | "license": null, 666 | "forks": 0, 667 | "open_issues": 0, 668 | "watchers": 1, 669 | "default_branch": "master" 670 | }, 671 | { 672 | "id": 6116102, 673 | "node_id": "MDEwOlJlcG9zaXRvcnk2MTE2MTAy", 674 | "name": "euler", 675 | "full_name": "christoomey/euler", 676 | "owner": { 677 | "login": "christoomey", 678 | "id": 420113, 679 | "node_id": "MDQ6VXNlcjQyMDExMw==", 680 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 681 | "gravatar_id": "", 682 | "url": "https://api.github.com/users/christoomey", 683 | "html_url": "https://github.com/christoomey", 684 | "followers_url": "https://api.github.com/users/christoomey/followers", 685 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 686 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 687 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 688 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 689 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 690 | "repos_url": "https://api.github.com/users/christoomey/repos", 691 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 692 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 693 | "type": "User", 694 | "site_admin": false 695 | }, 696 | "private": false, 697 | "html_url": "https://github.com/christoomey/euler", 698 | "description": "My solutions to project euler", 699 | "fork": false, 700 | "url": "https://api.github.com/repos/christoomey/euler", 701 | "forks_url": "https://api.github.com/repos/christoomey/euler/forks", 702 | "keys_url": "https://api.github.com/repos/christoomey/euler/keys{/key_id}", 703 | "collaborators_url": "https://api.github.com/repos/christoomey/euler/collaborators{/collaborator}", 704 | "teams_url": "https://api.github.com/repos/christoomey/euler/teams", 705 | "hooks_url": "https://api.github.com/repos/christoomey/euler/hooks", 706 | "issue_events_url": "https://api.github.com/repos/christoomey/euler/issues/events{/number}", 707 | "events_url": "https://api.github.com/repos/christoomey/euler/events", 708 | "assignees_url": "https://api.github.com/repos/christoomey/euler/assignees{/user}", 709 | "branches_url": "https://api.github.com/repos/christoomey/euler/branches{/branch}", 710 | "tags_url": "https://api.github.com/repos/christoomey/euler/tags", 711 | "blobs_url": "https://api.github.com/repos/christoomey/euler/git/blobs{/sha}", 712 | "git_tags_url": "https://api.github.com/repos/christoomey/euler/git/tags{/sha}", 713 | "git_refs_url": "https://api.github.com/repos/christoomey/euler/git/refs{/sha}", 714 | "trees_url": "https://api.github.com/repos/christoomey/euler/git/trees{/sha}", 715 | "statuses_url": "https://api.github.com/repos/christoomey/euler/statuses/{sha}", 716 | "languages_url": "https://api.github.com/repos/christoomey/euler/languages", 717 | "stargazers_url": "https://api.github.com/repos/christoomey/euler/stargazers", 718 | "contributors_url": "https://api.github.com/repos/christoomey/euler/contributors", 719 | "subscribers_url": "https://api.github.com/repos/christoomey/euler/subscribers", 720 | "subscription_url": "https://api.github.com/repos/christoomey/euler/subscription", 721 | "commits_url": "https://api.github.com/repos/christoomey/euler/commits{/sha}", 722 | "git_commits_url": "https://api.github.com/repos/christoomey/euler/git/commits{/sha}", 723 | "comments_url": "https://api.github.com/repos/christoomey/euler/comments{/number}", 724 | "issue_comment_url": "https://api.github.com/repos/christoomey/euler/issues/comments{/number}", 725 | "contents_url": "https://api.github.com/repos/christoomey/euler/contents/{+path}", 726 | "compare_url": "https://api.github.com/repos/christoomey/euler/compare/{base}...{head}", 727 | "merges_url": "https://api.github.com/repos/christoomey/euler/merges", 728 | "archive_url": "https://api.github.com/repos/christoomey/euler/{archive_format}{/ref}", 729 | "downloads_url": "https://api.github.com/repos/christoomey/euler/downloads", 730 | "issues_url": "https://api.github.com/repos/christoomey/euler/issues{/number}", 731 | "pulls_url": "https://api.github.com/repos/christoomey/euler/pulls{/number}", 732 | "milestones_url": "https://api.github.com/repos/christoomey/euler/milestones{/number}", 733 | "notifications_url": "https://api.github.com/repos/christoomey/euler/notifications{?since,all,participating}", 734 | "labels_url": "https://api.github.com/repos/christoomey/euler/labels{/name}", 735 | "releases_url": "https://api.github.com/repos/christoomey/euler/releases{/id}", 736 | "deployments_url": "https://api.github.com/repos/christoomey/euler/deployments", 737 | "created_at": "2012-10-07T20:40:02Z", 738 | "updated_at": "2013-10-27T18:37:52Z", 739 | "pushed_at": "2012-10-08T23:43:59Z", 740 | "git_url": "git://github.com/christoomey/euler.git", 741 | "ssh_url": "git@github.com:christoomey/euler.git", 742 | "clone_url": "https://github.com/christoomey/euler.git", 743 | "svn_url": "https://github.com/christoomey/euler", 744 | "homepage": null, 745 | "size": 108, 746 | "stargazers_count": 0, 747 | "watchers_count": 0, 748 | "language": "Ruby", 749 | "has_issues": true, 750 | "has_projects": true, 751 | "has_downloads": true, 752 | "has_wiki": true, 753 | "has_pages": false, 754 | "forks_count": 0, 755 | "mirror_url": null, 756 | "archived": false, 757 | "open_issues_count": 0, 758 | "license": null, 759 | "forks": 0, 760 | "open_issues": 0, 761 | "watchers": 0, 762 | "default_branch": "master" 763 | }, 764 | { 765 | "id": 111120261, 766 | "node_id": "MDEwOlJlcG9zaXRvcnkxMTExMjAyNjE=", 767 | "name": "github-tell-me-when-it-closes-extension", 768 | "full_name": "christoomey/github-tell-me-when-it-closes-extension", 769 | "owner": { 770 | "login": "christoomey", 771 | "id": 420113, 772 | "node_id": "MDQ6VXNlcjQyMDExMw==", 773 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 774 | "gravatar_id": "", 775 | "url": "https://api.github.com/users/christoomey", 776 | "html_url": "https://github.com/christoomey", 777 | "followers_url": "https://api.github.com/users/christoomey/followers", 778 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 779 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 780 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 781 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 782 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 783 | "repos_url": "https://api.github.com/users/christoomey/repos", 784 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 785 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 786 | "type": "User", 787 | "site_admin": false 788 | }, 789 | "private": false, 790 | "html_url": "https://github.com/christoomey/github-tell-me-when-it-closes-extension", 791 | "description": "Browser Extension for tellmewhenitcloses.com", 792 | "fork": true, 793 | "url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension", 794 | "forks_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/forks", 795 | "keys_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/keys{/key_id}", 796 | "collaborators_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/collaborators{/collaborator}", 797 | "teams_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/teams", 798 | "hooks_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/hooks", 799 | "issue_events_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/issues/events{/number}", 800 | "events_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/events", 801 | "assignees_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/assignees{/user}", 802 | "branches_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/branches{/branch}", 803 | "tags_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/tags", 804 | "blobs_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/git/blobs{/sha}", 805 | "git_tags_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/git/tags{/sha}", 806 | "git_refs_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/git/refs{/sha}", 807 | "trees_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/git/trees{/sha}", 808 | "statuses_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/statuses/{sha}", 809 | "languages_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/languages", 810 | "stargazers_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/stargazers", 811 | "contributors_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/contributors", 812 | "subscribers_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/subscribers", 813 | "subscription_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/subscription", 814 | "commits_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/commits{/sha}", 815 | "git_commits_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/git/commits{/sha}", 816 | "comments_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/comments{/number}", 817 | "issue_comment_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/issues/comments{/number}", 818 | "contents_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/contents/{+path}", 819 | "compare_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/compare/{base}...{head}", 820 | "merges_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/merges", 821 | "archive_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/{archive_format}{/ref}", 822 | "downloads_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/downloads", 823 | "issues_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/issues{/number}", 824 | "pulls_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/pulls{/number}", 825 | "milestones_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/milestones{/number}", 826 | "notifications_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/notifications{?since,all,participating}", 827 | "labels_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/labels{/name}", 828 | "releases_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/releases{/id}", 829 | "deployments_url": "https://api.github.com/repos/christoomey/github-tell-me-when-it-closes-extension/deployments", 830 | "created_at": "2017-11-17T15:39:07Z", 831 | "updated_at": "2017-11-17T15:39:09Z", 832 | "pushed_at": "2017-11-19T00:22:45Z", 833 | "git_url": "git://github.com/christoomey/github-tell-me-when-it-closes-extension.git", 834 | "ssh_url": "git@github.com:christoomey/github-tell-me-when-it-closes-extension.git", 835 | "clone_url": "https://github.com/christoomey/github-tell-me-when-it-closes-extension.git", 836 | "svn_url": "https://github.com/christoomey/github-tell-me-when-it-closes-extension", 837 | "homepage": "https://kevinjalbert.com/github-tell-me-when-it-closes-extension/", 838 | "size": 4319, 839 | "stargazers_count": 0, 840 | "watchers_count": 0, 841 | "language": "JavaScript", 842 | "has_issues": false, 843 | "has_projects": true, 844 | "has_downloads": true, 845 | "has_wiki": true, 846 | "has_pages": false, 847 | "forks_count": 0, 848 | "mirror_url": null, 849 | "archived": false, 850 | "open_issues_count": 0, 851 | "license": { 852 | "key": "mit", 853 | "name": "MIT License", 854 | "spdx_id": "MIT", 855 | "url": "https://api.github.com/licenses/mit", 856 | "node_id": "MDc6TGljZW5zZTEz" 857 | }, 858 | "forks": 0, 859 | "open_issues": 0, 860 | "watchers": 0, 861 | "default_branch": "master" 862 | }, 863 | { 864 | "id": 47783847, 865 | "node_id": "MDEwOlJlcG9zaXRvcnk0Nzc4Mzg0Nw==", 866 | "name": "go-react-web", 867 | "full_name": "christoomey/go-react-web", 868 | "owner": { 869 | "login": "christoomey", 870 | "id": 420113, 871 | "node_id": "MDQ6VXNlcjQyMDExMw==", 872 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 873 | "gravatar_id": "", 874 | "url": "https://api.github.com/users/christoomey", 875 | "html_url": "https://github.com/christoomey", 876 | "followers_url": "https://api.github.com/users/christoomey/followers", 877 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 878 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 879 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 880 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 881 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 882 | "repos_url": "https://api.github.com/users/christoomey/repos", 883 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 884 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 885 | "type": "User", 886 | "site_admin": false 887 | }, 888 | "private": false, 889 | "html_url": "https://github.com/christoomey/go-react-web", 890 | "description": null, 891 | "fork": false, 892 | "url": "https://api.github.com/repos/christoomey/go-react-web", 893 | "forks_url": "https://api.github.com/repos/christoomey/go-react-web/forks", 894 | "keys_url": "https://api.github.com/repos/christoomey/go-react-web/keys{/key_id}", 895 | "collaborators_url": "https://api.github.com/repos/christoomey/go-react-web/collaborators{/collaborator}", 896 | "teams_url": "https://api.github.com/repos/christoomey/go-react-web/teams", 897 | "hooks_url": "https://api.github.com/repos/christoomey/go-react-web/hooks", 898 | "issue_events_url": "https://api.github.com/repos/christoomey/go-react-web/issues/events{/number}", 899 | "events_url": "https://api.github.com/repos/christoomey/go-react-web/events", 900 | "assignees_url": "https://api.github.com/repos/christoomey/go-react-web/assignees{/user}", 901 | "branches_url": "https://api.github.com/repos/christoomey/go-react-web/branches{/branch}", 902 | "tags_url": "https://api.github.com/repos/christoomey/go-react-web/tags", 903 | "blobs_url": "https://api.github.com/repos/christoomey/go-react-web/git/blobs{/sha}", 904 | "git_tags_url": "https://api.github.com/repos/christoomey/go-react-web/git/tags{/sha}", 905 | "git_refs_url": "https://api.github.com/repos/christoomey/go-react-web/git/refs{/sha}", 906 | "trees_url": "https://api.github.com/repos/christoomey/go-react-web/git/trees{/sha}", 907 | "statuses_url": "https://api.github.com/repos/christoomey/go-react-web/statuses/{sha}", 908 | "languages_url": "https://api.github.com/repos/christoomey/go-react-web/languages", 909 | "stargazers_url": "https://api.github.com/repos/christoomey/go-react-web/stargazers", 910 | "contributors_url": "https://api.github.com/repos/christoomey/go-react-web/contributors", 911 | "subscribers_url": "https://api.github.com/repos/christoomey/go-react-web/subscribers", 912 | "subscription_url": "https://api.github.com/repos/christoomey/go-react-web/subscription", 913 | "commits_url": "https://api.github.com/repos/christoomey/go-react-web/commits{/sha}", 914 | "git_commits_url": "https://api.github.com/repos/christoomey/go-react-web/git/commits{/sha}", 915 | "comments_url": "https://api.github.com/repos/christoomey/go-react-web/comments{/number}", 916 | "issue_comment_url": "https://api.github.com/repos/christoomey/go-react-web/issues/comments{/number}", 917 | "contents_url": "https://api.github.com/repos/christoomey/go-react-web/contents/{+path}", 918 | "compare_url": "https://api.github.com/repos/christoomey/go-react-web/compare/{base}...{head}", 919 | "merges_url": "https://api.github.com/repos/christoomey/go-react-web/merges", 920 | "archive_url": "https://api.github.com/repos/christoomey/go-react-web/{archive_format}{/ref}", 921 | "downloads_url": "https://api.github.com/repos/christoomey/go-react-web/downloads", 922 | "issues_url": "https://api.github.com/repos/christoomey/go-react-web/issues{/number}", 923 | "pulls_url": "https://api.github.com/repos/christoomey/go-react-web/pulls{/number}", 924 | "milestones_url": "https://api.github.com/repos/christoomey/go-react-web/milestones{/number}", 925 | "notifications_url": "https://api.github.com/repos/christoomey/go-react-web/notifications{?since,all,participating}", 926 | "labels_url": "https://api.github.com/repos/christoomey/go-react-web/labels{/name}", 927 | "releases_url": "https://api.github.com/repos/christoomey/go-react-web/releases{/id}", 928 | "deployments_url": "https://api.github.com/repos/christoomey/go-react-web/deployments", 929 | "created_at": "2015-12-10T19:49:33Z", 930 | "updated_at": "2015-12-11T19:39:51Z", 931 | "pushed_at": "2015-12-11T20:15:43Z", 932 | "git_url": "git://github.com/christoomey/go-react-web.git", 933 | "ssh_url": "git@github.com:christoomey/go-react-web.git", 934 | "clone_url": "https://github.com/christoomey/go-react-web.git", 935 | "svn_url": "https://github.com/christoomey/go-react-web", 936 | "homepage": null, 937 | "size": 60, 938 | "stargazers_count": 0, 939 | "watchers_count": 0, 940 | "language": "JavaScript", 941 | "has_issues": true, 942 | "has_projects": true, 943 | "has_downloads": true, 944 | "has_wiki": true, 945 | "has_pages": false, 946 | "forks_count": 1, 947 | "mirror_url": null, 948 | "archived": false, 949 | "open_issues_count": 1, 950 | "license": { 951 | "key": "mit", 952 | "name": "MIT License", 953 | "spdx_id": "MIT", 954 | "url": "https://api.github.com/licenses/mit", 955 | "node_id": "MDc6TGljZW5zZTEz" 956 | }, 957 | "forks": 1, 958 | "open_issues": 1, 959 | "watchers": 0, 960 | "default_branch": "master" 961 | } 962 | ] 963 | -------------------------------------------------------------------------------- /queries/rest/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "christoomey", 3 | "id": 420113, 4 | "node_id": "MDQ6VXNlcjQyMDExMw==", 5 | "avatar_url": "https://avatars2.githubusercontent.com/u/420113?v=4", 6 | "gravatar_id": "", 7 | "url": "https://api.github.com/users/christoomey", 8 | "html_url": "https://github.com/christoomey", 9 | "followers_url": "https://api.github.com/users/christoomey/followers", 10 | "following_url": "https://api.github.com/users/christoomey/following{/other_user}", 11 | "gists_url": "https://api.github.com/users/christoomey/gists{/gist_id}", 12 | "starred_url": "https://api.github.com/users/christoomey/starred{/owner}{/repo}", 13 | "subscriptions_url": "https://api.github.com/users/christoomey/subscriptions", 14 | "organizations_url": "https://api.github.com/users/christoomey/orgs", 15 | "repos_url": "https://api.github.com/users/christoomey/repos", 16 | "events_url": "https://api.github.com/users/christoomey/events{/privacy}", 17 | "received_events_url": "https://api.github.com/users/christoomey/received_events", 18 | "type": "User", 19 | "site_admin": false, 20 | "name": "Chris Toomey", 21 | "company": "@thoughtbot", 22 | "blog": "https://ctoomey.com", 23 | "location": "Boston, MA", 24 | "email": null, 25 | "hireable": true, 26 | "bio": "Developer @thoughtbot focused on Ruby, JS, Scala, and Elm.", 27 | "public_repos": 41, 28 | "public_gists": 36, 29 | "followers": 337, 30 | "following": 9, 31 | "created_at": "2010-09-29T02:36:15Z", 32 | "updated_at": "2018-08-12T21:35:02Z" 33 | } 34 | -------------------------------------------------------------------------------- /src/components/Avatar.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {spacing} from '../styles'; 3 | 4 | const Avatar = styled.img` 5 | border-radius: 3px; 6 | height: ${props => size(props)}em; 7 | margin-right: ${spacing.small}; 8 | width: ${props => size(props)}em; 9 | `; 10 | 11 | const size = ({tiny, small, large}) => { 12 | if (tiny) { 13 | return 2; 14 | } else if (small) { 15 | return 3; 16 | } else if (large) { 17 | return 10; 18 | // eslint-disable-next-line 19 | } else { 20 | return 3; 21 | } 22 | }; 23 | 24 | export default Avatar; 25 | -------------------------------------------------------------------------------- /src/components/Button.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | const Button = styled.button` 4 | background-color: #ddd; 5 | `; 6 | 7 | export default Button; 8 | -------------------------------------------------------------------------------- /src/components/Circle.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | const Circle = styled.span` 4 | background-color: ${props => props.color}; 5 | border-radius: 50%; 6 | display: inline-block; 7 | height: 0.75em; 8 | margin-right: 0.25em; 9 | width: 0.75em; 10 | `; 11 | 12 | export default Circle; 13 | -------------------------------------------------------------------------------- /src/components/DefaultQuery.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Query} from 'react-apollo'; 3 | 4 | const DefaultQuery = ({query, variables = {}, children}) => ( 5 | 6 | {({loading, error, data, fetchMore}) => { 7 | if (loading) 8 | return ( 9 |
10 |

loading...

11 |
12 | ); 13 | if (error) 14 | return ( 15 |
16 |

{`Error!: ${error}`}

17 |
18 | ); 19 | 20 | return children({data, fetchMore}); 21 | }} 22 |
23 | ); 24 | 25 | export default DefaultQuery; 26 | -------------------------------------------------------------------------------- /src/components/Flex.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {spacing} from '../styles'; 3 | 4 | const Flex = styled.div` 5 | display: flex; 6 | ${props => props.spaceBetween && 'justify-content: space-between'}; 7 | `; 8 | 9 | export const Column = styled(Flex)` 10 | flex-direction: column; 11 | height: 100%; 12 | `; 13 | 14 | export const Row = styled(Flex)``; 15 | 16 | export const PaddedRow = styled(Row)` 17 | margin-bottom: ${spacing.small}; 18 | `; 19 | -------------------------------------------------------------------------------- /src/components/Grid.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {spacing} from '../styles'; 3 | 4 | const Grid = styled.ul` 5 | padding: 0; 6 | display: grid; 7 | grid-template-columns: ${props => templateColumns(props)}; 8 | grid-gap: ${spacing.small} ${spacing.normal}; 9 | `; 10 | 11 | const templateColumns = ({columns}) => 12 | [...Array(columns)].map(() => '1fr').join(' '); 13 | 14 | export default Grid; 15 | -------------------------------------------------------------------------------- /src/components/Headings.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Title = styled.span` 4 | color: #333; 5 | font-size: 1.5em; 6 | `; 7 | 8 | export const Subtitle = styled.span` 9 | color: #666; 10 | font-size: 0.8em; 11 | `; 12 | -------------------------------------------------------------------------------- /src/components/Icon.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {RepoForkedIcon, StarIcon as Star} from 'react-octicons'; 3 | 4 | export const StarIcon = styled(Star)` 5 | margin-right: 0.25em; 6 | `; 7 | 8 | export const ForkedIcon = styled(RepoForkedIcon)` 9 | margin-right: 0.25em; 10 | `; 11 | -------------------------------------------------------------------------------- /src/components/Language.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import Circle from './Circle'; 4 | 5 | const Language = ({language}) => ( 6 | 7 | 8 | {language.name} 9 | 10 | ); 11 | 12 | Language.fragment = gql` 13 | fragment Language on Language { 14 | id 15 | name 16 | color 17 | } 18 | `; 19 | 20 | export default Language; 21 | -------------------------------------------------------------------------------- /src/components/LoadMoreButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const LoadMoreButton = ({edges, fetchMore}) => ( 4 | 7 | ); 8 | 9 | const loadMoreResults = (edges, fetchMore) => { 10 | const {cursor} = edges[edges.length - 1]; 11 | fetchMore({ 12 | variables: {cursor}, 13 | updateQuery: (previousResult, {fetchMoreResult}) => ({ 14 | ...previousResult, 15 | search: { 16 | __typename: previousResult.search.__typename, 17 | edges: [ 18 | ...previousResult.search.edges, 19 | ...fetchMoreResult.search.edges, 20 | ], 21 | }, 22 | }), 23 | }); 24 | }; 25 | 26 | export default LoadMoreButton; 27 | -------------------------------------------------------------------------------- /src/components/Org.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import Avatar from './Avatar'; 4 | 5 | const Org = ({org}) => ( 6 | 7 | ); 8 | 9 | Org.fragment = gql` 10 | fragment Org on Organization { 11 | id 12 | name 13 | avatarUrl 14 | } 15 | `; 16 | 17 | export default Org; 18 | -------------------------------------------------------------------------------- /src/components/Page.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {spacing} from '../styles'; 3 | 4 | const Page = styled.main` 5 | background: white; 6 | margin: ${spacing.large} auto; 7 | max-width: 650px; 8 | `; 9 | 10 | export default Page; 11 | -------------------------------------------------------------------------------- /src/components/Repo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import RepoHeader from './RepoHeader'; 4 | import RepoStats from './RepoStats'; 5 | import Tile from './Tile'; 6 | import {Column} from './Flex'; 7 | 8 | const Repo = ({repo}) => ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | 17 | Repo.fragment = gql` 18 | fragment Repo on Repository { 19 | id 20 | ...RepoHeader 21 | ...RepoStats 22 | } 23 | 24 | ${RepoStats.fragment} 25 | ${RepoHeader.fragment} 26 | `; 27 | 28 | export default Repo; 29 | -------------------------------------------------------------------------------- /src/components/RepoHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import ToggleStarButton from './ToggleStarButton'; 4 | import {Row} from './Flex'; 5 | import TitleLink from './TitleLink'; 6 | 7 | const RepoHeader = ({repo}) => ( 8 |
9 | 10 | {repo.name} 11 | 12 | 13 |

{repo.description}

14 |
15 | ); 16 | 17 | RepoHeader.fragment = gql` 18 | fragment RepoHeader on Repository { 19 | id 20 | url 21 | name 22 | description 23 | ...ToggleStarButton 24 | } 25 | ${ToggleStarButton.fragment} 26 | `; 27 | 28 | export default RepoHeader; 29 | -------------------------------------------------------------------------------- /src/components/RepoStats.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import Language from './Language'; 4 | import {StarIcon, ForkedIcon} from './Icon'; 5 | import {Row} from './Flex'; 6 | 7 | const RepoStats = ({repo}) => ( 8 | 9 | { repo.primaryLanguage && } 10 | 11 | 12 | {repo.forkCount} 13 | 14 | 15 | 16 | {repo.stargazers.totalCount} 17 | 18 | 19 | ); 20 | 21 | RepoStats.fragment = gql` 22 | fragment RepoStats on Repository { 23 | id 24 | forkCount 25 | stargazers { 26 | totalCount 27 | } 28 | primaryLanguage { 29 | ...Language 30 | } 31 | } 32 | 33 | ${Language.fragment} 34 | `; 35 | 36 | export default RepoStats; 37 | -------------------------------------------------------------------------------- /src/components/Tile.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {spacing} from '../styles'; 3 | 4 | const Tile = styled.li` 5 | border-radius: 3px; 6 | border: 1px solid lightgray; 7 | list-style: none; 8 | margin-bottom: ${spacing.small}; 9 | padding: ${props => props.full || spacing.small}; 10 | `; 11 | 12 | export default Tile; 13 | -------------------------------------------------------------------------------- /src/components/TitleLink.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | const TitleLink = styled.a` 4 | color: #333; 5 | text-decoration: none; 6 | font-size: 1.25em; 7 | font-weight: 550; 8 | `; 9 | 10 | export default TitleLink; 11 | -------------------------------------------------------------------------------- /src/components/ToggleStarButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import {Mutation} from 'react-apollo'; 4 | import Button from './Button'; 5 | 6 | const ToggleStarButton = ({repo}) => 7 | repo.viewerHasStarred ? ( 8 | 13 | ) : ( 14 | 19 | ); 20 | 21 | const BaseToggleButton = ({mutation, repoId, title}) => ( 22 | 23 | {(triggerMutation, {loading}) => ( 24 | 27 | )} 28 | 29 | ); 30 | 31 | ToggleStarButton.fragment = gql` 32 | fragment ToggleStarButton on Repository { 33 | id 34 | viewerHasStarred 35 | stargazers { 36 | totalCount 37 | } 38 | } 39 | `; 40 | 41 | const STAR_MUTATION = gql` 42 | mutation StarRepo($repoId: ID!) { 43 | addStar(input: {starrableId: $repoId}) { 44 | starrable { 45 | ...ToggleStarButton 46 | } 47 | } 48 | } 49 | ${ToggleStarButton.fragment} 50 | `; 51 | 52 | const UNSTAR_MUTATION = gql` 53 | mutation UnstarRepo($repoId: ID!) { 54 | removeStar(input: {starrableId: $repoId}) { 55 | starrable { 56 | ...ToggleStarButton 57 | } 58 | } 59 | } 60 | ${ToggleStarButton.fragment} 61 | `; 62 | 63 | export default ToggleStarButton; 64 | -------------------------------------------------------------------------------- /src/components/UnstyledLink.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {Link} from 'react-router-dom'; 3 | 4 | const UnstyledLink = styled(Link)` 5 | color: black; 6 | text-decoration: none; 7 | `; 8 | 9 | export default UnstyledLink; 10 | -------------------------------------------------------------------------------- /src/components/UserHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import Avatar from './Avatar'; 4 | import {Column, PaddedRow} from './Flex'; 5 | import {Title, Subtitle} from './Headings'; 6 | 7 | const UserHeader = ({user}) => ( 8 | 9 | 10 | 11 | {user.login} 12 | {user.name || '(name not provided)'} 13 |

{user.bio}

14 |
15 |
16 | ); 17 | 18 | UserHeader.fragment = gql` 19 | fragment UserHeader on User { 20 | id 21 | name 22 | bio 23 | login 24 | avatarUrl 25 | } 26 | `; 27 | 28 | export default UserHeader; 29 | -------------------------------------------------------------------------------- /src/components/UserList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import Query from './DefaultQuery'; 4 | import UserTile from './UserTile'; 5 | import LoadMoreButton from './LoadMoreButton'; 6 | import Grid from './Grid'; 7 | 8 | const UserList = ({login}) => ( 9 | 10 | {({data: {search}, fetchMore, loading}) => ( 11 |
12 | 13 | {search.edges.map(({user}) => ( 14 | 15 | ))} 16 | 17 | 18 | {loading || ( 19 | 20 | )} 21 |
22 | )} 23 |
24 | ); 25 | 26 | const QUERY = gql` 27 | query UserSearch($login: String!, $cursor: String) { 28 | search(first: 12, query: $login, type: USER, after: $cursor) { 29 | edges { 30 | cursor 31 | user: node { 32 | ... on User { 33 | id 34 | login 35 | name 36 | avatarUrl 37 | } 38 | } 39 | } 40 | } 41 | } 42 | `; 43 | 44 | export default UserList; 45 | -------------------------------------------------------------------------------- /src/components/UserTile.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import Avatar from './Avatar'; 4 | import {Column, Row} from './Flex'; 5 | import {Title, Subtitle} from './Headings'; 6 | import UnstyledLink from './UnstyledLink'; 7 | import Tile from './Tile'; 8 | 9 | const UserTile = ({user}) => ( 10 | 11 | 12 | 13 | 18 | 19 | {user.login} 20 | {user.name && `(${user.name})`} 21 | 22 | 23 | 24 | 25 | ); 26 | 27 | UserTile.fragment = gql` 28 | fragment UserTile on User { 29 | id 30 | login 31 | name 32 | avatarUrl 33 | } 34 | `; 35 | 36 | export default UserTile; 37 | -------------------------------------------------------------------------------- /src/hocs/withLoading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const withLoading = WrappedComponent => { 4 | const WithLoading = props => 5 | props.data && props.data.loading ? ( 6 |
Loading...
7 | ) : ( 8 | 9 | ); 10 | 11 | setDisplayName(WithLoading, WrappedComponent); 12 | 13 | return WithLoading; 14 | }; 15 | 16 | const getDisplayName = WrappedComponent => 17 | WrappedComponent.displayName || WrappedComponent.name || 'Component'; 18 | 19 | const setDisplayName = (hoc, WrappedComponent) => { 20 | // eslint-disable-next-line no-param-reassign 21 | hoc.displayName = `${hoc.name}(${getDisplayName(WrappedComponent)})`; 22 | }; 23 | 24 | export default withLoading; 25 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GitHub GraphQL User Search Sample 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import ApolloClient from 'apollo-boost'; 4 | import {ApolloProvider} from 'react-apollo'; 5 | import {BrowserRouter, Route, Switch, Redirect} from 'react-router-dom'; 6 | import {SearchPage, UserPage} from './pages'; 7 | 8 | const client = new ApolloClient({ 9 | uri: 'https://api.github.com/graphql', 10 | request: async operation => { 11 | operation.setContext({ 12 | headers: { 13 | authorization: `Bearer ${process.env.GITHUB_TOKEN}`, 14 | }, 15 | }); 16 | }, 17 | }); 18 | 19 | const App = () => ( 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | 31 | ReactDOM.render(, document.getElementById('root')); 32 | 33 | // Hot Module Replacement 34 | if (module.hot) { 35 | module.hot.accept(); 36 | } 37 | -------------------------------------------------------------------------------- /src/pages/SearchPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import {MarkGithubIcon} from 'react-octicons'; 4 | import queryString from 'query-string'; 5 | import UserList from '../components/UserList'; 6 | import Page from '../components/Page'; 7 | 8 | class SearchPage extends React.Component { 9 | handleSubmit = event => { 10 | event.preventDefault(); 11 | const login = event.target.querySelector("[name='login']").value; 12 | if (login === '') { 13 | this.props.history.push('/users'); 14 | } else { 15 | this.props.history.push(`/users?login=${login}`); 16 | } 17 | }; 18 | 19 | render() { 20 | const login = 21 | queryString.parse(this.props.location.search).login || ''; 22 | 23 | return ( 24 | 25 |

26 | GitHub User Search 27 |

28 |
29 | 30 | 31 | 32 |
33 | ); 34 | } 35 | } 36 | 37 | const SearchBar = styled.input` 38 | font-size: 1.5em; 39 | width: 100%; 40 | `; 41 | 42 | export default SearchPage; 43 | -------------------------------------------------------------------------------- /src/pages/UserPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import DefaultQuery from '../components/DefaultQuery'; 4 | import Page from '../components/Page'; 5 | import Repo from '../components/Repo'; 6 | import Org from '../components/Org'; 7 | import UserHeader from '../components/UserHeader'; 8 | import {Row} from '../components/Flex'; 9 | import Grid from '../components/Grid'; 10 | 11 | const UserPage = ({match: {params: {login}}}) => ( 12 | 13 | {({data: {user}}) => ( 14 | 15 | 16 | 17 | {user.organizations.nodes.map(org => ( 18 | 19 | ))} 20 | 21 | 22 | {user.repositories.nodes.map(repo => ( 23 | 24 | ))} 25 | 26 | 27 | )} 28 | 29 | ); 30 | 31 | const QUERY = gql` 32 | query UserQuery($login: String!) { 33 | user(login: $login) { 34 | ...UserHeader 35 | 36 | organizations(first: 10) { 37 | nodes { 38 | ...Org 39 | } 40 | } 41 | 42 | repositories( 43 | first: 10 44 | isFork: false 45 | orderBy: {field: STARGAZERS, direction: DESC} 46 | ) { 47 | nodes { 48 | ...Repo 49 | } 50 | } 51 | } 52 | } 53 | 54 | ${UserHeader.fragment} 55 | ${Repo.fragment} 56 | ${Org.fragment} 57 | `; 58 | 59 | export default UserPage; 60 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | export {default as SearchPage} from './SearchPage'; 2 | export {default as UserPage} from './UserPage'; 3 | -------------------------------------------------------------------------------- /src/styles/index.js: -------------------------------------------------------------------------------- 1 | export {default as spacing} from './spacing'; 2 | -------------------------------------------------------------------------------- /src/styles/spacing.js: -------------------------------------------------------------------------------- 1 | export default { 2 | tiny: '0.25em', 3 | small: '0.5em', 4 | normal: '1em', 5 | large: '2em', 6 | }; 7 | --------------------------------------------------------------------------------