From a838859cb01ef5b08be37fef6078fd9bb023d0c2 Mon Sep 17 00:00:00 2001 From: urigo Date: Sat, 18 Mar 2017 20:12:23 +0100 Subject: [PATCH 01/16] docs(graphql-cookbook): Complete GraphQL cookbook --- .../docs/_examples/heroes-graphql/e2e-spec.ts | 283 ++++++++ .../_examples/heroes-graphql/ts/.gitignore | 10 + .../heroes-graphql/ts/aot/index.html | 19 + .../heroes-graphql/ts/aot/styles.css | 116 +++ .../heroes-graphql/ts/bs-config.aot.json | 14 + .../heroes-graphql/ts/copy-dist-files.js | 12 + .../heroes-graphql/ts/example-config.json | 0 .../_examples/heroes-graphql/ts/plnkr.json | 11 + .../heroes-graphql/ts/rollup-config.js | 53 ++ .../ts/src/app/app-routing.module.ts | 20 + .../ts/src/app/app.component.css | 29 + .../ts/src/app/app.component.ts | 19 + .../heroes-graphql/ts/src/app/app.module.ts | 53 ++ .../heroes-graphql/ts/src/app/client.1.ts | 8 + .../heroes-graphql/ts/src/app/client.2.ts | 13 + .../heroes-graphql/ts/src/app/client.ts | 12 + .../ts/src/app/dashboard.component.css | 62 ++ .../ts/src/app/dashboard.component.html | 12 + .../ts/src/app/dashboard.component.ts | 44 ++ .../ts/src/app/hero-detail.component.1.html | 17 + .../ts/src/app/hero-detail.component.1.ts | 62 ++ .../ts/src/app/hero-detail.component.css | 30 + .../ts/src/app/hero-detail.component.html | 14 + .../ts/src/app/hero-detail.component.ts | 81 +++ .../ts/src/app/hero-search.component.css | 21 + .../ts/src/app/hero-search.component.html | 11 + .../ts/src/app/hero-search.component.ts | 71 ++ .../heroes-graphql/ts/src/app/hero.ts | 4 + .../ts/src/app/heroes.component.1.html | 24 + .../ts/src/app/heroes.component.1.ts | 69 ++ .../ts/src/app/heroes.component.2.ts | 111 +++ .../ts/src/app/heroes.component.css | 68 ++ .../ts/src/app/heroes.component.html | 31 + .../ts/src/app/heroes.component.ts | 114 +++ .../ts/src/app/in-memory-graphql.ts | 139 ++++ .../heroes-graphql/ts/src/index.html | 27 + .../heroes-graphql/ts/src/main-aot.ts | 6 + .../_examples/heroes-graphql/ts/src/main.ts | 6 + .../ts/src/systemjs.config.extras.js | 68 ++ .../heroes-graphql/ts/tsconfig-aot.json | 26 + public/docs/_examples/package.json | 13 + .../toh-4/ts/src/app/app.component.ts | 2 + .../toh-4/ts/src/app/hero-detail.component.ts | 2 + .../docs/_examples/toh-4/ts/src/app/hero.ts | 1 + .../toh-6/ts/src/app/hero-detail.component.ts | 3 + public/docs/ts/latest/cookbook/_data.json | 5 + public/docs/ts/latest/cookbook/graphql.jade | 672 ++++++++++++++++++ .../heroes- graphql-mutation.gif | Bin 0 -> 234619 bytes 48 files changed, 2488 insertions(+) create mode 100755 public/docs/_examples/heroes-graphql/e2e-spec.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/.gitignore create mode 100755 public/docs/_examples/heroes-graphql/ts/aot/index.html create mode 100755 public/docs/_examples/heroes-graphql/ts/aot/styles.css create mode 100755 public/docs/_examples/heroes-graphql/ts/bs-config.aot.json create mode 100755 public/docs/_examples/heroes-graphql/ts/copy-dist-files.js create mode 100755 public/docs/_examples/heroes-graphql/ts/example-config.json create mode 100755 public/docs/_examples/heroes-graphql/ts/plnkr.json create mode 100755 public/docs/_examples/heroes-graphql/ts/rollup-config.js create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/app-routing.module.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/app.component.css create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/app.component.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/app.module.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/client.1.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/client.2.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/client.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.css create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.html create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.html create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.css create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.html create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.css create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.html create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/hero.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.1.html create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.1.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.2.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.css create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.html create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/app/in-memory-graphql.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/index.html create mode 100755 public/docs/_examples/heroes-graphql/ts/src/main-aot.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/main.ts create mode 100755 public/docs/_examples/heroes-graphql/ts/src/systemjs.config.extras.js create mode 100755 public/docs/_examples/heroes-graphql/ts/tsconfig-aot.json create mode 100644 public/docs/ts/latest/cookbook/graphql.jade create mode 100755 public/resources/images/cookbooks/heroes-graphql/heroes- graphql-mutation.gif diff --git a/public/docs/_examples/heroes-graphql/e2e-spec.ts b/public/docs/_examples/heroes-graphql/e2e-spec.ts new file mode 100755 index 0000000000..302f396db4 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/e2e-spec.ts @@ -0,0 +1,283 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder, ElementArrayFinder } from 'protractor'; +import { promise } from 'selenium-webdriver'; + +const expectedH1 = 'Tour of Heroes - GraphQL'; +const expectedTitle = `Angular ${expectedH1}`; +const targetHero = { id: 15, name: 'Magneta' }; +const targetHeroDashboardIndex = 3; +const nameSuffix = 'X'; +const newHeroName = targetHero.name + nameSuffix; + +class Hero { + id: number; + name: string; + + // Factory methods + + // Hero from string formatted as ' '. + static fromString(s: string): Hero { + return { + id: +s.substr(0, s.indexOf(' ')), + name: s.substr(s.indexOf(' ') + 1), + }; + } + + // Hero from hero list
  • element. + static async fromLi(li: ElementFinder): Promise { + let strings = await li.all(by.xpath('span')).getText(); + return { id: +strings[0], name: strings[1] }; + } + + // Hero id and name from the given detail element. + static async fromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
    + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + let _name = await detail.element(by.css('h2')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; + } +} + +describe('Heroes GraphQL', () => { + + beforeAll(() => browser.get('')); + + function getPageElts() { + let navElts = element.all(by.css('my-app nav a')); + + return { + navElts: navElts, + + myDashboardHref: navElts.get(0), + myDashboard: element(by.css('my-app my-dashboard')), + topHeroes: element.all(by.css('my-app my-dashboard > div h4')), + + myHeroesHref: navElts.get(1), + myHeroes: element(by.css('my-app my-heroes')), + allHeroes: element.all(by.css('my-app my-heroes li')), + selectedHero: element(by.css('my-app li.selected')), + selectedHeroSubview: element(by.css('my-app my-heroes > div:last-child')), + + heroDetail: element(by.css('my-app my-hero-detail > div')), + + searchBox: element(by.css('#search-box')), + searchResults: element.all(by.css('.search-result')) + }; + } + + describe('Initial page', () => { + + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h1 '${expectedH1}'`, () => { + expectHeading(1, expectedH1); + }); + + const expectedViewNames = ['Dashboard', 'Heroes']; + it(`has views ${expectedViewNames}`, () => { + let viewNames = getPageElts().navElts.map((el: ElementFinder) => el.getText()); + expect(viewNames).toEqual(expectedViewNames); + }); + + it('has dashboard as the active view', () => { + let page = getPageElts(); + expect(page.myDashboard.isPresent()).toBeTruthy(); + }); + + }); + + describe('Dashboard tests', () => { + + beforeAll(() => browser.get('')); + + it('has top heroes', () => { + let page = getPageElts(); + expect(page.topHeroes.count()).toEqual(4); + }); + + it(`selects and routes to ${targetHero.name} details`, dashboardSelectTargetHero); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`cancels and shows ${targetHero.name} in Dashboard`, () => { + element(by.buttonText('Back')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(targetHero.name); + }); + + it(`selects and routes to ${targetHero.name} details`, dashboardSelectTargetHero); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`saves and shows ${newHeroName} in Dashboard`, () => { + element(by.buttonText('Save')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(newHeroName); + }); + + }); + + describe('Heroes tests', () => { + + beforeAll(() => browser.get('')); + + it('can switch to Heroes view', () => { + getPageElts().myHeroesHref.click(); + let page = getPageElts(); + expect(page.myHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(10, 'number of heroes'); + }); + + it(`selects and shows ${targetHero.name} as selected in list`, () => { + getHeroLiEltById(targetHero.id).click(); + expect(Hero.fromLi(getPageElts().selectedHero)).toEqual(targetHero); + }); + + it('shows selected hero subview', () => { + let page = getPageElts(); + let title = page.selectedHeroSubview.element(by.css('h2')).getText(); + let expectedTitle = `${targetHero.name.toUpperCase()} is my hero`; + expect(title).toEqual(expectedTitle); + }); + + it('can route to hero details', () => { + element(by.buttonText('View Details')).click(); + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + let hero = Hero.fromDetail(page.heroDetail); + expect(hero).toEqual(targetHero); + }); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`shows ${newHeroName} in Heroes list`, () => { + element(by.buttonText('Save')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + let expectedHero = {id: targetHero.id, name: newHeroName}; + expect(Hero.fromLi(getHeroLiEltById(targetHero.id))).toEqual(expectedHero); + }); + + it(`deletes ${newHeroName} from Heroes list`, async () => { + const heroesBefore = await toHeroArray(getPageElts().allHeroes); + const li = getHeroLiEltById(targetHero.id); + li.element(by.buttonText('x')).click(); + + const page = getPageElts(); + expect(page.myHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(9, 'number of heroes'); + const heroesAfter = await toHeroArray(page.allHeroes); + const expectedHeroes = heroesBefore.filter(h => h.name !== newHeroName); + expect(heroesAfter).toEqual(expectedHeroes); + expect(page.selectedHeroSubview.isPresent()).toBeFalsy(); + }); + + it(`adds back ${targetHero.name}`, async () => { + const newHeroName = 'Alice'; + const heroesBefore = await toHeroArray(getPageElts().allHeroes); + const numHeroes = heroesBefore.length; + + element(by.css('input')).sendKeys(newHeroName); + element(by.buttonText('Add')).click(); + + let page = getPageElts(); + let heroesAfter = await toHeroArray(page.allHeroes); + expect(heroesAfter.length).toEqual(numHeroes + 1, 'number of heroes'); + + expect(heroesAfter.slice(0, numHeroes)).toEqual(heroesBefore, 'Old heroes are still there'); + + const maxId = heroesBefore[heroesBefore.length - 1].id; + expect(heroesAfter[numHeroes]).toEqual({id: maxId + 1, name: newHeroName}); + }); + }); + + describe('Progressive hero search', () => { + + beforeAll(() => browser.get('')); + + it(`searches for 'Ma'`, async () => { + getPageElts().searchBox.sendKeys('Ma'); + browser.sleep(1000); + expect(getPageElts().searchResults.count()).toBe(4); + }); + + it(`continues search with 'g'`, async () => { + getPageElts().searchBox.sendKeys('g'); + browser.sleep(1000); + expect(getPageElts().searchResults.count()).toBe(2); + }); + + it(`continues search with 'n' and gets ${targetHero.name}`, async () => { + getPageElts().searchBox.sendKeys('n'); + browser.sleep(1000); + let page = getPageElts(); + expect(page.searchResults.count()).toBe(1); + let hero = page.searchResults.get(0); + expect(hero.getText()).toEqual(targetHero.name); + }); + + it(`navigates to ${targetHero.name} details view`, async () => { + let hero = getPageElts().searchResults.get(0); + expect(hero.getText()).toEqual(targetHero.name); + hero.click(); + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + expect(Hero.fromDetail(page.heroDetail)).toEqual(targetHero); + }); + }); + + function dashboardSelectTargetHero() { + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(targetHero.name); + targetHeroElt.click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + let hero = Hero.fromDetail(page.heroDetail); + expect(hero).toEqual(targetHero); + } + + async function updateHeroNameInDetailView() { + // Assumes that the current view is the hero details view. + addToHeroName(nameSuffix); + + let hero = await Hero.fromDetail(getPageElts().heroDetail); + expect(hero).toEqual({id: targetHero.id, name: newHeroName}); + } + +}); + +function addToHeroName(text: string): promise.Promise { + let input = element(by.css('input')); + return input.sendKeys(text); +} + +function expectHeading(hLevel: number, expectedText: string): void { + let hTag = `h${hLevel}`; + let hText = element(by.css(hTag)).getText(); + expect(hText).toEqual(expectedText, hTag); +}; + +function getHeroLiEltById(id: number): ElementFinder { + let spanForId = element(by.cssContainingText('li span.badge', id.toString())); + return spanForId.element(by.xpath('..')); +} + +async function toHeroArray(allHeroes: ElementArrayFinder): Promise { + let promisedHeroes = await allHeroes.map(Hero.fromLi); + // The cast is necessary to get around issuing with the signature of Promise.all() + return > Promise.all(promisedHeroes); +} diff --git a/public/docs/_examples/heroes-graphql/ts/.gitignore b/public/docs/_examples/heroes-graphql/ts/.gitignore new file mode 100755 index 0000000000..c66c617d1f --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/.gitignore @@ -0,0 +1,10 @@ +aot/**/*.ts +**/*.ngfactory.ts +**/*.ngsummary.json +**/*.metadata.json +**/*.js +dist +!app/tsconfig.json +!rollup-config.js +!copy-dist-files.js +!systemjs.config.extras.js diff --git a/public/docs/_examples/heroes-graphql/ts/aot/index.html b/public/docs/_examples/heroes-graphql/ts/aot/index.html new file mode 100755 index 0000000000..6aea787999 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/aot/index.html @@ -0,0 +1,19 @@ + + + + + + Angular Tour of Heroes - GraphQL + + + + + + + + + + Loading... + + + \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql/ts/aot/styles.css b/public/docs/_examples/heroes-graphql/ts/aot/styles.css new file mode 100755 index 0000000000..d81835d0cd --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/aot/styles.css @@ -0,0 +1,116 @@ +/* #docregion , quickstart, toh */ +/* Master Styles */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} +h2, h3 { + color: #444; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +/* #enddocregion quickstart */ +body, input[text], button { + color: #888; + font-family: Cambria, Georgia; +} +/* #enddocregion toh */ +a { + cursor: pointer; + cursor: hand; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} + +/* Navigation link styles */ +nav a { + padding: 5px 10px; + text-decoration: none; + margin-right: 10px; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} + +/* items class */ +.items { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 24em; +} +.items li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.items li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.items li.selected { + background-color: #CFD8DC; + color: white; +} +.items li.selected:hover { + background-color: #BBD8DC; +} +.items .text { + position: relative; + top: -3px; +} +.items .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +/* #docregion toh */ +/* everywhere else */ +* { + font-family: Arial, Helvetica, sans-serif; +} diff --git a/public/docs/_examples/heroes-graphql/ts/bs-config.aot.json b/public/docs/_examples/heroes-graphql/ts/bs-config.aot.json new file mode 100755 index 0000000000..b219464d0e --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/bs-config.aot.json @@ -0,0 +1,14 @@ +{ + "open": false, + "logLevel": "silent", + "port": 8080, + "server": { + "baseDir": "aot", + "routes": { + "/node_modules": "node_modules" + }, + "middleware": { + "0": null + } + } +} \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql/ts/copy-dist-files.js b/public/docs/_examples/heroes-graphql/ts/copy-dist-files.js new file mode 100755 index 0000000000..a451cbd633 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/copy-dist-files.js @@ -0,0 +1,12 @@ +// #docregion +var fs = require('fs'); +var resources = [ + 'node_modules/core-js/client/shim.min.js', + 'node_modules/zone.js/dist/zone.min.js', + 'src/styles.css' +]; +resources.map(function(f) { + var path = f.split('/'); + var t = 'aot/' + path[path.length-1]; + fs.createReadStream(f).pipe(fs.createWriteStream(t)); +}); \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql/ts/example-config.json b/public/docs/_examples/heroes-graphql/ts/example-config.json new file mode 100755 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/heroes-graphql/ts/plnkr.json b/public/docs/_examples/heroes-graphql/ts/plnkr.json new file mode 100755 index 0000000000..fe0f72aa24 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/plnkr.json @@ -0,0 +1,11 @@ +{ + "description": "Tour of Heroes: GraphQL", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1,2].*", + "systemjs.config.extras.js" + ], + "tags": ["tutorial", "tour", "heroes", "http", "GraphQL"] +} \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql/ts/rollup-config.js b/public/docs/_examples/heroes-graphql/ts/rollup-config.js new file mode 100755 index 0000000000..f00fdcde1d --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/rollup-config.js @@ -0,0 +1,53 @@ +// #docregion +import rollup from 'rollup' +import nodeResolve from 'rollup-plugin-node-resolve' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' + +import builtins from 'rollup-plugin-node-builtins'; +import globals from 'rollup-plugin-node-globals'; +//paths are relative to the execution path +export default { + entry: 'src/main-aot.js', + dest: 'aot/dist/build.js', // output a single application bundle + sourceMap: true, + sourceMapFile: 'aot/dist/build.js.map', + format: 'iife', + onwarn: function(warning) { + // Skip certain warnings + + // should intercept ... but doesn't in some rollup versions + if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; } + // intercepts in some rollup versions + if ( warning.indexOf("The 'this' keyword is equivalent to 'undefined'") > -1 ) { return; } + + // console.warn everything else + console.warn( warning.message ); + }, + plugins: [ + nodeResolve({jsnext: true, module: true, browser: true}), + commonjs({ + include: [ + 'node_modules/rxjs/**', + 'node_modules/graphql-tag/**', + 'node_modules/apollo-client/**', + 'node_modules/lodash/**', + 'node_modules/graphql-tools/dist/**', + 'node_modules/graphql/**', + 'node_modules/graphql-anywhere/**', + 'node_modules/iterall/**', + 'node_modules/deprecated-decorator/**', + 'node_modules/uuid/**' + ], + namedExports: { + 'node_modules/graphql-tools/dist/index.js': ['makeExecutableSchema' ], + 'node_modules/graphql/index.js': ['execute' ], + 'node_modules/graphql-tag/printer.js': ['print'], + 'node_modules/lodash/lodash.js': ['find', 'omit', 'assign', 'isFunction'], + } + }), + globals(), + builtins(), + uglify() + ] +} \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/app-routing.module.ts b/public/docs/_examples/heroes-graphql/ts/src/app/app-routing.module.ts new file mode 100755 index 0000000000..dfd957782b --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/app-routing.module.ts @@ -0,0 +1,20 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, + { path: 'dashboard', component: DashboardComponent }, + { path: 'detail/:id', component: HeroDetailComponent }, + { path: 'heroes', component: HeroesComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/app.component.css b/public/docs/_examples/heroes-graphql/ts/src/app/app.component.css new file mode 100755 index 0000000000..071e665767 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/app.component.css @@ -0,0 +1,29 @@ +/* #docregion */ +h1 { + font-size: 1.2em; + color: #999; + margin-bottom: 0; +} +h2 { + font-size: 2em; + margin-top: 0; + padding-top: 0; +} +nav a { + padding: 5px 10px; + text-decoration: none; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/app.component.ts b/public/docs/_examples/heroes-graphql/ts/src/app/app.component.ts new file mode 100755 index 0000000000..18a45c6dad --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/app.component.ts @@ -0,0 +1,19 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    + + + `, + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'Tour of Heroes - GraphQL'; +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/app.module.ts b/public/docs/_examples/heroes-graphql/ts/src/app/app.module.ts new file mode 100755 index 0000000000..a783800749 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/app.module.ts @@ -0,0 +1,53 @@ +// #docplaster +// #docregion + +// #docregion v1, v2 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppRoutingModule } from './app-routing.module'; + +// #enddocregion v1 + +// #docregion import-apollo +import { ApolloModule } from 'apollo-angular'; +import { getClient } from './client'; +// #enddocregion import-apollo + +// #docregion v1 +import { AppComponent } from './app.component'; +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; +// #enddocregion v1, v2 +import { HeroSearchComponent } from './hero-search.component'; +// #docregion v1, v2 + +// #docregion apollo-ngmodule +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + // #enddocregion v1 + // #docregion v1 + AppRoutingModule, + ApolloModule.forRoot(getClient) + ], + // #docregion search + declarations: [ +// #enddocregion apollo-ngmodule + AppComponent, + DashboardComponent, + HeroDetailComponent, + HeroesComponent, + // #enddocregion v1, v2 + HeroSearchComponent + // #docregion v1, v2 + ], + // #enddocregion search + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/client.1.ts b/public/docs/_examples/heroes-graphql/ts/src/app/client.1.ts new file mode 100755 index 0000000000..388789b10a --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/client.1.ts @@ -0,0 +1,8 @@ +// #docregion , default-initialization +import ApolloClient from 'apollo-client'; + +const client = new ApolloClient(); +export function getClient(): ApolloClient { + return client; +} +// #enddocregion default-initialization diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/client.2.ts b/public/docs/_examples/heroes-graphql/ts/src/app/client.2.ts new file mode 100755 index 0000000000..7c0c442e3f --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/client.2.ts @@ -0,0 +1,13 @@ +// #docregion , network-initialization +import ApolloClient, { createNetworkInterface } from 'apollo-client'; + +const client = new ApolloClient({ + networkInterface: createNetworkInterface({ + uri: 'http://my-api.graphql.com' + }) +}); + +export function getClient(): ApolloClient { + return client; +} +// #enddocregion network-initialization diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/client.ts b/public/docs/_examples/heroes-graphql/ts/src/app/client.ts new file mode 100755 index 0000000000..555a090f9b --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/client.ts @@ -0,0 +1,12 @@ +// #docregion +import { ApolloClient } from 'apollo-client'; +import { networkInterface } from './in-memory-graphql'; + +const client = new ApolloClient({ + networkInterface, + dataIdFromObject: (object: any) => object.id, +}); +export function getClient(): ApolloClient { + return client; +} +// #enddocregion diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.css b/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.css new file mode 100755 index 0000000000..dc7fb7ce06 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.css @@ -0,0 +1,62 @@ +/* #docregion */ +[class*='col-'] { + float: left; + padding-right: 20px; + padding-bottom: 20px; +} +[class*='col-']:last-of-type { + padding-right: 0; +} +a { + text-decoration: none; +} +*, *:after, *:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +h3 { + text-align: center; margin-bottom: 0; +} +h4 { + position: relative; +} +.grid { + margin: 0; +} +.col-1-4 { + width: 25%; +} +.module { + padding: 20px; + text-align: center; + color: #eee; + max-height: 120px; + min-width: 120px; + background-color: #607D8B; + border-radius: 2px; +} +.module:hover { + background-color: #EEE; + cursor: pointer; + color: #607d8b; +} +.grid-pad { + padding: 10px 0; +} +.grid-pad > [class*='col-']:last-of-type { + padding-right: 20px; +} +@media (max-width: 600px) { + .module { + font-size: 10px; + max-height: 75px; } +} +@media (max-width: 1024px) { + .grid { + margin: 0; + } + .module { + min-width: 60px; + } +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.html b/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.html new file mode 100755 index 0000000000..04962576c1 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.html @@ -0,0 +1,12 @@ + +

    Top Heroes

    + + diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.ts b/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.ts new file mode 100755 index 0000000000..6732904c29 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/dashboard.component.ts @@ -0,0 +1,44 @@ +// #docregion , search +import { Component, OnInit } from '@angular/core'; + +// #docregion import-apollo +import { Apollo } from 'apollo-angular'; +// #enddocregion import-apollo +// #docregion import-graphql-tag +import gql from 'graphql-tag'; +// #enddocregion import-graphql-tag +import { ApolloQueryResult } from 'apollo-client'; +import { Hero } from './hero'; + +@Component({ + selector: 'my-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: [ './dashboard.component.css' ] +}) +// #enddocregion search +export class DashboardComponent implements OnInit { + // #docregion this-heroes + heroes: Hero[]; + // #enddocregion this-heroes + // #docregion inject-apollo + constructor(private apollo: Apollo) { } + // #enddocregion inject-apollo + + // #docregion query-heroes + ngOnInit(): void { + this.apollo.watchQuery({ + query: gql` + query allHeroes { + heroes { + id + name + } + } + ` + }).subscribe((queryResult: ApolloQueryResult<{ heroes: Hero[] }>) => { + this.heroes = queryResult.data.heroes.slice(1, 5); + }); + } + // #enddocregion query-heroes +} +// #enddocregion diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.html b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.html new file mode 100755 index 0000000000..7c08aaf22d --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.html @@ -0,0 +1,17 @@ + +
    +

    {{hero.name}} details!

    +
    + {{hero.id}}
    +
    + + + + + +
    + + + + +
    diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.ts b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.ts new file mode 100755 index 0000000000..e8445ee1cf --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.ts @@ -0,0 +1,62 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Location } from '@angular/common'; + +import { Apollo, ApolloQueryObservable } from 'apollo-angular'; +import { Subscription } from 'rxjs/Subscription'; +import gql from 'graphql-tag'; + +import { Hero } from './hero'; + +@Component({ + selector: 'my-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: [ './hero-detail.component.css' ] +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + private heroSubscription: Subscription; + private heroObservable: ApolloQueryObservable; + + constructor( + private route: ActivatedRoute, + private location: Location, + private apollo: Apollo + ) {} + + ngOnInit(): void { + this.route.params.subscribe(params => { + const heroId = params['id']; + + // #docregion graphql-query-new-field + this.heroObservable = this.apollo.watchQuery({ + query: gql` + query Hero($heroId: Int!) { + hero(heroId: $heroId) { + id + name + age + } + } + `, + variables: { heroId: heroId } + }); + // #enddocregion graphql-query-new-field + + this.heroSubscription = this.heroObservable.subscribe(({data}) => { + this.hero = Object.assign({}, data.hero); + }); + }); + } + + // #docregion save + save(): void { + } + // #enddocregion save + + goBack(): void { + this.location.back(); + } +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.css b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.css new file mode 100755 index 0000000000..ab2437efd8 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.css @@ -0,0 +1,30 @@ +/* #docregion */ +label { + display: inline-block; + width: 3em; + margin: .5em 0; + color: #607D8B; + font-weight: bold; +} +input { + height: 2em; + font-size: 1em; + padding-left: .4em; +} +button { + margin-top: 20px; + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #ccc; + cursor: auto; +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.html b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.html new file mode 100755 index 0000000000..32fe6d4391 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.html @@ -0,0 +1,14 @@ + +
    +

    {{hero.name}} details!

    +
    + {{hero.id}}
    +
    + + +
    + + + + +
    diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.ts b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.ts new file mode 100755 index 0000000000..1eb4487c8f --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.ts @@ -0,0 +1,81 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Location } from '@angular/common'; + +import { Apollo, ApolloQueryObservable } from 'apollo-angular'; +import { Subscription } from 'rxjs/Subscription'; +import gql from 'graphql-tag'; + +import { Hero } from './hero'; +import { ApolloQueryResult } from 'apollo-client'; + +@Component({ + selector: 'my-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: [ './hero-detail.component.css' ] +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + private heroSubscription: Subscription; + private heroObservable: ApolloQueryObservable; + + constructor( + private route: ActivatedRoute, + private location: Location, + private apollo: Apollo + ) {} + + // #docregion service-fetch-by-id + ngOnInit(): void { + this.route.params.subscribe(params => { + const heroId = params['id']; + + // #docregion graphql-query + this.heroObservable = this.apollo.watchQuery({ + query: gql` + query Hero($heroId: Int!) { + hero(heroId: $heroId) { + id + name + } + } + `, + variables: { heroId: heroId } + }); + + this.heroSubscription = this.heroObservable.subscribe(({data}) => { + this.hero = Object.assign({}, data.hero); + }); + // #enddocregion graphql-query + }); + } + // #enddocregion service-fetch-by-id + + // #docregion save + save(): void { + + this.apollo.mutate({ + mutation: gql` + mutation updateHero($id: Int!, $name: String!) { + updateHero(id: $id, name: $name) { + id + name + } + } + `, + variables: { + id: this.hero.id, + name: this.hero.name + } + }).subscribe((mutationResult: ApolloQueryResult<{ updateHero: Hero }>) => { + this.goBack(); + }); + } + // #enddocregion save + + goBack(): void { + this.location.back(); + } +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.css b/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.css new file mode 100755 index 0000000000..9bf8d13457 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.css @@ -0,0 +1,21 @@ +/* #docregion */ +.search-result{ + border-bottom: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + width:195px; + height: 16px; + padding: 5px; + background-color: white; + cursor: pointer; +} + +.search-result:hover { + color: #eee; + background-color: #607D8B; +} + +#search-box{ + width: 200px; + height: 20px; +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.html b/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.html new file mode 100755 index 0000000000..c6cd10894c --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.html @@ -0,0 +1,11 @@ + +
    +

    Hero Search

    + +
    +
    + {{hero.name}} +
    +
    +
    diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.ts b/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.ts new file mode 100755 index 0000000000..b02face7ff --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-search.component.ts @@ -0,0 +1,71 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +// #docregion rxjs-imports +import { Subject } from 'rxjs/Subject'; + +// Observable class extensions +import 'rxjs/add/observable/of'; + +// Observable operators +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/distinctUntilChanged'; +// #enddocregion rxjs-imports + +import { Hero } from './hero'; + +import { Apollo, ApolloQueryObservable } from 'apollo-angular'; +import gql from 'graphql-tag'; + +@Component({ + selector: 'hero-search', + templateUrl: './hero-search.component.html', + styleUrls: [ './hero-search.component.css' ] +}) +export class HeroSearchComponent implements OnInit { + // #docregion search + heroes: ApolloQueryObservable; + // #enddocregion search + // #docregion searchTerms + private searchTerms = new Subject(); + // #enddocregion searchTerms + + constructor( + private apollo: Apollo, + private router: Router) {} + // #docregion searchTerms + + // Push a search term into the observable stream. + search(term: string): void { + this.searchTerms.next(term); + } + // #enddocregion searchTerms + // #docregion search + + ngOnInit(): void { + + this.heroes = this.apollo.watchQuery({ + query: gql` + query searchHeroes ($search: String) { + heroes (search: $search) { + id + name + } + }`, + variables: { + search: this.searchTerms + .debounceTime(300) // wait 300ms after each keystroke before considering the term + .distinctUntilChanged() // ignore if next search term is same as previous + } + }); + } + // #enddocregion search + + gotoDetail(hero: Hero): void { + let link = ['/detail', hero.id]; + this.router.navigate(link); + } +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero.ts b/public/docs/_examples/heroes-graphql/ts/src/app/hero.ts new file mode 100755 index 0000000000..e3eac516da --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.1.html b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.1.html new file mode 100755 index 0000000000..4fbf37a8bc --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.1.html @@ -0,0 +1,24 @@ + +

    My Heroes

    + +
    + + +
    + + +
      +
    • + {{hero.id}} + {{hero.name}} +
    • +
    + +
    +

    + {{selectedHero.name | uppercase}} is my hero +

    + +
    diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.1.ts b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.1.ts new file mode 100755 index 0000000000..e4e278b257 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.1.ts @@ -0,0 +1,69 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +// #docregion import-apollo +import { Apollo } from 'apollo-angular'; +// #enddocregion import-apollo +// #docregion import-graphql-tag +import gql from 'graphql-tag'; +// #enddocregion import-graphql-tag +import { ApolloQueryResult } from 'apollo-client'; +import { Hero } from './hero'; + +@Component({ + selector: 'my-heroes', + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] +}) +export class HeroesComponent implements OnInit { + // #docregion this-heroes + heroes: Hero[]; + selectedHero: Hero; + // #enddocregion this-heroes + +// #docregion inject-apollo + constructor( + private apollo: Apollo, + private router: Router) { } + // #enddocregion inject-apollo + + // #docregion query-heroes + getHeroes(): void { + this.apollo.watchQuery({ + query: gql` + query allHeroes { + heroes { + id + name + } + } + `, + }).subscribe((queryResult: ApolloQueryResult<{ heroes: Hero[] }>) => { + this.heroes = queryResult.data.heroes; + }); + } + // #enddocregion query-heroes + + // #docregion add + add(name: string): void { + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + } + // #enddocregion delete + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.2.ts b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.2.ts new file mode 100755 index 0000000000..a45a24f6e2 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.2.ts @@ -0,0 +1,111 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +// #docregion import-apollo +import { Apollo } from 'apollo-angular'; +// #enddocregion import-apollo +// #docregion import-graphql-tag +import gql from 'graphql-tag'; +// #enddocregion import-graphql-tag +import { ApolloQueryResult } from 'apollo-client'; +import { Hero } from './hero'; + +@Component({ + selector: 'my-heroes', + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] +}) +export class HeroesComponent implements OnInit { + // #docregion this-heroes + heroes: Hero[]; + selectedHero: Hero; + // #enddocregion this-heroes + +// #docregion inject-apollo + constructor( + private apollo: Apollo, + private router: Router) { } + // #enddocregion inject-apollo + + // #docregion query-heroes + getHeroes(): void { + this.apollo.watchQuery({ + query: gql` + query allHeroes { + heroes { + id + name + } + } + ` + }).subscribe((queryResult: ApolloQueryResult<{ heroes: Hero[] }>) => { + this.heroes = queryResult.data.heroes; + }); + // #enddocregion query-heroes + } + + // #docregion add + add(name: string): void { + name = name.trim(); + if (!name) { return; } + + // #docregion add-mutation + this.apollo.mutate({ + mutation: gql` + mutation addHero($heroName: String!) { + addHero(heroName: $heroName) { + id + name + } + } + `, + variables: { + heroName: name + } + }).subscribe((mutationResult: ApolloQueryResult<{ addHero: Hero }>) => { + this.heroes.push({ + // #docregion access-mutation-result + id: mutationResult.data.addHero.id, + name: mutationResult.data.addHero.name + // #enddocregion access-mutation-result + }); + }); + // #enddocregion add-mutation + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + + this.apollo.mutate({ + mutation: gql` + mutation deleteHero($id: Int!) { + deleteHero(id: $id) { + id + name + } + } + `, + variables: { + id: hero.id + } + }).subscribe((mutationResult: ApolloQueryResult<{ deleteHero: Hero }>) => { + this.heroes = this.heroes.filter(h => h !== hero); + if (this.selectedHero === hero) { this.selectedHero = null; } + }); + } + // #enddocregion delete + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.css b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.css new file mode 100755 index 0000000000..d2c958a911 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.css @@ -0,0 +1,68 @@ +/* #docregion */ +.selected { + background-color: #CFD8DC !important; + color: white; +} +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} +.heroes .text { + position: relative; + top: -3px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +/* #docregion additions */ +button.delete { + float:right; + margin-top: 2px; + margin-right: .8em; + background-color: gray !important; + color:white; +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.html b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.html new file mode 100755 index 0000000000..19e155241b --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.html @@ -0,0 +1,31 @@ + +

    My Heroes

    + +
    + + +
    + +
      + + +
    • + {{hero.id}} + {{hero.name}} + + + +
    • + + +
    +
    +

    + {{selectedHero.name | uppercase}} is my hero +

    + +
    diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.ts b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.ts new file mode 100755 index 0000000000..7dcadd5d64 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.ts @@ -0,0 +1,114 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +// #docregion import-apollo +import { Apollo } from 'apollo-angular'; +// #enddocregion import-apollo +// #docregion import-graphql-tag +import gql from 'graphql-tag'; +// #enddocregion import-graphql-tag +// #docregion import-apollo-query-result +import { ApolloQueryResult } from 'apollo-client'; +// #enddocregion import-apollo-query-result +import { Hero } from './hero'; + +@Component({ + selector: 'my-heroes', + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] +}) +export class HeroesComponent implements OnInit { + // #docregion this-heroes + heroes: Hero[]; + selectedHero: Hero; + // #enddocregion this-heroes + +// #docregion inject-apollo + constructor( + private apollo: Apollo, + private router: Router) { } + // #enddocregion inject-apollo + + // #docregion query-heroes + getHeroes(): void { + this.apollo.watchQuery({ + query: gql` + query allHeroes { + heroes { + id + name + } + } + ` + }).subscribe((queryResult: ApolloQueryResult<{ heroes: Hero[] }>) => { + this.heroes = queryResult.data.heroes; + }); + } + // #enddocregion query-heroes + + // #docregion add + add(name: string): void { + name = name.trim(); + if (!name) { return; } + + // #docregion add-mutation + this.apollo.mutate({ + mutation: gql` + mutation addHero($heroName: String!) { + addHero(heroName: $heroName) { + id + name + } + } + `, + variables: { + heroName: name + } + }).subscribe((mutationResult: ApolloQueryResult<{ addHero: Hero }>) => { + // #docregion access-mutation-result + this.heroes.push({ + id: mutationResult.data.addHero.id, + name: mutationResult.data.addHero.name + }); + // #enddocregion access-mutation-result + this.selectedHero = null; + }); + // #enddocregion add-mutation + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + + this.apollo.mutate({ + mutation: gql` + mutation deleteHero($id: Int!) { + deleteHero(id: $id) { + id + name + } + } + `, + variables: { + id: hero.id + } + }).subscribe((mutationResult: ApolloQueryResult<{ deleteHero: Hero }>) => { + this.heroes = this.heroes.filter(h => h !== hero); + if (this.selectedHero === hero) { this.selectedHero = null; } + }); + } + // #enddocregion delete + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } +} diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-graphql.ts b/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-graphql.ts new file mode 100755 index 0000000000..8d2fcd597c --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-graphql.ts @@ -0,0 +1,139 @@ +// #docregion +// #docregion import-lodash +import { find as lodashFind } from 'lodash'; +// #enddocregion import-lodash +// #docregion import-graphql-tools +import { makeExecutableSchema } from 'graphql-tools'; +// #enddocregion import-graphql-tools +// #docregion import-graphql +import { execute } from 'graphql'; +// #enddocregion import-graphql +// #docregion graphql-schema +const typeDefinitions = ` +# the model +type Hero { + id: Int! + name: String! +} + +# The schema allows the following queries: +type Query { + heroes(search: String): [Hero] + + hero(heroId: Int!): Hero +} + +# This schema allows the following mutation: +type Mutation { + updateHero ( + id: Int! + name: String! + ): Hero + + addHero ( + heroName: String! + ): Hero + + deleteHero ( + id: Int! + ): Hero +} + +# Tell the server which types represent the root query and root mutation types. +# By convention, they are called RootQuery and RootMutation. +schema { + query: Query + mutation: Mutation +} +`; +// #enddocregion graphql-schema +// #docregion heroes-array +let heroes = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} +]; +// #enddocregion heroes-array + +// #docregion resolvers +const resolveFunctions = { + Query: { + heroes(obj: any, args: any) { + if (args.search) { + return heroes.filter(function (currentHero){ + return currentHero.name.toLowerCase().search(args.search.toLowerCase()) !== -1; + }); + } else { + return heroes; + } + }, + hero(obj: any, args: any, context: any) { + return lodashFind(heroes, { id: args.heroId }); + } + }, + Mutation: { + updateHero(root: any, args: any) { + let hero = lodashFind(heroes, { id: args.id }); + if (!hero) { + throw new Error(`Couldn't find post with id ${args.id}`); + } + hero.name = args.name; + return hero; + }, + addHero(root: any, args: any) { + const maxId = Math.max(...heroes.map((hero) => {return hero.id; })); + const newHero = { + name: args.heroName, + id: maxId + 1 + }; + heroes.push(newHero); + return newHero; + }, + deleteHero(root: any, args: any) { + let hero = lodashFind(heroes, { id: args.id }); + if (!hero) { + throw new Error(`Couldn't find post with id ${args.id}`); + } + heroes = heroes.filter(function (currentHero) { return currentHero.id !== args.id; }); + return hero; + }, + } +}; +// #enddocregion resolvers +// #docregion make-executable-schema +const schema = makeExecutableSchema({ + typeDefs: typeDefinitions, + resolvers: resolveFunctions, +}); +// #enddocregion make-executable-schema +// #docregion execute-and-export +class InBrowserNetworkInterface { + schema: any = {}; + constructor(params: any) { + this.schema = params.schema; + } + + query(request: any) { + return execute( + this.schema, + request.query, + {}, + {}, + request.variables, + request.operationName); + } +} + +const networkInterface = new InBrowserNetworkInterface({ schema }); +export { + networkInterface +} +// #enddocregion execute-and-export +// #enddocregion diff --git a/public/docs/_examples/heroes-graphql/ts/src/index.html b/public/docs/_examples/heroes-graphql/ts/src/index.html new file mode 100755 index 0000000000..29cfb3785e --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/index.html @@ -0,0 +1,27 @@ + + + + + + Angular Tour of Heroes - GraphQL + + + + + + + + + + + + + + + + + Loading... + + \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql/ts/src/main-aot.ts b/public/docs/_examples/heroes-graphql/ts/src/main-aot.ts new file mode 100755 index 0000000000..bd2ca604a3 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/main-aot.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowser } from '@angular/platform-browser'; + +import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); diff --git a/public/docs/_examples/heroes-graphql/ts/src/main.ts b/public/docs/_examples/heroes-graphql/ts/src/main.ts new file mode 100755 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/heroes-graphql/ts/src/systemjs.config.extras.js b/public/docs/_examples/heroes-graphql/ts/src/systemjs.config.extras.js new file mode 100755 index 0000000000..c59e015378 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/systemjs.config.extras.js @@ -0,0 +1,68 @@ + +/** App specific SystemJS configuration */ +System.config({ + + map: { + + // #docregion systemjs-apollo-client-map + 'apollo-client': 'npm:apollo-client/apollo.umd.js', + 'apollo-client-rxjs': 'npm:apollo-client-rxjs/build/bundles/apollo-rxjs.umd.js', + 'apollo-angular': 'npm:apollo-angular/build/bundles/apollo.umd.js', + + 'whatwg-fetch': 'npm:whatwg-fetch', + + 'graphql-anywhere': 'npm:graphql-anywhere', + + 'graphql-tag': 'npm:graphql-tag', + 'symbol-observable': 'npm:symbol-observable', + 'redux': 'npm:redux/dist/redux.min.js', + // #enddocregion systemjs-apollo-client-map + + // #docregion systemjs-graphql-server-map + 'graphql': 'npm:graphql', + 'graphql-tools': 'npm:graphql-tools', + 'deprecated-decorator': 'npm:deprecated-decorator', + 'node-uuid': 'npm:node-uuid', + 'uuid': 'npm:uuid', + 'iterall': 'npm:iterall', + 'lodash': 'npm:lodash' + // #enddocregion systemjs-graphql-server-map + }, + packages: { + + // #docregion systemjs-apollo-client-packages + 'whatwg-fetch': { main: './fetch.js', defaultExtension: 'js' }, + 'redux': { format: 'cjs', defaultExtension: 'js' }, + 'graphql-tag': { main: './index.js', defaultExtension: 'js' }, + 'symbol-observable': { main: './index.js', defaultExtension: 'js' }, + 'graphql-anywhere': { + main: '/lib/src/index.js', + defaultExtension: 'js' + }, + // #enddocregion systemjs-apollo-client-packages + + // #docregion systemjs-graphql-server-packages + 'graphql': { + main: './index.js', + defaultExtension: 'js', + map: { + './type': './type/index.js', + './language': './language/index.js', + './execution': './execution/index.js', + './validation': './validation/index.js', + './error': './error/index.js', + './utilities': './utilities/index.js' + }, + }, + 'graphql-tools': { + main: '/dist/index.js', + defaultExtension: 'js' + }, + 'deprecated-decorator': { main: '/bld/index.js', defaultExtension: 'js' }, + 'node-uuid': { main: './uuid.js', defaultExtension: 'js' }, + 'uuid': { main: './lib/rng-browser.js', defaultExtension: 'js' }, + 'iterall': { main: './index.js', defaultExtension: 'js' }, + 'lodash': { main: './index.js', defaultExtension: 'js' } + // #enddocregion systemjs-graphql-server-packages + } +}); diff --git a/public/docs/_examples/heroes-graphql/ts/tsconfig-aot.json b/public/docs/_examples/heroes-graphql/ts/tsconfig-aot.json new file mode 100755 index 0000000000..646b63f6d2 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/tsconfig-aot.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + + "files": [ + "src/app/app.module.ts", + "src/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "skipMetadataEmit" : true + } +} \ No newline at end of file diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index 41dc5e5b56..02a323dbaa 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -26,7 +26,14 @@ "@angular/tsc-wrapped": "~4.0.0", "@angular/upgrade": "~4.0.0", "angular-in-memory-web-api": "~0.3.1", + "apollo-angular": "^0.12.0", + "apollo-client": "0.10.0", "core-js": "^2.4.1", + "graphql": "^0.9.1", + "graphql-subscriptions": "^0.3.1", + "graphql-tag": "^1.3.1", + "graphql-tools": "^0.10.1", + "lodash": "^4.17.4", "rxjs": "5.0.1", "systemjs": "0.19.39", "zone.js": "^0.8.4" @@ -40,7 +47,11 @@ "@types/angular-resource": "^1.5.6", "@types/angular-route": "^1.3.2", "@types/angular-sanitize": "^1.3.3", + "@types/chai": "^3.4.35", + "@types/graphql": "^0.8.6", + "@types/isomorphic-fetch": "0.0.33", "@types/jasmine": "2.5.36", + "@types/lodash": "4.14.50", "@types/node": "^6.0.45", "angular2-template-loader": "^0.6.0", "awesome-typescript-loader": "^3.0.4", @@ -74,6 +85,8 @@ "rimraf": "^2.5.4", "rollup": "^0.41.6", "rollup-plugin-commonjs": "^8.0.2", + "rollup-plugin-node-builtins": "^2.1.0", + "rollup-plugin-node-globals": "^1.1.0", "rollup-plugin-node-resolve": "2.0.0", "rollup-plugin-uglify": "^1.0.1", "source-map-explorer": "^1.3.2", diff --git a/public/docs/_examples/toh-4/ts/src/app/app.component.ts b/public/docs/_examples/toh-4/ts/src/app/app.component.ts index 0d57acb5b0..e22b81ae70 100644 --- a/public/docs/_examples/toh-4/ts/src/app/app.component.ts +++ b/public/docs/_examples/toh-4/ts/src/app/app.component.ts @@ -20,7 +20,9 @@ import { HeroService } from './hero.service'; {{hero.id}} {{hero.name}}
  • + // #docregion calling-component + // #enddocregion calling-component `, // #enddocregion template styles: [` diff --git a/public/docs/_examples/toh-4/ts/src/app/hero-detail.component.ts b/public/docs/_examples/toh-4/ts/src/app/hero-detail.component.ts index 865fb98da7..487c7f3592 100644 --- a/public/docs/_examples/toh-4/ts/src/app/hero-detail.component.ts +++ b/public/docs/_examples/toh-4/ts/src/app/hero-detail.component.ts @@ -18,5 +18,7 @@ import { Hero } from './hero'; ` }) export class HeroDetailComponent { + // #docregion declaring-conponent-input @Input() hero: Hero; + // #enddocregion declaring-conponent-input } diff --git a/public/docs/_examples/toh-4/ts/src/app/hero.ts b/public/docs/_examples/toh-4/ts/src/app/hero.ts index e3eac516da..8f7cc205c8 100644 --- a/public/docs/_examples/toh-4/ts/src/app/hero.ts +++ b/public/docs/_examples/toh-4/ts/src/app/hero.ts @@ -1,3 +1,4 @@ +// #docregion export class Hero { id: number; name: string; diff --git a/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.ts b/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.ts index 6224f10ac1..697a28c753 100644 --- a/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.ts +++ b/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.ts @@ -21,11 +21,14 @@ export class HeroDetailComponent implements OnInit { private location: Location ) {} + // #docregion service-fetch-by-id ngOnInit(): void { this.route.params .switchMap((params: Params) => this.heroService.getHero(+params['id'])) .subscribe(hero => this.hero = hero); } + // #enddocregion service-fetch-by-id + // #docregion save save(): void { diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json index 1aed135fa8..86dc4f1faf 100644 --- a/public/docs/ts/latest/cookbook/_data.json +++ b/public/docs/ts/latest/cookbook/_data.json @@ -41,6 +41,11 @@ "intro": "Validate user's form entries." }, + "graphql": { + "title": "GraphQL", + "intro": "Use GraphQL to talk to a remote server" + }, + "i18n": { "title": "Internationalization (i18n)", "intro": "Translate the app's template text into multiple languages." diff --git a/public/docs/ts/latest/cookbook/graphql.jade b/public/docs/ts/latest/cookbook/graphql.jade new file mode 100644 index 0000000000..b9aed7d337 --- /dev/null +++ b/public/docs/ts/latest/cookbook/graphql.jade @@ -0,0 +1,672 @@ +include ../_util-fns + + +:marked + GraphQL is a network protocol, a query language for your API, and a runtime for fulfilling those queries with your existing data. + +.l-sub-section + :marked + GraphQL is a replacement or enhancement for REST and can be used in conjunction with it. + +:marked + GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools. + + + +:marked + ## Contents + + - [What is GraphQL?](#what-is-graphql) + + - [The benefits of GraphQL with Angular](#benefits-of-graphql) + + - [How to use GraphQL in an Angular app with app demo:](#how-to) + - [Installation](#installation) + + - [Performing a query](#querying) + + - [Performing a mutation](#mutation) + + - [Appendix: Setting up a GraphQL server](#server) + + - [Further resources](#resources) + + - [Full Example](#example) + +:marked + **See the **. + +.l-main-section + +:marked + ## What is GraphQL? + + GraphQL is an API query language, helping your Angular app: + + - Fetch exactly the information it needs from the server. + - Add type safety to your API. + - Merge multiple dependencies into one single response from the server. + - Handle server data dependency in a component structure. + + It’s also important to understand that: + + - **GraphQL is not a data source**. The GraphQL runtime works on top of any data source—SQL, + NoSql, REST, Queues, .NET servers, Java servers or any other technology or data source. + - GraphQL solves the need of sending multiple requests for multiple resources to the server and + then running complex joins on the client—without the need to create a custom endpoint like REST does. + - The GraphQL specification also includes protocols for real-time push updates from the server to the client. + + See the official [GraphQL](http://graphql.org/) site for a more in-depth look. + +.l-main-section + +:marked + ## The benefits of GraphQL with Angular + +.l-sub-section + :marked + For a summary of this section, see [Faster modern apps with Angular and GraphQL](https://www.youtube.com/watch?v=Xx39bv-5ojA&t=1s) + presented by [Jeff Cross](https://twitter.com/jeffbcross) and [Uri Goldshtein](https://twitter.com/UriGoldshtein). + +iframe(type='text/html' width='560' height='315' + src='https://www.youtube.com/embed/Xx39bv-5ojA' + frameborder='0') + +:marked + ### Component based API + + Angular components are composable, reusable, and allow encapsulation of behaviour + and state. So how does one keep these benefits when fetching data from the server? + Without GraphQL, there are three possible solutions: + + 1. Using the HTTP service inside components. + 2. Calling a service from a component. + 3. Fetching data at the parent component and passing it down the component tree. + + While these solutions are valid, they have their limitations. + + #### Using the HTTP service in the Component + + There are two potential issues with this approach: + + 1. Multiple redundant requests; when you render multiple components, + for example, through `ngFor` with many components, each sends its own + HTTP call. + 2. Inconsistent data; if two components fetch the same data but in different requests, + the data might change and not be consistent across the app. + +a#http-heroes +:marked + #### Using a service + + Consider the following service and component: + ++makeExample('toh-6/ts/src/app/hero.service.ts', 'getHero','hero.service.ts (Fetch by Id)') ++makeExample('toh-6/ts/src/app/hero-detail.component.ts', 'service-fetch-by-id','hero-detail.component.ts (Fetch by Id)') + +:marked + There are two potential issues here. + + 1. A dependency between the service and all of the components that use it + make the component no longer reusable. If you change something in the service, + it might break other components that use that service. + 2. There is a main, complex point to handle batching, caching, and join logic. + Because the logic is shared between components, the potential of things breaking increases. + +:marked + #### Fetching data at the parent component and passing it down the component tree + + Consider an example of the second possibility: + ++makeExample('toh-4/ts/src/app/hero.ts','','Declare the API type') ++makeExample('toh-4/ts/src/app/hero-detail.component.ts','declaring-conponent-input','Declare the input') ++makeExample('toh-4/ts/src/app/app.component.ts','calling-component','Using from parent') + +:marked + This works until you change the API of the component, which means you need to change + its parent components _all the way to the top_. + Again, this creates a dependency. This time it is with the child component + all the way up to the fetching component + and _all the components in between_. + + #### Solution - Component based API + + +:marked + Here, the data dependency is inside the component. The query reflects just + what the single component needs and is included as part of the + component or a wrapper component. That means that when the + data dependency changes, the component is the only thing + impacted. You don't have to touch any services or parent components. + +:marked + Now, a single component contains all of its own data dependency changes. + +:marked + The `watchQuery` function tells the Apollo Client what data + this component needs. The Apollo Client then returns the + necessary data to the component as an Observable. + For example, adding an `age` field to the app is + simple because you only change the component (you cover + this syntax [later](#querying) in the cookbook) And then modify the template accordingly: + ++makeExample('heroes-graphql/ts/src/app/hero-detail.component.1.ts','graphql-query-new-field','Adding an `age` field to the component') ++makeExample('heroes-graphql/ts/src/app/hero-detail.component.1.html','template-new-field','Adding an `age` field to the template') + +:marked + So far, you've seen how to fetch data with GraphQL for a component while + keeping the component isolated from the rest of the app. + That solves the most time-consuming and bug provoking code + that one usually writes in order to fetch data from the server. + You can also use GraphQL to improve efficiency. + +:marked + ### Network Performance + + The [Tour of Heroes HTTP guide](latest/tutorial/toh-pt6.html) + calls `getHeroes` to fetch all heroes and their information. + +:marked + That might work for simple cases but the problem here is that `getHeroes` might fetch + more information than the app really needs for each hero. + This approach also creates a dependency between the server endpoint and the UI + component—if you change or limit the amount of information you send on the + server, you might break the components that use that endpoint. + + The other approach would be to call `getHeroes`, get the ids of the heroes and call `getHero` for each id. + That might result in _multiple requests to the server_ for one single render of the page. + + With a REST API, you _always have to choose between those two options_ and + their respective problems. + +:marked + With GraphQL, you just specify the dependency of each component and a + GraphQL client library, like the [Apollo Client](http://dev.apollodata.com/), + to merge those into **one single network request**. GraphQL sends back the information + in a single response, with exactly the information you need—no more, no + less—in exactly the structure and shape you want the data to be with + no need to do complex joins or wait for responses. + +.l-sub-section + :marked + You can work with the Apollo Client + while still keep your existing REST services in your Angular app + and migrate gradually from them. + +:marked + ### Typed API, tooling and auto documentation + + Just as TypeScript provides tooling to increase productivity and best practices, + GraphQL provides a similar solution for working with APIs. + + Often, APIs are written by teams you don't have access to and + can change without notice. + + With GraphQL, the schema is typed and shared between the client + and the server. As a result, just as with Angular and TypeScript, + you get the same development experience when calling calling a remote + API—validation and autocompletion inside the IDE at development time. + +.l-main-section + +:marked + ## How to use GraphQL in an Angular app + + This guide uses [Apollo Client](http://dev.apollodata.com/) as the GraphQL client for Angular. + Apollo helps you query GraphQL and provides a caching layer + with common features you need for querying a server such as + caching, mutations, optimistic UI, real-time subscriptions, + pagination, server-side rendering, and prefetching. + +.l-sub-section + :marked + This cookbook touches on the main points of using GraphQL with Angular. + The full documentation can be found on the [Apollo Client website](http://dev.apollodata.com/). + +:marked + The starting point for the app is the [Tour of Heroes tutorial](https://github.com/Urigo/quickstart/archive/graphql-start.zip) app at its end state. + + This guide shows you how to migrate that app from REST to GraphQL. + +.l-main-section + +:marked + ## Installation + + First, install Apollo Client and the integration libraries from npm: + +code-example(language="sh" class="code-shell"). + npm install apollo-client apollo-angular graphql-tag --save + +.l-sub-section + :marked + This example uses `system.js` so you need to also add the configuration to it. + With other build systems, the following process will be different and maybe easier. + +:marked + Add the following configuration to your `systemjs.config.js` file under the `map` key: + ++makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-apollo-client-map', 'under map: { (excerpt)') + +:marked + and the following configuration to your `systemjs.config.js` file under the `packages` key: + ++makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-apollo-client-packages', 'under packages: { (excerpt)') + +:marked + Next, initialize the client by creating a new file called `client.ts` and + pasting in the following code: + ++makeExample('heroes-graphql/ts/src/app/client.1.ts', '', 'app/client.ts') +:marked + So what's happening here? + + This is how to use the default initialization of Apollo which calls the `/graphql` endpoint. + First, you import `ApolloClient`. then you create a constant for the new instance of the client, + and finally export it so that it is available to the app. + +.l-sub-section + :marked + ### To use a different URI for the Apollo Client + For this cookbook we would use the default `/graphql` endpoint, + but it's good to know it is possible to change those settings. + To change the [settings](http://dev.apollodata.com/core/apollo-client-api.html#ApolloClient\.constructor) + of `ApolloClient`, call its constructor with different parameters. + Go to the [Apollo documentation](http://dev.apollodata.com/angular2/initialization.html#creating-client) for further resources. + +:marked + Usually you need to query an existing server. + The server for this guide is based on the [Tour of Heroes](ts/latest/tutorial/) app. + The starter app already has an in-memory GraphQL server prepared. + + Now all that's left is to connect the in-memory server to the Apollo Client configuration + by importing `networkInterface` and adding it to the `client` constant in `client.ts`. ++makeExample('heroes-graphql/ts/src/app/client.ts', '', 'client.ts') +.l-sub-section + :marked + In order to learn how to create the GraphQL server for this example, follow the instructions on + [Appendix: Setting up a GraphQL server](#server). + +:marked + After initializing the Apollo Client, import the `ApolloModule` and `getClient` + which you just configured in `client.ts` into the app's root module: ++makeExample('heroes-graphql/ts/src/app/app.module.ts', 'import-apollo', 'app.module.ts (excerpt)') + +:marked + Next, add `ApolloModule.forRoot(getClient)` to the `@NgModule` imports array. This + is an initialization function that accepts the Apollo configuration + you created earlier as an argument and creates a new Apollo instance for the app. + ++makeExample('heroes-graphql/ts/src/app/app.module.ts', 'apollo-ngmodule', 'app.module.ts (excerpt)') + +:marked + Now Apollo is initialized and ready for use in the app. + +.l-main-section + +:marked + ## Performing a query + + With GraphQL you query a schema, which is organized into types and fields, + that represents the data you can query. + + The schema begins with data types and fields followed by the specific queries + you can perform on the data. These are in turn followed by + mutations, which are _actions_ that you + can call on the server, similar to a POST request in REST. + + Here is the schema the Tour of Heroes server in the app use: + ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'graphql-schema', 'Tour of heroes schema') + +:marked + Once you have a server, which is prepared already in this app, to start querying data, begin by importing `Apollo` into `heroes.component.ts`, + and injecting it into the constructor: ++makeExample('heroes-graphql/ts/src/app/heroes.component.ts', 'import-apollo', 'heroes.component.ts (excerpt)') ++makeExample('heroes-graphql/ts/src/app/heroes.component.ts', 'inject-apollo', 'heroes.component.ts (excerpt)') +:marked + Now that the schema is available to the app, the next step is querying it. + In the component, import `gql` from the `graphql-tag` library. + The `gql` function turns your query string to something `Apollo` + can accept and understand. + ++makeExample('heroes-graphql/ts/src/app/heroes.component.ts', 'import-graphql-tag', 'heroes.component.ts') + +:marked + In order to specify the TypeScript type of the data that is recieved, import `ApolloQueryResult` from `apollo-client`: + ++makeExample('heroes-graphql/ts/src/app/heroes.component.ts', 'import-apollo-query-result', 'import type') + +:marked + To query data with the Apollo Client, pass a GraphQL query with the + data and structure that you want to the `Apollo` `watchQuery` function. + The `Apollo` ` watchQuery` function returns the data from the + server in the form of an Observable. + Replace the `getHeroes()` function with this one: + ++makeExample('heroes-graphql/ts/src/app/heroes.component.ts', 'query-heroes', 'heroes.component.ts') + +:marked + For more information on GraphQL queries, see the GraphQL documentation on + [Queries and Mutations](http://graphql.org/learn/queries/). +:marked + Next, update the template so it displays the results of the query. ++makeExample('heroes-graphql/ts/src/app/heroes.component.1.html', 'render-heroes', 'heroes.component.html') + +:marked + At this point, if you have a running [GraphQL server](#server), the browser displays the + fetched data. + +.l-main-section + +:marked + ## Performing a mutation + + In addition to fetching data using queries, GraphQL also makes it possible to change data through mutations. + + Mutations are identical to queries in syntax, the only difference being that you use the keyword `mutation` instead of `query` to indicate that you are performing writes to the backend. + +.l-sub-section + :marked + You can look at a mutation as the equivalent of a POST request in REST. +:marked + GraphQL mutations, like queries, are straightforward with minimal syntax. + Consider this example of a mutation: +code-example(language="json"). + mutation { + addHero(heroName: "Russell Brand") { + id + name + } + } +:marked + First, you declare that you're writing a mutation and then specify what it does. + To break it down, GraphQL mutations consist of two parts: + 1. The mutation name with arguments (`addHero`), which represents the actual + operation to be done on the server (just like calling a function). + 2. The fields you want back from the result of the mutation, which are sent back to the client. + In this example, they are `id` and `name`. This allows you to decide + which fields you get back from the server, + rather than the server dictating what's returned. + + The result of the above mutation might be: +code-example(language="json"). + { + "data": { + "addHero": { + "id": "69", + "name": "Russel Brand" + } + } + } +.l-sub-section + :marked + For an in-depth look at mutation syntax, see the [Mutations + documentation](http://graphql.org/learn/queries/#mutations) + at [GraphQL.org](http://graphql.org). +:marked + To use a mutation, first update the template with a function to add a hero: ++makeExample('heroes-graphql/ts/src/app/heroes.component.html', 'add', 'heroes.component.html') +:marked + In the component class, create the `add()` function. It expects a name argument of type `string` + and is `void` because it returns nothing. ++makeExample('heroes-graphql/ts/src/app/heroes.component.1.ts', 'add', 'heroes.component.ts') +:marked + Now for the fun part. Inside of the `add()` function, add an `addHero` mutation + using the `apollo.mutate` function as follows: ++makeExample('heroes-graphql/ts/src/app/heroes.component.2.ts', 'add-mutation', 'heroes.component.ts') +:marked + The mutation requires a variable and you pass it to the `mutate` function through the `variables` parameter. + + As mentioned above, with GraphQL mutations, you specify the result you want to get back from the server. + + Apollo's `mutate` function returns the result as an Observable. + The Observable returns a `mutationResult` variable that is structured + like the `ApolloQueryResult` TypeScript type, where the generic `T` type is a `Hero` type: +code-example(language="json"). + type ApolloQueryResult<T> = { + data: T; + loading: boolean; + networkStatus: NetworkStatus; + }; +:marked + If that looks familiar, it's because that's also how you reference the `mutationResult` variable in TypeScript. + To access the hero data `mutationResult` returns, use dot notation to traverse `mutationResult` and assign it to a new hero object: ++makeExample('heroes-graphql/ts/src/app/heroes.component.ts', 'access-mutation-result', 'heroes.component.ts') +:marked + Now that you have created the new object with the data, push it into the `heroes` array. + +:marked + Just like a query, the `mutate` function returns an Observable you can subscribe to + that handles the data you request. + + Now your existing heroes app can add a hero using GraphQL. +figure.image-display + img(src='/resources/images/cookbooks/heroes-graphql/heroes- graphql-mutation.gif' alt="Heroes GraphQL Mutation") + +.l-main-section + +:marked + ## Appendix: Setting up a GraphQL server + + This example shows how to run a GraphQL in the browser but running a GraphQL server on + Node.js or in the browser is very similar. + + If you don't have the option of running GraphQL on the server, + this method makes it possible to still use GraphQL in your app with the + benefit of not needing to sync multiple REST requests and join logic + on the client. + +.l-sub-section + :marked + To read more about how to run a full GraphQL backend, see the [Apollo Server documentation](http://dev.apollodata.com/tools/). + Because the real, backend server is written in Isomorphic Javascript, + it is almost identical to the local server in this appendix. + Everything you learn here applies to writing an actual GraphQL backend server. + + Additionally, there are a few GraphQL backend-as-a-service platforms available, + similar to Firebase, but based on the GraphQL API spec. + For help on getting up and running, see [Scaphold](https://www.scaphold.io/) and [Graphcool](https://www.graph.cool/). + +:marked + In order to create a GraphQL schema, you need the `graphql-tools` library. + It allows you to write a GraphQL schema as a string and make it executable. + In a terminal window, issue the following command: + +.l-sub-section + :marked + This example uses `system.js` so you need to also add the configuration to it. + With other build systems, or when running on Node, the following process will be different and + maybe easier. + +code-example(language="sh" class="code-shell"). + npm install graphql-tools --save + +.l-sub-section + :marked + This example uses `system.js` so you need to also add the configuration to it. + With other build systems, or when running on Node, the following process will be different and + maybe easier. + +:marked + Add the following configuration to your `systemjs.config.js` file under the `map` key: + ++makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-graphql-server-map', 'under map: { (excerpt)') + +:marked + and the following configuration to your `systemjs.config.js` file under the `packages` key: + ++makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-graphql-server-packages', 'under packages: { (excerpt)') + +:marked + Next, create a file called `in-memory-graphql.ts` in the `app` directory + and paste in the following schema: + ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'graphql-schema', 'in-memory-graphql.ts') +:marked + The schema starts with a represention of the model of data the server exposes. + Then the schema specifies what queries are allowed on that data, followed by + what mutations, or actions, clients are allowed to do on the server. + The end of the schema provides the definitions as the root types the GraphQL server will expose. + +.l-sub-section + :marked + While the schema includes the major points covered in this cookbook, + you can read more in the [GraphQL.org Introduction to GraphQL](http://graphql.org/learn/). +:marked + Now, create your in-memory data: ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'heroes-array', 'in-memory-graphql.ts (excerpt)') +:marked + The next step is writing a server that _resolves_ + the queries from the client based on the schema. + Hence, the GraphQL server consists of _resolver + functions_ that correspond to the _types_ of the schema. + + In some server functions you use the `lodash` library so don't + forget to install them from npm and import them: +code-example(language="sh" class="code-shell"). + npm install lodash --save ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'import-lodash', 'in-memory-graphql.ts (imports)') + +:marked + To create the resolvers, copy the following code and add it to `in-memory-graphql.ts`. ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'resolvers', 'in-memory-graphql.ts (excerpt)') + +.l-sub-section + :marked + For the full explanation about how GraphQL resolvers work see + [Execution](http://graphql.org/learn/execution/) on [GraphQL.org](http://graphql.org/). + +:marked + Notice that the server includes functions that correspond to each + type in the schema _and_ the mutations. + + This mechanism makes writing simple GraphQL servers straightforward—you simply + resolve a specific type of data. + This removes the coupling between the frontend and backend because you don't need to know the specific + query the client makes to create the server implementation. + +:marked + Now, connect the schema to the resolvers with the `makeExecutableSchema` function from + the [graphql-tools](http://dev.apollodata.com/tools/graphql-tools/index.html) library: ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'import-graphql-tools', 'in-memory-graphql.ts (excerpt)') ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'make-executable-schema', 'in-memory-graphql.ts (excerpt)') + +:marked + In the constant `schema`, `makeExecutableSchema` has two properties, + `typeDefs` and `resolvers`. Here, you define them with the `typeDefinitions` + and `resolveFunctions` that you created earlier in `in-memory-graphql.ts`. + This way, your GraphQL server knows where to look for definitions and resolvers. + +:marked + Now that you have an executable schema, execute it using the `graphql` + library and export it so you can use it with the Apollo Client. + First, `npm install`: +code-example(language="sh" class="code-shell"). + npm install graphql --save + +:marked + Next, add an import statement for `execute`. + ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'import-graphql', 'in-memory-graphql.ts (excerpt)') +:marked + Now create a new `networkInterface` class and call it `InBrowserNetworkInterface`. + + This class has a `schema` property which it initializes in the constructor. + + Next, the `query` function takes as an argument the query request and executes + that query using the GraphQL `execute` function against the schema property. + + You send empty objects to the `rootValue` and `contextValue` arguments of the function with `{}` and `{}` respectively + and send the `variables` and `operationName` arguments that are related to the query request. + + Lastly, export the new `InBrowserNetworkInterface` class in order to import it to the Apollo Client. ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'execute-and-export', 'in-memory-graphql.ts (excerpt)') +:marked + Now all that's left is to connect the new in-memory server to the Apollo Client configuration + by importing `networkInterface` and adding it to the `client` constant in `client.ts`. ++makeExample('heroes-graphql/ts/src/app/client.ts', '', 'client.ts') +:marked + That's it. Now you can run your application as if you had a GraphQL server connected to it. + However, there is no persistance—everything is running in-memory in the browser, + so when you refresh the page, all changes will be lost. + + Now that you have a local server set up, you have some options: + * You can store everything on the browser's local-storage using local-storage database libraries. + * You can make the resolver functions call your server's existing REST endpoint. + * You can start a separate Node GraphQL server and simply move the code into it for persistance. + +.l-main-section +:marked + ## Conclusion + + This cookbook covered: + + - What is GraphQL and why it can benefit Angular developers. + - How to create a basic GraphQL query. + - How to create a basic GraphQL mutation. + - How to build a GraphQL server. + - Resources to dive deeper. + +.l-main-section + +:marked + ## Further resources + + * [GraphQL.org](http://graphql.org/) is a great website, with the following sections + (by the way, all the examples on the website are runing live, try to edit them in the browser while you reading it): + * [Learn](http://graphql.org/learn/) + * [Implementations in any language](http://graphql.org/code/) + * [Community](http://graphql.org/community/) + * [Apollo Developer resources](http://dev.apollodata.com/) - The [team](http://www.apollodata.com/) behind the Angular GraphQL client, + there you will find a more advanced resources about: + * [Handling updates from the server and managing the local store](http://dev.apollodata.com/angular2/receiving-updates.html) + * [Authentication](http://dev.apollodata.com/angular2/auth.html) + * [Pagination](http://dev.apollodata.com/angular2/pagination.html) + * [Server-side rendering](http://dev.apollodata.com/angular2/server-side-rendering.html) + * and more.. + * [Apollo Dev Blog](https://dev-blog.apollodata.com/) - The most popular GraphQL blog + * [Apollo Client Developer Tools](https://dev-blog.apollodata.com/apollo-client-developer-tools-ff89181ebcf#.n5f3fhbg2) - GraphQL debugging tools for Apollo Client in the Chrome developer console + +.l-main-section + +:marked + ## Full Example + +block file-summary + +makeTabs( + `heroes-graphql/ts/src/app/app.component.ts, + heroes-graphql/ts/src/app/app.module.ts, + heroes-graphql/ts/src/app/heroes.component.ts, + heroes-graphql/ts/src/app/heroes.component.html, + heroes-graphql/ts/src/app/heroes.component.css, + heroes-graphql/ts/src/app/hero-detail.component.ts, + heroes-graphql/ts/src/app/hero-detail.component.html, + heroes-graphql/ts/src/app/in-memory-graphql.ts, + heroes-graphql/ts/src/app/client.ts`, + ',,,,,,,,', + `app.comp...ts, + app.mod...ts, + heroes.comp...ts, + heroes.comp...html, + heroes.comp...css, + hero-detail.comp...ts, + hero-detail.comp...html, + in-memory-graphql.ts, + client.ts` + ) + + +makeTabs( + `heroes-graphql/ts/src/app/app-routing.module.ts, + heroes-graphql/ts/src/app/hero-search.component.ts, + heroes-graphql/ts/src/app/hero-search.component.html, + heroes-graphql/ts/src/app/hero-search.component.css`, + null, + `app-routing.modules.ts, + hero-search.component.ts, + hero-search.component.html, + hero-search.component.css` + ) + +:marked + [Back to top](#top) diff --git a/public/resources/images/cookbooks/heroes-graphql/heroes- graphql-mutation.gif b/public/resources/images/cookbooks/heroes-graphql/heroes- graphql-mutation.gif new file mode 100755 index 0000000000000000000000000000000000000000..012f1359777e6ee768da9be555c64fe933b9310e GIT binary patch literal 234619 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

    Y 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 Date: Mon, 20 Mar 2017 13:45:11 +0100 Subject: [PATCH 02/16] docs(graphql-cookbook): Update dependencies Use ISubscription because this from Apollo is not compatible with that from RxJS --- .../heroes-graphql/ts/src/app/hero-detail.component.1.ts | 4 ++-- .../heroes-graphql/ts/src/app/hero-detail.component.ts | 4 ++-- public/docs/_examples/package.json | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.ts b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.ts index e8445ee1cf..830a11e129 100755 --- a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.ts +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.1.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { Location } from '@angular/common'; import { Apollo, ApolloQueryObservable } from 'apollo-angular'; -import { Subscription } from 'rxjs/Subscription'; +import { ISubscription } from 'rxjs/Subscription'; import gql from 'graphql-tag'; import { Hero } from './hero'; @@ -17,7 +17,7 @@ import { Hero } from './hero'; export class HeroDetailComponent implements OnInit { hero: Hero; - private heroSubscription: Subscription; + private heroSubscription: ISubscription; private heroObservable: ApolloQueryObservable; constructor( diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.ts b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.ts index 1eb4487c8f..0f9eeb15fb 100755 --- a/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.ts +++ b/public/docs/_examples/heroes-graphql/ts/src/app/hero-detail.component.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { Location } from '@angular/common'; import { Apollo, ApolloQueryObservable } from 'apollo-angular'; -import { Subscription } from 'rxjs/Subscription'; +import { ISubscription } from 'rxjs/Subscription'; import gql from 'graphql-tag'; import { Hero } from './hero'; @@ -18,7 +18,7 @@ import { ApolloQueryResult } from 'apollo-client'; export class HeroDetailComponent implements OnInit { hero: Hero; - private heroSubscription: Subscription; + private heroSubscription: ISubscription; private heroObservable: ApolloQueryObservable; constructor( diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index 02a323dbaa..54e4d8ef4b 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -27,11 +27,11 @@ "@angular/upgrade": "~4.0.0", "angular-in-memory-web-api": "~0.3.1", "apollo-angular": "^0.12.0", - "apollo-client": "0.10.0", + "apollo-client": "1.0.0-rc.5", "core-js": "^2.4.1", "graphql": "^0.9.1", "graphql-subscriptions": "^0.3.1", - "graphql-tag": "^1.3.1", + "graphql-tag": "^1.3.2", "graphql-tools": "^0.10.1", "lodash": "^4.17.4", "rxjs": "5.0.1", From 0088d67419173b5aa2be47c2a7f73adbdaa13d40 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 00:13:07 +0100 Subject: [PATCH 03/16] docs(graphql-cookbook): Add a downloadable starter example --- .../heroes-graphql-starter/e2e-spec.ts | 283 ++++++++++++++++++ .../heroes-graphql-starter/ts/.gitignore | 8 + .../heroes-graphql-starter/ts/aot/index.html | 19 ++ .../heroes-graphql-starter/ts/aot/styles.css | 116 +++++++ .../ts/bs-config.aot.json | 14 + .../ts/example-config.json | 0 .../heroes-graphql-starter/ts/plnkr.json | 10 + .../ts/rollup-config.js | 53 ++++ .../ts/src/app/app-routing.module.ts | 19 ++ .../ts/src/app/app.component.css | 29 ++ .../ts/src/app/app.component.ts | 19 ++ .../ts/src/app/app.module.ts | 52 ++++ .../ts/src/app/dashboard.component.css | 62 ++++ .../ts/src/app/dashboard.component.html | 10 + .../ts/src/app/dashboard.component.ts | 22 ++ .../ts/src/app/hero-detail.component.css | 30 ++ .../ts/src/app/hero-detail.component.html | 14 + .../ts/src/app/hero-detail.component.ts | 43 +++ .../ts/src/app/hero-search.component.css | 21 ++ .../ts/src/app/hero-search.component.html | 11 + .../ts/src/app/hero-search.component.ts | 69 +++++ .../ts/src/app/hero-search.service.ts | 20 ++ .../ts/src/app/hero.service.ts | 87 ++++++ .../heroes-graphql-starter/ts/src/app/hero.ts | 4 + .../ts/src/app/heroes.component.1.ts | 48 +++ .../ts/src/app/heroes.component.css | 68 +++++ .../ts/src/app/heroes.component.html | 29 ++ .../ts/src/app/heroes.component.ts | 61 ++++ .../ts/src/app/in-memory-data.service.ts | 19 ++ .../ts/src/app/in-memory-graphql.ts | 103 +++++++ .../ts/src/app/schema.ts | 38 +++ .../heroes-graphql-starter/ts/src/index.html | 26 ++ .../heroes-graphql-starter/ts/src/main-aot.ts | 6 + .../heroes-graphql-starter/ts/src/main.ts | 6 + .../ts/tsconfig-aot.json | 26 ++ 35 files changed, 1445 insertions(+) create mode 100644 public/docs/_examples/heroes-graphql-starter/e2e-spec.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/.gitignore create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/aot/index.html create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/aot/styles.css create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/bs-config.aot.json create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/example-config.json create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/plnkr.json create mode 100755 public/docs/_examples/heroes-graphql-starter/ts/rollup-config.js create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/app-routing.module.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.css create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/app.module.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.css create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.html create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.css create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.html create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.css create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.html create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.service.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero.service.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/hero.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.1.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.css create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.html create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/in-memory-data.service.ts create mode 100755 public/docs/_examples/heroes-graphql-starter/ts/src/app/in-memory-graphql.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/index.html create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/main-aot.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/main.ts create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/tsconfig-aot.json diff --git a/public/docs/_examples/heroes-graphql-starter/e2e-spec.ts b/public/docs/_examples/heroes-graphql-starter/e2e-spec.ts new file mode 100644 index 0000000000..9440778496 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/e2e-spec.ts @@ -0,0 +1,283 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder, ElementArrayFinder } from 'protractor'; +import { promise } from 'selenium-webdriver'; + +const expectedH1 = 'Tour of Heroes - GraphQL Starter'; +const expectedTitle = `Angular ${expectedH1}`; +const targetHero = { id: 15, name: 'Magneta' }; +const targetHeroDashboardIndex = 3; +const nameSuffix = 'X'; +const newHeroName = targetHero.name + nameSuffix; + +class Hero { + id: number; + name: string; + + // Factory methods + + // Hero from string formatted as ' '. + static fromString(s: string): Hero { + return { + id: +s.substr(0, s.indexOf(' ')), + name: s.substr(s.indexOf(' ') + 1), + }; + } + + // Hero from hero list

  • element. + static async fromLi(li: ElementFinder): Promise { + let strings = await li.all(by.xpath('span')).getText(); + return { id: +strings[0], name: strings[1] }; + } + + // Hero id and name from the given detail element. + static async fromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
    + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + let _name = await detail.element(by.css('h2')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; + } +} + +describe('Heroes GraphQL Starter', () => { + + beforeAll(() => browser.get('')); + + function getPageElts() { + let navElts = element.all(by.css('my-app nav a')); + + return { + navElts: navElts, + + myDashboardHref: navElts.get(0), + myDashboard: element(by.css('my-app my-dashboard')), + topHeroes: element.all(by.css('my-app my-dashboard > div h4')), + + myHeroesHref: navElts.get(1), + myHeroes: element(by.css('my-app my-heroes')), + allHeroes: element.all(by.css('my-app my-heroes li')), + selectedHero: element(by.css('my-app li.selected')), + selectedHeroSubview: element(by.css('my-app my-heroes > div:last-child')), + + heroDetail: element(by.css('my-app my-hero-detail > div')), + + searchBox: element(by.css('#search-box')), + searchResults: element.all(by.css('.search-result')) + }; + } + + describe('Initial page', () => { + + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h1 '${expectedH1}'`, () => { + expectHeading(1, expectedH1); + }); + + const expectedViewNames = ['Dashboard', 'Heroes']; + it(`has views ${expectedViewNames}`, () => { + let viewNames = getPageElts().navElts.map((el: ElementFinder) => el.getText()); + expect(viewNames).toEqual(expectedViewNames); + }); + + it('has dashboard as the active view', () => { + let page = getPageElts(); + expect(page.myDashboard.isPresent()).toBeTruthy(); + }); + + }); + + describe('Dashboard tests', () => { + + beforeAll(() => browser.get('')); + + it('has top heroes', () => { + let page = getPageElts(); + expect(page.topHeroes.count()).toEqual(4); + }); + + it(`selects and routes to ${targetHero.name} details`, dashboardSelectTargetHero); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`cancels and shows ${targetHero.name} in Dashboard`, () => { + element(by.buttonText('Back')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(targetHero.name); + }); + + it(`selects and routes to ${targetHero.name} details`, dashboardSelectTargetHero); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`saves and shows ${newHeroName} in Dashboard`, () => { + element(by.buttonText('Save')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(newHeroName); + }); + + }); + + describe('Heroes tests', () => { + + beforeAll(() => browser.get('')); + + it('can switch to Heroes view', () => { + getPageElts().myHeroesHref.click(); + let page = getPageElts(); + expect(page.myHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(10, 'number of heroes'); + }); + + it(`selects and shows ${targetHero.name} as selected in list`, () => { + getHeroLiEltById(targetHero.id).click(); + expect(Hero.fromLi(getPageElts().selectedHero)).toEqual(targetHero); + }); + + it('shows selected hero subview', () => { + let page = getPageElts(); + let title = page.selectedHeroSubview.element(by.css('h2')).getText(); + let expectedTitle = `${targetHero.name.toUpperCase()} is my hero`; + expect(title).toEqual(expectedTitle); + }); + + it('can route to hero details', () => { + element(by.buttonText('View Details')).click(); + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + let hero = Hero.fromDetail(page.heroDetail); + expect(hero).toEqual(targetHero); + }); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`shows ${newHeroName} in Heroes list`, () => { + element(by.buttonText('Save')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + let expectedHero = {id: targetHero.id, name: newHeroName}; + expect(Hero.fromLi(getHeroLiEltById(targetHero.id))).toEqual(expectedHero); + }); + + it(`deletes ${newHeroName} from Heroes list`, async () => { + const heroesBefore = await toHeroArray(getPageElts().allHeroes); + const li = getHeroLiEltById(targetHero.id); + li.element(by.buttonText('x')).click(); + + const page = getPageElts(); + expect(page.myHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(9, 'number of heroes'); + const heroesAfter = await toHeroArray(page.allHeroes); + const expectedHeroes = heroesBefore.filter(h => h.name !== newHeroName); + expect(heroesAfter).toEqual(expectedHeroes); + expect(page.selectedHeroSubview.isPresent()).toBeFalsy(); + }); + + it(`adds back ${targetHero.name}`, async () => { + const newHeroName = 'Alice'; + const heroesBefore = await toHeroArray(getPageElts().allHeroes); + const numHeroes = heroesBefore.length; + + element(by.css('input')).sendKeys(newHeroName); + element(by.buttonText('Add')).click(); + + let page = getPageElts(); + let heroesAfter = await toHeroArray(page.allHeroes); + expect(heroesAfter.length).toEqual(numHeroes + 1, 'number of heroes'); + + expect(heroesAfter.slice(0, numHeroes)).toEqual(heroesBefore, 'Old heroes are still there'); + + const maxId = heroesBefore[heroesBefore.length - 1].id; + expect(heroesAfter[numHeroes]).toEqual({id: maxId + 1, name: newHeroName}); + }); + }); + + describe('Progressive hero search', () => { + + beforeAll(() => browser.get('')); + + it(`searches for 'Ma'`, async () => { + getPageElts().searchBox.sendKeys('Ma'); + browser.sleep(1000); + expect(getPageElts().searchResults.count()).toBe(4); + }); + + it(`continues search with 'g'`, async () => { + getPageElts().searchBox.sendKeys('g'); + browser.sleep(1000); + expect(getPageElts().searchResults.count()).toBe(2); + }); + + it(`continues search with 'n' and gets ${targetHero.name}`, async () => { + getPageElts().searchBox.sendKeys('n'); + browser.sleep(1000); + let page = getPageElts(); + expect(page.searchResults.count()).toBe(1); + let hero = page.searchResults.get(0); + expect(hero.getText()).toEqual(targetHero.name); + }); + + it(`navigates to ${targetHero.name} details view`, async () => { + let hero = getPageElts().searchResults.get(0); + expect(hero.getText()).toEqual(targetHero.name); + hero.click(); + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + expect(Hero.fromDetail(page.heroDetail)).toEqual(targetHero); + }); + }); + + function dashboardSelectTargetHero() { + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(targetHero.name); + targetHeroElt.click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + let hero = Hero.fromDetail(page.heroDetail); + expect(hero).toEqual(targetHero); + } + + async function updateHeroNameInDetailView() { + // Assumes that the current view is the hero details view. + addToHeroName(nameSuffix); + + let hero = await Hero.fromDetail(getPageElts().heroDetail); + expect(hero).toEqual({id: targetHero.id, name: newHeroName}); + } + +}); + +function addToHeroName(text: string): promise.Promise { + let input = element(by.css('input')); + return input.sendKeys(text); +} + +function expectHeading(hLevel: number, expectedText: string): void { + let hTag = `h${hLevel}`; + let hText = element(by.css(hTag)).getText(); + expect(hText).toEqual(expectedText, hTag); +}; + +function getHeroLiEltById(id: number): ElementFinder { + let spanForId = element(by.cssContainingText('li span.badge', id.toString())); + return spanForId.element(by.xpath('..')); +} + +async function toHeroArray(allHeroes: ElementArrayFinder): Promise { + let promisedHeroes = await allHeroes.map(Hero.fromLi); + // The cast is necessary to get around issuing with the signature of Promise.all() + return > Promise.all(promisedHeroes); +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/.gitignore b/public/docs/_examples/heroes-graphql-starter/ts/.gitignore new file mode 100644 index 0000000000..804879d44a --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/.gitignore @@ -0,0 +1,8 @@ +aot/**/*.ts +**/*.ngfactory.ts +**/*.ngsummary.json +**/*.metadata.json +**/*.js +dist +!app/tsconfig.json +!rollup-config.js diff --git a/public/docs/_examples/heroes-graphql-starter/ts/aot/index.html b/public/docs/_examples/heroes-graphql-starter/ts/aot/index.html new file mode 100644 index 0000000000..cb8ecc4461 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/aot/index.html @@ -0,0 +1,19 @@ + + + + + + Angular Tour of Heroes + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/heroes-graphql-starter/ts/aot/styles.css b/public/docs/_examples/heroes-graphql-starter/ts/aot/styles.css new file mode 100644 index 0000000000..d81835d0cd --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/aot/styles.css @@ -0,0 +1,116 @@ +/* #docregion , quickstart, toh */ +/* Master Styles */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} +h2, h3 { + color: #444; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +/* #enddocregion quickstart */ +body, input[text], button { + color: #888; + font-family: Cambria, Georgia; +} +/* #enddocregion toh */ +a { + cursor: pointer; + cursor: hand; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} + +/* Navigation link styles */ +nav a { + padding: 5px 10px; + text-decoration: none; + margin-right: 10px; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} + +/* items class */ +.items { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 24em; +} +.items li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.items li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.items li.selected { + background-color: #CFD8DC; + color: white; +} +.items li.selected:hover { + background-color: #BBD8DC; +} +.items .text { + position: relative; + top: -3px; +} +.items .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +/* #docregion toh */ +/* everywhere else */ +* { + font-family: Arial, Helvetica, sans-serif; +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/bs-config.aot.json b/public/docs/_examples/heroes-graphql-starter/ts/bs-config.aot.json new file mode 100644 index 0000000000..e59a7403a0 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/bs-config.aot.json @@ -0,0 +1,14 @@ +{ + "open": false, + "logLevel": "silent", + "port": 8080, + "server": { + "baseDir": "aot", + "routes": { + "/node_modules": "node_modules" + }, + "middleware": { + "0": null + } + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/example-config.json b/public/docs/_examples/heroes-graphql-starter/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json b/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json new file mode 100644 index 0000000000..d355bc9ff2 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "Tour of Heroes: Part 6", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1,2].*" + ], + "tags": ["tutorial", "tour", "heroes", "http"] +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/rollup-config.js b/public/docs/_examples/heroes-graphql-starter/ts/rollup-config.js new file mode 100755 index 0000000000..3591eb4e2a --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/rollup-config.js @@ -0,0 +1,53 @@ +// #docregion +import rollup from 'rollup' +import nodeResolve from 'rollup-plugin-node-resolve' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' + +import builtins from 'rollup-plugin-node-builtins'; +import globals from 'rollup-plugin-node-globals'; +//paths are relative to the execution path +export default { + entry: 'src/main-aot.js', + dest: 'aot/dist/build.js', // output a single application bundle + sourceMap: true, + sourceMapFile: 'aot/dist/build.js.map', + format: 'iife', + onwarn: function(warning) { + // Skip certain warnings + + // should intercept ... but doesn't in some rollup versions + if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; } + // intercepts in some rollup versions + if ( warning.indexOf("The 'this' keyword is equivalent to 'undefined'") > -1 ) { return; } + + // console.warn everything else + console.warn( warning.message ); + }, + plugins: [ + nodeResolve({jsnext: true, module: true, browser: true}), + commonjs({ + include: [ + 'node_modules/rxjs/**', + 'node_modules/graphql-tag/**', + 'node_modules/apollo-client/**', + 'node_modules/lodash/**', + 'node_modules/graphql-tools/dist/**', + 'node_modules/graphql/**', + 'node_modules/graphql-anywhere/**', + 'node_modules/iterall/**', + 'node_modules/deprecated-decorator/**', + 'node_modules/uuid/**' + ], + namedExports: { + 'node_modules/graphql-tools/dist/index.js': ['makeExecutableSchema' ], + 'node_modules/graphql/index.js': ['execute' ], + 'node_modules/graphql-tag/bundledPrinter.js': ['print'], + 'node_modules/lodash/lodash.js': ['find', 'omit', 'assign', 'isFunction'], + } + }), + globals(), + builtins(), + uglify() + ] +} \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/app-routing.module.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..bc070f6c31 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, + { path: 'dashboard', component: DashboardComponent }, + { path: 'detail/:id', component: HeroDetailComponent }, + { path: 'heroes', component: HeroesComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.css b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.css new file mode 100644 index 0000000000..071e665767 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.css @@ -0,0 +1,29 @@ +/* #docregion */ +h1 { + font-size: 1.2em; + color: #999; + margin-bottom: 0; +} +h2 { + font-size: 2em; + margin-top: 0; + padding-top: 0; +} +nav a { + padding: 5px 10px; + text-decoration: none; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.ts new file mode 100644 index 0000000000..a9fe05a9a8 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.ts @@ -0,0 +1,19 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    +
    + + `, + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'Tour of Heroes'; +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.module.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.module.ts new file mode 100644 index 0000000000..58eeb10c54 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.module.ts @@ -0,0 +1,52 @@ +// #docplaster +// #docregion +// #docregion v1, v2 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppRoutingModule } from './app-routing.module'; + +// #enddocregion v1 +// Imports for loading & configuring the in-memory web api +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; +import { InMemoryDataService } from './in-memory-data.service'; + +// #docregion v1 +import { AppComponent } from './app.component'; +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroService } from './hero.service'; +// #enddocregion v1, v2 +import { HeroSearchComponent } from './hero-search.component'; +// #docregion v1, v2 + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + // #enddocregion v1 + // #docregion in-mem-web-api + InMemoryWebApiModule.forRoot(InMemoryDataService), + // #enddocregion in-mem-web-api + // #docregion v1 + AppRoutingModule + ], + // #docregion search + declarations: [ + AppComponent, + DashboardComponent, + HeroDetailComponent, + HeroesComponent, + // #enddocregion v1, v2 + HeroSearchComponent + // #docregion v1, v2 + ], + // #enddocregion search + providers: [ HeroService ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.css b/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.css new file mode 100644 index 0000000000..dc7fb7ce06 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.css @@ -0,0 +1,62 @@ +/* #docregion */ +[class*='col-'] { + float: left; + padding-right: 20px; + padding-bottom: 20px; +} +[class*='col-']:last-of-type { + padding-right: 0; +} +a { + text-decoration: none; +} +*, *:after, *:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +h3 { + text-align: center; margin-bottom: 0; +} +h4 { + position: relative; +} +.grid { + margin: 0; +} +.col-1-4 { + width: 25%; +} +.module { + padding: 20px; + text-align: center; + color: #eee; + max-height: 120px; + min-width: 120px; + background-color: #607D8B; + border-radius: 2px; +} +.module:hover { + background-color: #EEE; + cursor: pointer; + color: #607d8b; +} +.grid-pad { + padding: 10px 0; +} +.grid-pad > [class*='col-']:last-of-type { + padding-right: 20px; +} +@media (max-width: 600px) { + .module { + font-size: 10px; + max-height: 75px; } +} +@media (max-width: 1024px) { + .grid { + margin: 0; + } + .module { + min-width: 60px; + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.html b/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.html new file mode 100644 index 0000000000..db8546ccd2 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.html @@ -0,0 +1,10 @@ + +

    Top Heroes

    + + diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.ts new file mode 100644 index 0000000000..9960aa77d4 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/dashboard.component.ts @@ -0,0 +1,22 @@ +// #docregion , search +import { Component, OnInit } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: [ './dashboard.component.css' ] +}) +// #enddocregion search +export class DashboardComponent implements OnInit { + heroes: Hero[] = []; + + constructor(private heroService: HeroService) { } + + ngOnInit(): void { + this.heroService.getHeroes() + .then(heroes => this.heroes = heroes.slice(1, 5)); + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.css b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.css new file mode 100644 index 0000000000..ab2437efd8 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.css @@ -0,0 +1,30 @@ +/* #docregion */ +label { + display: inline-block; + width: 3em; + margin: .5em 0; + color: #607D8B; + font-weight: bold; +} +input { + height: 2em; + font-size: 1em; + padding-left: .4em; +} +button { + margin-top: 20px; + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #ccc; + cursor: auto; +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.html b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.html new file mode 100644 index 0000000000..32fe6d4391 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.html @@ -0,0 +1,14 @@ + +
    +

    {{hero.name}} details!

    +
    + {{hero.id}}
    +
    + + +
    + + + + +
    diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..54423cea7f --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-detail.component.ts @@ -0,0 +1,43 @@ +// #docregion +import 'rxjs/add/operator/switchMap'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; +import { Location } from '@angular/common'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: [ './hero-detail.component.css' ] +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + constructor( + private heroService: HeroService, + private route: ActivatedRoute, + private location: Location + ) {} + + // #docregion service-fetch-by-id + ngOnInit(): void { + this.route.params + .switchMap((params: Params) => this.heroService.getHero(+params['id'])) + .subscribe(hero => this.hero = hero); + } + // #enddocregion service-fetch-by-id + + + // #docregion save + save(): void { + this.heroService.update(this.hero) + .then(() => this.goBack()); + } + // #enddocregion save + + goBack(): void { + this.location.back(); + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.css b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.css new file mode 100644 index 0000000000..9bf8d13457 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.css @@ -0,0 +1,21 @@ +/* #docregion */ +.search-result{ + border-bottom: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + width:195px; + height: 16px; + padding: 5px; + background-color: white; + cursor: pointer; +} + +.search-result:hover { + color: #eee; + background-color: #607D8B; +} + +#search-box{ + width: 200px; + height: 20px; +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.html b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.html new file mode 100644 index 0000000000..08c0560c5b --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.html @@ -0,0 +1,11 @@ + +
    +

    Hero Search

    + +
    +
    + {{hero.name}} +
    +
    +
    diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.ts new file mode 100644 index 0000000000..8b2d32f06b --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.component.ts @@ -0,0 +1,69 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +// #docregion rxjs-imports +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; + +// Observable class extensions +import 'rxjs/add/observable/of'; + +// Observable operators +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/distinctUntilChanged'; +// #enddocregion rxjs-imports + +import { HeroSearchService } from './hero-search.service'; +import { Hero } from './hero'; + +@Component({ + selector: 'hero-search', + templateUrl: './hero-search.component.html', + styleUrls: [ './hero-search.component.css' ], + providers: [HeroSearchService] +}) +export class HeroSearchComponent implements OnInit { + // #docregion search + heroes: Observable; + // #enddocregion search + // #docregion searchTerms + private searchTerms = new Subject(); + // #enddocregion searchTerms + + constructor( + private heroSearchService: HeroSearchService, + private router: Router) {} + // #docregion searchTerms + + // Push a search term into the observable stream. + search(term: string): void { + this.searchTerms.next(term); + } + // #enddocregion searchTerms + // #docregion search + + ngOnInit(): void { + this.heroes = this.searchTerms + .debounceTime(300) // wait 300ms after each keystroke before considering the term + .distinctUntilChanged() // ignore if next search term is same as previous + .switchMap(term => term // switch to new observable each time the term changes + // return the http search observable + ? this.heroSearchService.search(term) + // or the observable of empty heroes if there was no search term + : Observable.of([])) + .catch(error => { + // TODO: add real error handling + console.log(error); + return Observable.of([]); + }); + } + // #enddocregion search + + gotoDetail(hero: Hero): void { + let link = ['/detail', hero.id]; + this.router.navigate(link); + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.service.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.service.ts new file mode 100644 index 0000000000..d24e0fba41 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero-search.service.ts @@ -0,0 +1,20 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; + +import { Hero } from './hero'; + +@Injectable() +export class HeroSearchService { + + constructor(private http: Http) {} + + search(term: string): Observable { + return this.http + .get(`app/heroes/?name=${term}`) + .map(response => response.json().data as Hero[]); + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero.service.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..18af476123 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero.service.ts @@ -0,0 +1,87 @@ +// #docplaster +// #docregion , imports +import { Injectable } from '@angular/core'; +import { Headers, Http } from '@angular/http'; + +// #docregion rxjs +import 'rxjs/add/operator/toPromise'; +// #enddocregion rxjs + +import { Hero } from './hero'; +// #enddocregion imports + +@Injectable() +export class HeroService { + + // #docregion update + private headers = new Headers({'Content-Type': 'application/json'}); + // #enddocregion update + // #docregion getHeroes + private heroesUrl = 'api/heroes'; // URL to web api + + constructor(private http: Http) { } + + getHeroes(): Promise { + return this.http.get(this.heroesUrl) + // #docregion to-promise + .toPromise() + // #enddocregion to-promise + // #docregion to-data + .then(response => response.json().data as Hero[]) + // #enddocregion to-data + // #docregion catch + .catch(this.handleError); + // #enddocregion catch + } + + // #enddocregion getHeroes + + // #docregion getHero + getHero(id: number): Promise { + const url = `${this.heroesUrl}/${id}`; + return this.http.get(url) + .toPromise() + .then(response => response.json().data as Hero) + .catch(this.handleError); + } + // #enddocregion getHero + + // #docregion delete + delete(id: number): Promise { + const url = `${this.heroesUrl}/${id}`; + return this.http.delete(url, {headers: this.headers}) + .toPromise() + .then(() => null) + .catch(this.handleError); + } + // #enddocregion delete + + // #docregion create + create(name: string): Promise { + return this.http + .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers}) + .toPromise() + .then(res => res.json().data) + .catch(this.handleError); + } + // #enddocregion create + // #docregion update + + update(hero: Hero): Promise { + const url = `${this.heroesUrl}/${hero.id}`; + return this.http + .put(url, JSON.stringify(hero), {headers: this.headers}) + .toPromise() + .then(() => hero) + .catch(this.handleError); + } + // #enddocregion update + + // #docregion getHeroes, handleError + private handleError(error: any): Promise { + console.error('An error occurred', error); // for demo purposes only + return Promise.reject(error.message || error); + } + // #enddocregion getHeroes, handleError +} + diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero.ts new file mode 100644 index 0000000000..e3eac516da --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.1.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.1.ts new file mode 100644 index 0000000000..1ce69b7f4c --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.1.ts @@ -0,0 +1,48 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero } from './hero'; + +@Component({ + selector: 'my-heroes', + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] +}) +export class HeroesComponent implements OnInit { + heroes: Hero[]; + selectedHero: Hero; + + constructor( + private router: Router) { } + + getHeroes(): void { + + } + + // #docregion add + add(name: string): void { + name = name.trim(); + if (!name) { return; } + + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + + } + // #enddocregion delete + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.css b/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.css new file mode 100644 index 0000000000..d2c958a911 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.css @@ -0,0 +1,68 @@ +/* #docregion */ +.selected { + background-color: #CFD8DC !important; + color: white; +} +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} +.heroes .text { + position: relative; + top: -3px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +/* #docregion additions */ +button.delete { + float:right; + margin-top: 2px; + margin-right: .8em; + background-color: gray !important; + color:white; +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.html b/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.html new file mode 100644 index 0000000000..392d241d52 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.html @@ -0,0 +1,29 @@ + +

    My Heroes

    + +
    + + +
    + +
      + +
    • + {{hero.id}} + {{hero.name}} + + + +
    • + +
    +
    +

    + {{selectedHero.name | uppercase}} is my hero +

    + +
    diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.ts new file mode 100644 index 0000000000..6350b803c4 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/heroes.component.ts @@ -0,0 +1,61 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-heroes', + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] +}) +export class HeroesComponent implements OnInit { + heroes: Hero[]; + selectedHero: Hero; + + constructor( + private heroService: HeroService, + private router: Router) { } + + getHeroes(): void { + this.heroService + .getHeroes() + .then(heroes => this.heroes = heroes); + } + + // #docregion add + add(name: string): void { + name = name.trim(); + if (!name) { return; } + this.heroService.create(name) + .then(hero => { + this.heroes.push(hero); + this.selectedHero = null; + }); + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + this.heroService + .delete(hero.id) + .then(() => { + this.heroes = this.heroes.filter(h => h !== hero); + if (this.selectedHero === hero) { this.selectedHero = null; } + }); + } + // #enddocregion delete + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/in-memory-data.service.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/in-memory-data.service.ts new file mode 100644 index 0000000000..c915955e22 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/in-memory-data.service.ts @@ -0,0 +1,19 @@ +// #docregion , init +import { InMemoryDbService } from 'angular-in-memory-web-api'; +export class InMemoryDataService implements InMemoryDbService { + createDb() { + let heroes = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} + ]; + return {heroes}; + } +} diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/in-memory-graphql.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/in-memory-graphql.ts new file mode 100755 index 0000000000..4a8156fc42 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/in-memory-graphql.ts @@ -0,0 +1,103 @@ +// #docregion +// #docregion import-lodash +import { find as lodashFind } from 'lodash'; +// #enddocregion import-lodash +// #docregion import-graphql-tools +import { makeExecutableSchema } from 'graphql-tools'; +// #enddocregion import-graphql-tools +// #docregion import-graphql +import { execute } from 'graphql'; +// #enddocregion import-graphql +// #docregion graphql-schema +import { typeDefinitions } from './schema'; +// #enddocregion graphql-schema +// #docregion heroes-array +let heroes = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} +]; +// #enddocregion heroes-array + +// #docregion resolvers +const resolveFunctions = { + Query: { + heroes(obj: any, args: any) { + if (args.search) { + return heroes.filter(function (currentHero){ + return currentHero.name.toLowerCase().search(args.search.toLowerCase()) !== -1; + }); + } else { + return heroes; + } + }, + hero(obj: any, args: any, context: any) { + return lodashFind(heroes, { id: args.heroId }); + } + }, + Mutation: { + updateHero(root: any, args: any) { + let hero = lodashFind(heroes, { id: args.id }); + if (!hero) { + throw new Error(`Couldn't find post with id ${args.id}`); + } + hero.name = args.name; + return hero; + }, + addHero(root: any, args: any) { + const maxId = Math.max(...heroes.map((hero) => {return hero.id; })); + const newHero = { + name: args.heroName, + id: maxId + 1 + }; + heroes.push(newHero); + return newHero; + }, + deleteHero(root: any, args: any) { + let hero = lodashFind(heroes, { id: args.id }); + if (!hero) { + throw new Error(`Couldn't find post with id ${args.id}`); + } + heroes = heroes.filter(function (currentHero) { return currentHero.id !== args.id; }); + return hero; + }, + } +}; +// #enddocregion resolvers +// #docregion make-executable-schema +const schema = makeExecutableSchema({ + typeDefs: typeDefinitions, + resolvers: resolveFunctions, +}); +// #enddocregion make-executable-schema +// #docregion execute-and-export +class InBrowserNetworkInterface { + schema: any = {}; + constructor(params: any) { + this.schema = params.schema; + } + + query(request: any) { + return execute( + this.schema, + request.query, + {}, + {}, + request.variables, + request.operationName); + } +} + +const networkInterface = new InBrowserNetworkInterface({ schema }); +export { + networkInterface +} +// #enddocregion execute-and-export +// #enddocregion diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts new file mode 100644 index 0000000000..935d1f2b62 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts @@ -0,0 +1,38 @@ +// #docregion +export const typeDefinitions = ` +# the model +type Hero { + id: Int! + name: String! +} + +# The schema allows the following queries: +type Query { + heroes(search: String): [Hero] + + hero(heroId: Int!): Hero +} + +# This schema allows the following mutation: +type Mutation { + updateHero ( + id: Int! + name: String! + ): Hero + + addHero ( + heroName: String! + ): Hero + + deleteHero ( + id: Int! + ): Hero +} + +# Tell the server which types represent the root query and root mutation types. +# By convention, they are called RootQuery and RootMutation. +schema { + query: Query + mutation: Mutation +} +`; \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/index.html b/public/docs/_examples/heroes-graphql-starter/ts/src/index.html new file mode 100644 index 0000000000..18977969bb --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + + Angular Tour of Heroes + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/main-aot.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/main-aot.ts new file mode 100644 index 0000000000..bd2ca604a3 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/main-aot.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowser } from '@angular/platform-browser'; + +import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/main.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/heroes-graphql-starter/ts/tsconfig-aot.json b/public/docs/_examples/heroes-graphql-starter/ts/tsconfig-aot.json new file mode 100644 index 0000000000..fe1e6df520 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/tsconfig-aot.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + + "files": [ + "src/app/app.module.ts", + "src/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "skipMetadataEmit" : true + } +} From 6a6b8817e59d162c29f65966753be0c90a204d13 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 00:14:20 +0100 Subject: [PATCH 04/16] docs(graphql-cookbook): Add Mocked network interface --- .../heroes-graphql/ts/rollup-config.js | 2 +- .../heroes-graphql/ts/src/app/app.module.1.ts | 54 +++++++++++++++++++ .../heroes-graphql/ts/src/app/client.3.ts | 13 +++++ .../ts/src/app/heroes.component.ts | 2 +- .../ts/src/app/in-memory-graphql.ts | 38 +------------ .../ts/src/app/mockedNetworkInterface.ts | 17 ++++++ .../heroes-graphql/ts/src/app/schema.ts | 38 +++++++++++++ .../ts/src/systemjs.config.extras.js | 8 +++ public/docs/_examples/package.json | 3 +- 9 files changed, 135 insertions(+), 40 deletions(-) create mode 100644 public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts create mode 100644 public/docs/_examples/heroes-graphql/ts/src/app/client.3.ts create mode 100644 public/docs/_examples/heroes-graphql/ts/src/app/mockedNetworkInterface.ts create mode 100644 public/docs/_examples/heroes-graphql/ts/src/app/schema.ts diff --git a/public/docs/_examples/heroes-graphql/ts/rollup-config.js b/public/docs/_examples/heroes-graphql/ts/rollup-config.js index f00fdcde1d..3591eb4e2a 100755 --- a/public/docs/_examples/heroes-graphql/ts/rollup-config.js +++ b/public/docs/_examples/heroes-graphql/ts/rollup-config.js @@ -42,7 +42,7 @@ export default { namedExports: { 'node_modules/graphql-tools/dist/index.js': ['makeExecutableSchema' ], 'node_modules/graphql/index.js': ['execute' ], - 'node_modules/graphql-tag/printer.js': ['print'], + 'node_modules/graphql-tag/bundledPrinter.js': ['print'], 'node_modules/lodash/lodash.js': ['find', 'omit', 'assign', 'isFunction'], } }), diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts b/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts new file mode 100644 index 0000000000..953edf6b38 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts @@ -0,0 +1,54 @@ +// #docplaster +// #docregion + +// #docregion v1, v2 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppRoutingModule } from './app-routing.module'; + +// #enddocregion v1 + +// #docregion import-apollo +import { ApolloModule } from 'apollo-angular'; +import { getClient } from './client'; +// #enddocregion import-apollo + +// #docregion v1 +import { AppComponent } from './app.component'; +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; +// #enddocregion v1, v2 +import { HeroSearchComponent } from './hero-search.component'; +// #docregion v1, v2 + +// #docregion apollo-ngmodule +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + InMemoryWebApiModule.forRoot(InMemoryDataService), + // #enddocregion v1 + // #docregion v1 + AppRoutingModule, + ApolloModule.forRoot(getClient) + ], + // #docregion search + declarations: [ +// #enddocregion apollo-ngmodule + AppComponent, + DashboardComponent, + HeroDetailComponent, + HeroesComponent, + // #enddocregion v1, v2 + HeroSearchComponent + // #docregion v1, v2 + ], + // #enddocregion search + bootstrap: [ AppComponent ] +}) +export class AppModule { } \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/client.3.ts b/public/docs/_examples/heroes-graphql/ts/src/app/client.3.ts new file mode 100644 index 0000000000..b39e743367 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/client.3.ts @@ -0,0 +1,13 @@ +// #docregion +import { ApolloClient } from 'apollo-client'; +// #docregion import-and-use +import { mockNetworkInterface } from './mockedNetworkInterface'; + +const client = new ApolloClient({ + networkInterface: mockNetworkInterface +}); +// #enddocregion import-and-use +export function getClient(): ApolloClient { + return client; +} +// #enddocregion diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.ts b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.ts index 7dcadd5d64..f49a60e7b4 100755 --- a/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.ts +++ b/public/docs/_examples/heroes-graphql/ts/src/app/heroes.component.ts @@ -42,7 +42,7 @@ export class HeroesComponent implements OnInit { } ` }).subscribe((queryResult: ApolloQueryResult<{ heroes: Hero[] }>) => { - this.heroes = queryResult.data.heroes; + this.heroes = queryResult.data.heroes.slice(); }); } // #enddocregion query-heroes diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-graphql.ts b/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-graphql.ts index 8d2fcd597c..4a8156fc42 100755 --- a/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-graphql.ts +++ b/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-graphql.ts @@ -9,43 +9,7 @@ import { makeExecutableSchema } from 'graphql-tools'; import { execute } from 'graphql'; // #enddocregion import-graphql // #docregion graphql-schema -const typeDefinitions = ` -# the model -type Hero { - id: Int! - name: String! -} - -# The schema allows the following queries: -type Query { - heroes(search: String): [Hero] - - hero(heroId: Int!): Hero -} - -# This schema allows the following mutation: -type Mutation { - updateHero ( - id: Int! - name: String! - ): Hero - - addHero ( - heroName: String! - ): Hero - - deleteHero ( - id: Int! - ): Hero -} - -# Tell the server which types represent the root query and root mutation types. -# By convention, they are called RootQuery and RootMutation. -schema { - query: Query - mutation: Mutation -} -`; +import { typeDefinitions } from './schema'; // #enddocregion graphql-schema // #docregion heroes-array let heroes = [ diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/mockedNetworkInterface.ts b/public/docs/_examples/heroes-graphql/ts/src/app/mockedNetworkInterface.ts new file mode 100644 index 0000000000..d472d5f71d --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/mockedNetworkInterface.ts @@ -0,0 +1,17 @@ +// #docregion +// #docregion imports +import { + makeExecutableSchema, + addMockFunctionsToSchema +} from 'graphql-tools'; +import { mockNetworkInterfaceWithSchema } from 'apollo-test-utils'; +import { typeDefinitions } from './schema'; +// #enddocregion imports + +// #docregion create-interface +const schema = makeExecutableSchema({ + typeDefs: typeDefinitions +}); +addMockFunctionsToSchema({ schema }); +export const mockNetworkInterface = mockNetworkInterfaceWithSchema({ schema }); +// #enddocregion create-interface diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/schema.ts b/public/docs/_examples/heroes-graphql/ts/src/app/schema.ts new file mode 100644 index 0000000000..935d1f2b62 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/schema.ts @@ -0,0 +1,38 @@ +// #docregion +export const typeDefinitions = ` +# the model +type Hero { + id: Int! + name: String! +} + +# The schema allows the following queries: +type Query { + heroes(search: String): [Hero] + + hero(heroId: Int!): Hero +} + +# This schema allows the following mutation: +type Mutation { + updateHero ( + id: Int! + name: String! + ): Hero + + addHero ( + heroName: String! + ): Hero + + deleteHero ( + id: Int! + ): Hero +} + +# Tell the server which types represent the root query and root mutation types. +# By convention, they are called RootQuery and RootMutation. +schema { + query: Query + mutation: Mutation +} +`; \ No newline at end of file diff --git a/public/docs/_examples/heroes-graphql/ts/src/systemjs.config.extras.js b/public/docs/_examples/heroes-graphql/ts/src/systemjs.config.extras.js index c59e015378..0cb9d58fdb 100755 --- a/public/docs/_examples/heroes-graphql/ts/src/systemjs.config.extras.js +++ b/public/docs/_examples/heroes-graphql/ts/src/systemjs.config.extras.js @@ -18,6 +18,9 @@ System.config({ 'redux': 'npm:redux/dist/redux.min.js', // #enddocregion systemjs-apollo-client-map + // #docregion systemjs-apollo-test-utils-map + 'apollo-test-utils': 'npm:apollo-test-utils', + // #docregion systemjs-graphql-server-map 'graphql': 'npm:graphql', 'graphql-tools': 'npm:graphql-tools', @@ -27,6 +30,7 @@ System.config({ 'iterall': 'npm:iterall', 'lodash': 'npm:lodash' // #enddocregion systemjs-graphql-server-map + // #enddocregion systemjs-apollo-test-utils-map }, packages: { @@ -41,6 +45,9 @@ System.config({ }, // #enddocregion systemjs-apollo-client-packages + // #docregion systemjs-apollo-test-utils-packages + 'apollo-test-utils': { main: '/dist/src/index.js', defaultExtension: 'js' }, + // #docregion systemjs-graphql-server-packages 'graphql': { main: './index.js', @@ -64,5 +71,6 @@ System.config({ 'iterall': { main: './index.js', defaultExtension: 'js' }, 'lodash': { main: './index.js', defaultExtension: 'js' } // #enddocregion systemjs-graphql-server-packages + // #enddocregion systemjs-apollo-test-utils-packages } }); diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index 54e4d8ef4b..a622693ed1 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -27,7 +27,8 @@ "@angular/upgrade": "~4.0.0", "angular-in-memory-web-api": "~0.3.1", "apollo-angular": "^0.12.0", - "apollo-client": "1.0.0-rc.5", + "apollo-client": "^1.0.0-rc.5", + "apollo-test-utils": "^0.2.1", "core-js": "^2.4.1", "graphql": "^0.9.1", "graphql-subscriptions": "^0.3.1", From 76f79f29500b20c01bcec8be1e03b6fc314d8ee4 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 00:14:47 +0100 Subject: [PATCH 05/16] docs(graphql-cookbook): Add Appendix about mocking a server --- public/docs/ts/latest/cookbook/graphql.jade | 124 +++++++++++++++++--- 1 file changed, 105 insertions(+), 19 deletions(-) diff --git a/public/docs/ts/latest/cookbook/graphql.jade b/public/docs/ts/latest/cookbook/graphql.jade index b9aed7d337..a2477441ed 100644 --- a/public/docs/ts/latest/cookbook/graphql.jade +++ b/public/docs/ts/latest/cookbook/graphql.jade @@ -27,7 +27,9 @@ include ../_util-fns - [Performing a mutation](#mutation) - - [Appendix: Setting up a GraphQL server](#server) + - [Appendix 1: Mocking a GraphQL server](#mock-server) + + - [Appendix 2: Setting up a GraphQL server](#server) - [Further resources](#resources) @@ -224,7 +226,9 @@ a#http-heroes The full documentation can be found on the [Apollo Client website](http://dev.apollodata.com/). :marked - The starting point for the app is the [Tour of Heroes tutorial](https://github.com/Urigo/quickstart/archive/graphql-start.zip) app at its end state. + The starting point for the app is the Tour of Heroes tutorial app at its end state. + + **Download the **. This guide shows you how to migrate that app from REST to GraphQL. @@ -253,6 +257,19 @@ code-example(language="sh" class="code-shell"). +makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-apollo-client-packages', 'under packages: { (excerpt)') +:marked + Because you also have a running server on your app with more dependencies, you will need to add additional configurations to + `systemjs.config.js` as well. + + Add the following configuration to your `systemjs.config.js` file under the `map` key: + ++makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-graphql-server-map', 'under map: { (excerpt)') + +:marked + and the following configuration to your `systemjs.config.js` file under the `packages` key: + ++makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-graphql-server-packages', 'under packages: { (excerpt)') + :marked Next, initialize the client by creating a new file called `client.ts` and pasting in the following code: @@ -268,7 +285,7 @@ code-example(language="sh" class="code-shell"). .l-sub-section :marked ### To use a different URI for the Apollo Client - For this cookbook we would use the default `/graphql` endpoint, + For this cookbook you would use the default `/graphql` endpoint, but it's good to know it is possible to change those settings. To change the [settings](http://dev.apollodata.com/core/apollo-client-api.html#ApolloClient\.constructor) of `ApolloClient`, call its constructor with different parameters. @@ -277,15 +294,18 @@ code-example(language="sh" class="code-shell"). :marked Usually you need to query an existing server. The server for this guide is based on the [Tour of Heroes](ts/latest/tutorial/) app. - The starter app already has an in-memory GraphQL server prepared. - + The starter app () already has an in-memory GraphQL server prepared. + Now all that's left is to connect the in-memory server to the Apollo Client configuration by importing `networkInterface` and adding it to the `client` constant in `client.ts`. +makeExample('heroes-graphql/ts/src/app/client.ts', '', 'client.ts') .l-sub-section :marked In order to learn how to create the GraphQL server for this example, follow the instructions on - [Appendix: Setting up a GraphQL server](#server). + [Appendix 2: Setting up a GraphQL server](#server). + + Another important ability of Apollo is to create a mock server in one line of code based on a GraphQL schema. + Check out the [Appendix 1: Mocking a GraphQL server](#mock-server) to learn about that as well. :marked After initializing the Apollo Client, import the `ApolloModule` and `getClient` @@ -297,7 +317,7 @@ code-example(language="sh" class="code-shell"). is an initialization function that accepts the Apollo configuration you created earlier as an argument and creates a new Apollo instance for the app. -+makeExample('heroes-graphql/ts/src/app/app.module.ts', 'apollo-ngmodule', 'app.module.ts (excerpt)') ++makeExample('heroes-graphql/ts/src/app/app.module.1.ts', 'apollo-ngmodule', 'app.module.ts (excerpt)') :marked Now Apollo is initialized and ready for use in the app. @@ -317,10 +337,17 @@ code-example(language="sh" class="code-shell"). Here is the schema the Tour of Heroes server in the app use: -+makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'graphql-schema', 'Tour of heroes schema') ++makeExample('heroes-graphql/ts/src/app/schema.ts', '', 'schema.ts') + +:marked + Once you have a server, which is prepared already in this app, to start querying data. + + You will convert the `heroes.component` from quering the data from the REST endpoint to the GraphQL server. + First remove all references of the exisitng `HeroService`: ++makeExample('heroes-graphql-starter/ts/src/app/heroes.component.1.ts', '', 'heroes.component.ts') :marked - Once you have a server, which is prepared already in this app, to start querying data, begin by importing `Apollo` into `heroes.component.ts`, + Now begin adding Apollo importing `Apollo` into `heroes.component.ts`, and injecting it into the constructor: +makeExample('heroes-graphql/ts/src/app/heroes.component.ts', 'import-apollo', 'heroes.component.ts (excerpt)') +makeExample('heroes-graphql/ts/src/app/heroes.component.ts', 'inject-apollo', 'heroes.component.ts (excerpt)') @@ -350,12 +377,12 @@ code-example(language="sh" class="code-shell"). For more information on GraphQL queries, see the GraphQL documentation on [Queries and Mutations](http://graphql.org/learn/queries/). :marked - Next, update the template so it displays the results of the query. + Now, the same template that worked before will still displays the results of the new query: +makeExample('heroes-graphql/ts/src/app/heroes.component.1.html', 'render-heroes', 'heroes.component.html') :marked - At this point, if you have a running [GraphQL server](#server), the browser displays the - fetched data. + At this point, if you go to the `heroes` tab, and you have a running [GraphQL server](#server), + the browser displays the fetched data. .l-main-section @@ -405,10 +432,10 @@ code-example(language="json"). documentation](http://graphql.org/learn/queries/#mutations) at [GraphQL.org](http://graphql.org). :marked - To use a mutation, first update the template with a function to add a hero: + To use a mutation, you can use the same existing template with a function to add a hero: +makeExample('heroes-graphql/ts/src/app/heroes.component.html', 'add', 'heroes.component.html') :marked - In the component class, create the `add()` function. It expects a name argument of type `string` + In the component class, there is already an `add()` function. It expects a name argument of type `string` and is `void` because it returns nothing. +makeExample('heroes-graphql/ts/src/app/heroes.component.1.ts', 'add', 'heroes.component.ts') :marked @@ -444,10 +471,65 @@ code-example(language="json"). figure.image-display img(src='/resources/images/cookbooks/heroes-graphql/heroes- graphql-mutation.gif' alt="Heroes GraphQL Mutation") +.l-main-section + +:marked + ## Appendix 1: Mocking a GraphQL server + + When writing a GraphQL Angular app, you are quering a shared Schema. + Both the client and the server agree on a single schema that describes the data the client can query and the actions it can perform + on the server. + + Once you have that schema, there is no need for an actual server and you can mock your server with one line of code. + That mocking is good for day to day development as well as for automatic tests for your Angular app. + + Let's create the schema that is based on the [Tour of Heroes](ts/latest/tutorial/) app. + + Create a file called `schema.ts` in the `app` directory and paste in the following schema: ++makeExample('heroes-graphql/ts/src/app/schema.ts', '', 'schema.ts') +:marked + Now that you have the schema, let's mock the server so you would be able to use actual data in your app. + First install the `Apollo Test Utils` library: + +code-example(language="sh" class="code-shell"). + npm install apollo-test-utils --save + +.l-sub-section + :marked + This example uses `system.js` so you need to also add the configuration to it. + With other build systems, or when running on Node, the following process will be different and + maybe easier. + +:marked + Add the following configuration to your `systemjs.config.js` file under the `map` key: + ++makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-apollo-test-utils-map', 'under map: { (excerpt)') + +:marked + and the following configuration to your `systemjs.config.js` file under the `packages` key: + ++makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-apollo-test-utils-packages', 'under packages: { (excerpt)') +:marked + Now you need to create a mocked network interface that will use `apollo-test-utils` and the schema you created. + + Create a file called `mockedNetworkInterface.ts` and import the schema and the tools to create a mock network interface: ++makeExample('heroes-graphql/ts/src/app/mockedNetworkInterface.ts', 'imports', 'imports') +:marked + Now you need to make the schema executable, add the mocking functions to it, create the network interface and export it: ++makeExample('heroes-graphql/ts/src/app/mockedNetworkInterface.ts', 'create-interface', 'Create Network Interface') +:marked + Now all you need to do is use that network interface in your Apollo Client instead of your regular network interface: ++makeExample('heroes-graphql/ts/src/app/client.3.ts', 'import-and-use', 'Use Network Interface') + +:marked + Now every time you will query Apollo Client it will return a mocked data for your client. + + To dive deeper to more advanced mocking, check out the [Apollo-Test-Utils repository](https://github.com/apollographql/apollo-test-utils). + .l-main-section :marked - ## Appendix: Setting up a GraphQL server + ## Appendix 2: Setting up a GraphQL server This example shows how to run a GraphQL in the browser but running a GraphQL server on Node.js or in the browser is very similar. @@ -466,7 +548,7 @@ figure.image-display Additionally, there are a few GraphQL backend-as-a-service platforms available, similar to Firebase, but based on the GraphQL API spec. - For help on getting up and running, see [Scaphold](https://www.scaphold.io/) and [Graphcool](https://www.graph.cool/). + For help on getting up and running, see [Scaphold.io](https://www.scaphold.io/) and [Graph.Cool](https://www.graph.cool/). :marked In order to create a GraphQL schema, you need the `graphql-tools` library. @@ -499,10 +581,10 @@ code-example(language="sh" class="code-shell"). +makeExample('heroes-graphql/ts/src/systemjs.config.extras.js', 'systemjs-graphql-server-packages', 'under packages: { (excerpt)') :marked - Next, create a file called `in-memory-graphql.ts` in the `app` directory + Next, create a file called `schema.ts` in the `app` directory and paste in the following schema: -+makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'graphql-schema', 'in-memory-graphql.ts') ++makeExample('heroes-graphql/ts/src/app/schema.ts', '', 'schema.ts') :marked The schema starts with a represention of the model of data the server exposes. Then the schema specifies what queries are allowed on that data, followed by @@ -514,7 +596,10 @@ code-example(language="sh" class="code-shell"). While the schema includes the major points covered in this cookbook, you can read more in the [GraphQL.org Introduction to GraphQL](http://graphql.org/learn/). :marked - Now, create your in-memory data: + Now, create another file called `in-memory-graphql.ts` and import the schema into it: ++makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'graphql-schema', 'in-memory-graphql.ts') +:marked + next, create your in-memory data: +makeExample('heroes-graphql/ts/src/app/in-memory-graphql.ts', 'heroes-array', 'in-memory-graphql.ts (excerpt)') :marked The next step is writing a server that _resolves_ @@ -605,6 +690,7 @@ code-example(language="sh" class="code-shell"). - What is GraphQL and why it can benefit Angular developers. - How to create a basic GraphQL query. - How to create a basic GraphQL mutation. + - How to mock a GraphQL server. - How to build a GraphQL server. - Resources to dive deeper. From e562ba8893cb223cfbff8785341111423eb116d8 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 00:30:48 +0100 Subject: [PATCH 06/16] docs(graphql-cookbook): Fix @kapunahelewong review --- public/docs/ts/latest/cookbook/graphql.jade | 34 +++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/public/docs/ts/latest/cookbook/graphql.jade b/public/docs/ts/latest/cookbook/graphql.jade index a2477441ed..546fa88ec6 100644 --- a/public/docs/ts/latest/cookbook/graphql.jade +++ b/public/docs/ts/latest/cookbook/graphql.jade @@ -6,10 +6,10 @@ include ../_util-fns .l-sub-section :marked - GraphQL is a replacement or enhancement for REST and can be used in conjunction with it. + The GraphQL interface is a replacement or enhancement for REST and can be used in conjunction with it. :marked - GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools. + It provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools. @@ -43,18 +43,18 @@ include ../_util-fns :marked ## What is GraphQL? - GraphQL is an API query language, helping your Angular app: + GraphQL is an API query language, that helps your Angular app do the following: - Fetch exactly the information it needs from the server. - Add type safety to your API. - Merge multiple dependencies into one single response from the server. - Handle server data dependency in a component structure. - It’s also important to understand that: + It’s also important to understand these key points: - **GraphQL is not a data source**. The GraphQL runtime works on top of any data source—SQL, - NoSql, REST, Queues, .NET servers, Java servers or any other technology or data source. - - GraphQL solves the need of sending multiple requests for multiple resources to the server and + NoSql, REST, Queues, .NET servers, Java servers, or any other technology or data source. + - GraphQL solves the need of sending multiple requests to the server for different resources and then running complex joins on the client—without the need to create a custom endpoint like REST does. - The GraphQL specification also includes protocols for real-time push updates from the server to the client. @@ -67,8 +67,8 @@ include ../_util-fns .l-sub-section :marked - For a summary of this section, see [Faster modern apps with Angular and GraphQL](https://www.youtube.com/watch?v=Xx39bv-5ojA&t=1s) - presented by [Jeff Cross](https://twitter.com/jeffbcross) and [Uri Goldshtein](https://twitter.com/UriGoldshtein). + For a summary of this section, see the following [video](https://www.youtube.com/watch?v=Xx39bv-5ojA&t=1s) + by [Jeff Cross](https://twitter.com/jeffbcross) and [Uri Goldshtein](https://twitter.com/UriGoldshtein). iframe(type='text/html' width='560' height='315' src='https://www.youtube.com/embed/Xx39bv-5ojA' @@ -86,13 +86,15 @@ iframe(type='text/html' width='560' height='315' 3. Fetching data at the parent component and passing it down the component tree. While these solutions are valid, they have their limitations. + + The following three sections cover each of these in turn. #### Using the HTTP service in the Component There are two potential issues with this approach: 1. Multiple redundant requests; when you render multiple components, - for example, through `ngFor` with many components, each sends its own + such as an `ngFor` with many components, each sends its own HTTP call. 2. Inconsistent data; if two components fetch the same data but in different requests, the data might change and not be consistent across the app. @@ -118,7 +120,7 @@ a#http-heroes :marked #### Fetching data at the parent component and passing it down the component tree - Consider an example of the second possibility: + Consider an example of the third possibility: +makeExample('toh-4/ts/src/app/hero.ts','','Declare the API type') +makeExample('toh-4/ts/src/app/hero-detail.component.ts','declaring-conponent-input','Declare the input') @@ -127,7 +129,7 @@ a#http-heroes :marked This works until you change the API of the component, which means you need to change its parent components _all the way to the top_. - Again, this creates a dependency. This time it is with the child component + Again, this creates a dependency. This time the dependency is with the child component all the way up to the fetching component and _all the components in between_. @@ -145,12 +147,12 @@ a#http-heroes Now, a single component contains all of its own data dependency changes. :marked - The `watchQuery` function tells the Apollo Client what data - this component needs. The Apollo Client then returns the + The `watchQuery` function tells the Apollo Client, the GraphQL client that lets you use GraphQL in your Angular app, + what data this component needs. The Apollo Client then returns the necessary data to the component as an Observable. For example, adding an `age` field to the app is simple because you only change the component (you cover - this syntax [later](#querying) in the cookbook) And then modify the template accordingly: + this syntax [later](#querying) in the cookbook) and then modify the template accordingly: +makeExample('heroes-graphql/ts/src/app/hero-detail.component.1.ts','graphql-query-new-field','Adding an `age` field to the component') +makeExample('heroes-graphql/ts/src/app/hero-detail.component.1.html','template-new-field','Adding an `age` field to the template') @@ -169,7 +171,7 @@ a#http-heroes calls `getHeroes` to fetch all heroes and their information. :marked - That might work for simple cases but the problem here is that `getHeroes` might fetch + That might work for simple cases but but as your app grows `getHeroes` might fetch more information than the app really needs for each hero. This approach also creates a dependency between the server endpoint and the UI component—if you change or limit the amount of information you send on the @@ -196,7 +198,7 @@ a#http-heroes and migrate gradually from them. :marked - ### Typed API, tooling and auto documentation + ### Typed API, tooling and, auto documentation Just as TypeScript provides tooling to increase productivity and best practices, GraphQL provides a similar solution for working with APIs. From 66c2e78a7f558061e570623642afd7fccede2b75 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 01:35:47 +0100 Subject: [PATCH 07/16] docs(graphql-cookbook): Update headers for tests --- public/docs/_examples/heroes-graphql-starter/ts/aot/index.html | 2 +- public/docs/_examples/heroes-graphql-starter/ts/src/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/docs/_examples/heroes-graphql-starter/ts/aot/index.html b/public/docs/_examples/heroes-graphql-starter/ts/aot/index.html index cb8ecc4461..b80b8d4d4c 100644 --- a/public/docs/_examples/heroes-graphql-starter/ts/aot/index.html +++ b/public/docs/_examples/heroes-graphql-starter/ts/aot/index.html @@ -3,7 +3,7 @@ - Angular Tour of Heroes + Angular Tour of Heroes - GraphQL Starter diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/index.html b/public/docs/_examples/heroes-graphql-starter/ts/src/index.html index 18977969bb..325a9418d7 100644 --- a/public/docs/_examples/heroes-graphql-starter/ts/src/index.html +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/index.html @@ -3,7 +3,7 @@ - Angular Tour of Heroes + Angular Tour of Heroes - GraphQL Starter From 16f9c855e343041d6b3732f422aa7b59438af11b Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 02:53:39 +0100 Subject: [PATCH 08/16] docs(graphql-cookbook): Fix inner property value --- public/docs/_examples/heroes-graphql-starter/ts/plnkr.json | 2 +- .../heroes-graphql-starter/ts/src/app/app.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json b/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json index d355bc9ff2..cf2d3d5174 100644 --- a/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json +++ b/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json @@ -1,5 +1,5 @@ { - "description": "Tour of Heroes: Part 6", + "description": "Tour of Heroes - GraphQL Starter", "basePath": "src/", "files":[ "!**/*.d.ts", diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.ts index a9fe05a9a8..f947f02698 100644 --- a/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.ts +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/app.component.ts @@ -15,5 +15,5 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.css'] }) export class AppComponent { - title = 'Tour of Heroes'; + title = 'Tour of Heroes - GraphQL Starter'; } From 045403019ad890b62566f1f8a14a7c1d2f4a1788 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 12:41:28 +0100 Subject: [PATCH 09/16] docs(graphql-cookbook): Fix lint errors --- .../docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts | 2 +- public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts | 2 +- .../heroes-graphql/ts/src/app/mockedNetworkInterface.ts | 2 +- public/docs/_examples/heroes-graphql/ts/src/app/schema.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts b/public/docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts index 935d1f2b62..0baf8da308 100644 --- a/public/docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/app/schema.ts @@ -35,4 +35,4 @@ schema { query: Query mutation: Mutation } -`; \ No newline at end of file +`; diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts b/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts index 953edf6b38..5690f75760 100644 --- a/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts +++ b/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts @@ -51,4 +51,4 @@ import { HeroSearchComponent } from './hero-search.component'; // #enddocregion search bootstrap: [ AppComponent ] }) -export class AppModule { } \ No newline at end of file +export class AppModule { } diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/mockedNetworkInterface.ts b/public/docs/_examples/heroes-graphql/ts/src/app/mockedNetworkInterface.ts index d472d5f71d..291328e919 100644 --- a/public/docs/_examples/heroes-graphql/ts/src/app/mockedNetworkInterface.ts +++ b/public/docs/_examples/heroes-graphql/ts/src/app/mockedNetworkInterface.ts @@ -1,6 +1,6 @@ // #docregion // #docregion imports -import { +import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools'; diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/schema.ts b/public/docs/_examples/heroes-graphql/ts/src/app/schema.ts index 935d1f2b62..0baf8da308 100644 --- a/public/docs/_examples/heroes-graphql/ts/src/app/schema.ts +++ b/public/docs/_examples/heroes-graphql/ts/src/app/schema.ts @@ -35,4 +35,4 @@ schema { query: Query mutation: Mutation } -`; \ No newline at end of file +`; From 7158650e64c817bf99578eb977d6d45302dff151 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 13:03:42 +0100 Subject: [PATCH 10/16] docs(graphql-cookbook): Add the old in-memory-data just so the file will look nice --- .../heroes-graphql/ts/src/app/app.module.1.ts | 2 ++ .../ts/src/app/in-memory-data.service.ts | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 public/docs/_examples/heroes-graphql/ts/src/app/in-memory-data.service.ts diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts b/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts index 5690f75760..68cd5a9284 100644 --- a/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts +++ b/public/docs/_examples/heroes-graphql/ts/src/app/app.module.1.ts @@ -10,6 +10,8 @@ import { HttpModule } from '@angular/http'; import { AppRoutingModule } from './app-routing.module'; // #enddocregion v1 +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; +import { InMemoryDataService } from './in-memory-data.service'; // #docregion import-apollo import { ApolloModule } from 'apollo-angular'; diff --git a/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-data.service.ts b/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-data.service.ts new file mode 100644 index 0000000000..c915955e22 --- /dev/null +++ b/public/docs/_examples/heroes-graphql/ts/src/app/in-memory-data.service.ts @@ -0,0 +1,19 @@ +// #docregion , init +import { InMemoryDbService } from 'angular-in-memory-web-api'; +export class InMemoryDataService implements InMemoryDbService { + createDb() { + let heroes = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} + ]; + return {heroes}; + } +} From 8609ea40d22940f2bc6cc8eb5bd556992fbc2a9d Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 14:17:30 +0100 Subject: [PATCH 11/16] docs(graphql-cookbook): Update Apollo Client --- public/docs/_examples/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index a622693ed1..bd1127787a 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -27,7 +27,7 @@ "@angular/upgrade": "~4.0.0", "angular-in-memory-web-api": "~0.3.1", "apollo-angular": "^0.12.0", - "apollo-client": "^1.0.0-rc.5", + "apollo-client": "^1.0.0-rc.6", "apollo-test-utils": "^0.2.1", "core-js": "^2.4.1", "graphql": "^0.9.1", From 52b0f059eb3f4739f4601a7d7b8785c85cbb4103 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 14:17:59 +0100 Subject: [PATCH 12/16] docs(graphql-cookbook): Add the GraphQL tag --- public/docs/_examples/heroes-graphql-starter/ts/plnkr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json b/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json index cf2d3d5174..037d93c3f3 100644 --- a/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json +++ b/public/docs/_examples/heroes-graphql-starter/ts/plnkr.json @@ -6,5 +6,5 @@ "!**/*.js", "!**/*.[1,2].*" ], - "tags": ["tutorial", "tour", "heroes", "http"] + "tags": ["tutorial", "tour", "heroes", "http", "GraphQL"] } From 11b4f08f606e5f77cd25aceda2f40bfcd38206a9 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 14:21:35 +0100 Subject: [PATCH 13/16] docs(graphql-cookbook): Add dist files to AOT bundle --- .../_examples/heroes-graphql-starter/ts/.gitignore | 2 ++ .../heroes-graphql-starter/ts/copy-dist-files.js | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/copy-dist-files.js diff --git a/public/docs/_examples/heroes-graphql-starter/ts/.gitignore b/public/docs/_examples/heroes-graphql-starter/ts/.gitignore index 804879d44a..c66c617d1f 100644 --- a/public/docs/_examples/heroes-graphql-starter/ts/.gitignore +++ b/public/docs/_examples/heroes-graphql-starter/ts/.gitignore @@ -6,3 +6,5 @@ aot/**/*.ts dist !app/tsconfig.json !rollup-config.js +!copy-dist-files.js +!systemjs.config.extras.js diff --git a/public/docs/_examples/heroes-graphql-starter/ts/copy-dist-files.js b/public/docs/_examples/heroes-graphql-starter/ts/copy-dist-files.js new file mode 100644 index 0000000000..a451cbd633 --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/copy-dist-files.js @@ -0,0 +1,12 @@ +// #docregion +var fs = require('fs'); +var resources = [ + 'node_modules/core-js/client/shim.min.js', + 'node_modules/zone.js/dist/zone.min.js', + 'src/styles.css' +]; +resources.map(function(f) { + var path = f.split('/'); + var t = 'aot/' + path[path.length-1]; + fs.createReadStream(f).pipe(fs.createWriteStream(t)); +}); \ No newline at end of file From 916a73492fcd33c3850cf83782ec381e4af171c9 Mon Sep 17 00:00:00 2001 From: urigo Date: Wed, 22 Mar 2017 14:22:10 +0100 Subject: [PATCH 14/16] docs(graphql-cookbook): Add extra systemjs config to starter --- .../heroes-graphql-starter/ts/src/index.html | 1 + .../ts/src/systemjs.config.extras.js | 76 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 public/docs/_examples/heroes-graphql-starter/ts/src/systemjs.config.extras.js diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/index.html b/public/docs/_examples/heroes-graphql-starter/ts/src/index.html index 325a9418d7..144c9e105c 100644 --- a/public/docs/_examples/heroes-graphql-starter/ts/src/index.html +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/index.html @@ -15,6 +15,7 @@ + diff --git a/public/docs/_examples/heroes-graphql-starter/ts/src/systemjs.config.extras.js b/public/docs/_examples/heroes-graphql-starter/ts/src/systemjs.config.extras.js new file mode 100644 index 0000000000..0cb9d58fdb --- /dev/null +++ b/public/docs/_examples/heroes-graphql-starter/ts/src/systemjs.config.extras.js @@ -0,0 +1,76 @@ + +/** App specific SystemJS configuration */ +System.config({ + + map: { + + // #docregion systemjs-apollo-client-map + 'apollo-client': 'npm:apollo-client/apollo.umd.js', + 'apollo-client-rxjs': 'npm:apollo-client-rxjs/build/bundles/apollo-rxjs.umd.js', + 'apollo-angular': 'npm:apollo-angular/build/bundles/apollo.umd.js', + + 'whatwg-fetch': 'npm:whatwg-fetch', + + 'graphql-anywhere': 'npm:graphql-anywhere', + + 'graphql-tag': 'npm:graphql-tag', + 'symbol-observable': 'npm:symbol-observable', + 'redux': 'npm:redux/dist/redux.min.js', + // #enddocregion systemjs-apollo-client-map + + // #docregion systemjs-apollo-test-utils-map + 'apollo-test-utils': 'npm:apollo-test-utils', + + // #docregion systemjs-graphql-server-map + 'graphql': 'npm:graphql', + 'graphql-tools': 'npm:graphql-tools', + 'deprecated-decorator': 'npm:deprecated-decorator', + 'node-uuid': 'npm:node-uuid', + 'uuid': 'npm:uuid', + 'iterall': 'npm:iterall', + 'lodash': 'npm:lodash' + // #enddocregion systemjs-graphql-server-map + // #enddocregion systemjs-apollo-test-utils-map + }, + packages: { + + // #docregion systemjs-apollo-client-packages + 'whatwg-fetch': { main: './fetch.js', defaultExtension: 'js' }, + 'redux': { format: 'cjs', defaultExtension: 'js' }, + 'graphql-tag': { main: './index.js', defaultExtension: 'js' }, + 'symbol-observable': { main: './index.js', defaultExtension: 'js' }, + 'graphql-anywhere': { + main: '/lib/src/index.js', + defaultExtension: 'js' + }, + // #enddocregion systemjs-apollo-client-packages + + // #docregion systemjs-apollo-test-utils-packages + 'apollo-test-utils': { main: '/dist/src/index.js', defaultExtension: 'js' }, + + // #docregion systemjs-graphql-server-packages + 'graphql': { + main: './index.js', + defaultExtension: 'js', + map: { + './type': './type/index.js', + './language': './language/index.js', + './execution': './execution/index.js', + './validation': './validation/index.js', + './error': './error/index.js', + './utilities': './utilities/index.js' + }, + }, + 'graphql-tools': { + main: '/dist/index.js', + defaultExtension: 'js' + }, + 'deprecated-decorator': { main: '/bld/index.js', defaultExtension: 'js' }, + 'node-uuid': { main: './uuid.js', defaultExtension: 'js' }, + 'uuid': { main: './lib/rng-browser.js', defaultExtension: 'js' }, + 'iterall': { main: './index.js', defaultExtension: 'js' }, + 'lodash': { main: './index.js', defaultExtension: 'js' } + // #enddocregion systemjs-graphql-server-packages + // #enddocregion systemjs-apollo-test-utils-packages + } +}); From 851cf07b114cc16b8aa15997efd6a1dd9cb2c1d1 Mon Sep 17 00:00:00 2001 From: urigo Date: Sun, 26 Mar 2017 14:58:28 +0300 Subject: [PATCH 15/16] docs(graphql-cookbook): Update @types/lodash because we use new TypeScript now --- public/docs/_examples/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index bd1127787a..16241699fc 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -27,8 +27,8 @@ "@angular/upgrade": "~4.0.0", "angular-in-memory-web-api": "~0.3.1", "apollo-angular": "^0.12.0", - "apollo-client": "^1.0.0-rc.6", - "apollo-test-utils": "^0.2.1", + "apollo-client": "^1.0.0-rc.4", + "apollo-test-utils": "0.2.1", "core-js": "^2.4.1", "graphql": "^0.9.1", "graphql-subscriptions": "^0.3.1", @@ -52,7 +52,7 @@ "@types/graphql": "^0.8.6", "@types/isomorphic-fetch": "0.0.33", "@types/jasmine": "2.5.36", - "@types/lodash": "4.14.50", + "@types/lodash": "^4.14.58", "@types/node": "^6.0.45", "angular2-template-loader": "^0.6.0", "awesome-typescript-loader": "^3.0.4", From f85548a782c02ecca2cafa68c5e2481692cacb81 Mon Sep 17 00:00:00 2001 From: urigo Date: Sun, 26 Mar 2017 15:08:23 +0300 Subject: [PATCH 16/16] docs(graphql-cookbook): Update to latest Apollo-Client --- public/docs/_examples/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index 16241699fc..c323ed5811 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -27,8 +27,8 @@ "@angular/upgrade": "~4.0.0", "angular-in-memory-web-api": "~0.3.1", "apollo-angular": "^0.12.0", - "apollo-client": "^1.0.0-rc.4", - "apollo-test-utils": "0.2.1", + "apollo-client": "^1.0.0-rc.7", + "apollo-test-utils": "^0.2.2", "core-js": "^2.4.1", "graphql": "^0.9.1", "graphql-subscriptions": "^0.3.1",