Note: For Polymer 1.x checkout branch 1.x
Polymer-Apollo
Examples
GitHunt-Polymer - An example of a client-side app built with Polymer and Apollo Client.
NEWS App - A news app built using polymer-apollo
Polymer Apollo Frontpage App - Polymer Apollo Hello World app
Polymer Apollo Meteor App - Github api app using polymer-apollo meteor and synthesis
Table of contents
- Installation
- Configuration
- Usage in components
- Queries
- Fragments
- Mutations
- Subscriptions
- Pagination with
fetchMore
Installation
npm install --save polymer-apollo apollo-client
Usage
Configuration
//config.js; // Create the apollo clientconst apolloClient = networkInterface: ;
Usage in components
//my-element.js// if you want the es5 compiled version use// import { PolymerApolloMixin } from 'polymer-apollo/es5';;; apolloClient PolymerElement static { return 'my-element' } { // Apollo specific options } ...);
You can access the apollo-client instance with this.$apollo.client
in all your polymer components.
Queries
In the apollo
object, add an attribute for each property you want to feed with the result of an Apollo query.
Simple query
Use gql
to write your GraphQL queries:
;
Put the gql query directly as the value:
{ return // Simple query that will update the 'hello' polymer property hello: gql`{hello}` ;}
Don't forget to initialize your property in your polymer component:
//my-element.js...properties : // Initialize your apollo data hello: String...
Server-side, add the corresponding schema and resolver:
const schema = `type Query { hello: String} schema { query: Query}`; const resolvers = Query: { return "Hello world!"; } ;
For more info, visit the apollo doc.
You can then use your property as usual in your polymer component:
<!--my-element.js--> Hello {{hello}}
Query with parameters
You can add variables (read parameters) to your gql
query by declaring query
and variables
in an object:
Options can be computed properties or static.
Initial values of variables should be given if options are computed, since polymer options wont be triggered if arguments are undefined, which maybe the case during first rendering.
eg
...static { return computedProp: type: Object computed: 'computeFn(prop1, prop2)' ;} { return query1: query: someQuery // watches prop1 and prop2 changes // you should either initialize values of prop1,prop2 == !undefined or // set an initial value to variables property variables: var1: 'blah' var2: 'blah blah' options: 'computedProp' ;} { return variables: var1: prop1 var2: prop2 + 10 ;}...
. In this graphql variables var1 and var2 change when the polymer properties prop1 and prop2 change (similar to computed feature);
...static { return computedProp: type: Object computed: 'computeFn(prop1, prop2)' ;}// Apollo-specific options { return // Query with parameters ping: // gql query query: gql`query PingMessage($message: String!) { ping(message: $message) }` options: 'computedProp' variables: message: '' ;} { return variables: message: ` ping...` ;}
In the above example you can use the apollo watchQuery
options in the property ping or in the computed function return, like:
forceFetch
fragments
returnPartialData
pollInterval
- ...
See the apollo doc for more details.
For example, you could add the forceFetch
apollo option like this:
static { return computedProp: type: Object computed: 'computeFn(prop1, prop2)' ;} { // Query with parameters return pingQuery: query: gql`query PingMessage($message: String!) { ping(message: $message) }` options: 'computedProp' variables: message: 'blah' skip: true // Additional options here. static. forceFetch: true ; } { // Additional options if added here becomes reactive return variables: message: prop1 skip: prop2 ;}
Don't forget to initialize your property in your polymer component.
//my-element.js...static { // Initialize your apollo data ping: String}...
Server-side, add the corresponding schema and resolver:
const schema = `type Query { ping(message: String!): String} schema { query: Query}`; const resolvers = Query: { return `Answering `; } ;
And then use it in your polymer component:
Ping {{ping}}
options
Options can be added in two ways - computed and static.
For computed options you may want to give initial values since
computing function is not invoked until all dependent properties are defined (!== undefined). So each dependent properties should have a default value defined in properties (or otherwise be initialized to a non-undefined value) to ensure the property is computed.
from polymer doc https://www.polymer-project.org/1.0/docs/devguide/observers#computed-properties
computed eg.
...static { return computedProp: type: Object computed: 'computeFn(prop1, prop2)' ;} { return // Query with parameters ping: query: gql`query PingMessage($message: String!) { ping(message: $message) }` options: 'computedProp' // Additional options here. static. forceFetch: true ; } { // Additional options if added here becomes reactive return variables: message: prop1 skip: prop2 ;}
static eg.
{ return // Query with parameters ping: query: gql`query PingMessage($message: String!) { ping(message: $message) }` options: variables: message: 'hai' skip: true // Additional options here. static. you can add skip here also forceFetch: true ;}
Advanced Options
Options
You can add these to options/directly to the ping property in the above example if you dont want them to be polymer reactive.
skip
Used to set the state of the query subscribtion. Check example below.loadingKey
will update the component data property you pass as the value. You should initialize this property tofalse
in properties. When the query is loading, this property will be set totrue
and as soon as it no longer is, the property will be set tofalse
.
Hooks
These are the available advanced options you can use:
error(error)
is a hook called when there are errors,error
being an Apollo error object with either agraphQLErrors
property or anetworkError
property.success(result)
is a hook called when query/subscription returns successfully. Note. result = { data, loading, networkStatus}watchLoading(isLoading)
is a hook called when the loading state of the query changes.
...static { return computedProp: type: Object computed: 'computeFn(prop1, prop2)' ;}// Apollo-specific options { return // Advanced query with parameters pingMessage: query: gql`query PingMessage($message: String!) { ping(message: $message) }` // Reactive parameters options: 'computedProp' // Loading state // loadingKey is the name of the data property // that will be unset when the query is loading // and set when it no longer is. loadingKey: 'loadingQueriesCount' // Error handling { console; } { console; // result is of the format { data, loading, networkStatus }; } // watchLoading will be called whenever the loading state changes { // isLoading is a boolean } ;} { return variables: message: ` ping...` skip: prop2 ;}
Refetch Query
Use $apollo.refetch(key);
// Apollo-specific options // 'tags' property of your polymer element tags: query: gql`query tagList { tags { id, label } }` { this$apollo;}
Reactive Query Example
Here is a reactive query example using polling:
...static { return computedProp: type: Object computed: 'computeFn(prop1, prop2)' ;}// Apollo-specific options { return // 'tags' property of your polymer element tags: query: gql`query tagList { tags { id, label } }` options: 'computedProp' ;} { return variables: var1: prop1 pollInterval: prop2 // ms ;}
Here is how the server-side looks like:
const schema = `type Tag { id: Int label: String} type Query { tags: [Tag]} schema { query: Query}`; // Fake word generator; // Let's generate some tagsvar id = 0;var tags = ;for let i = 0; i < 42; i++ ; { let t = id: id++ label ; tags; return t;} const resolvers = Query: { return tags; } ;
Skip query example
...static { return computedProp: type: Object computed: 'computeFn(prop1, prop2)' ;} // Apollo-specific options { return // 'tags' property of your polymer element tags: query: gql`query tagList { tags { id, label } }` options: 'computedProp' ;} { return variables: var1: prop1 skip: prop2 // Boolean ;}
Fragments
; const fragment = gql`fragment CommonFields on tags { id, label}`;
Embed the fragment in your query document directly with:
;// Apollo-specific optionsreturn // 'tags' property of your polymer element tags: query: gql`query tagList { tags: tags(rate: 0) { ...CommonFields }, besttags: tags(rate: 10) { ...CommonFields } } `
Mutations
Mutations are queries that changes your data state on your apollo server. For more info, visit the apollo doc.
{ // We save the user input in case of an error const newTag = thisnewTag; // We clear it early to give the UI a snappy feel thisnewTag = ''; // Call to the graphql mutation this$apollo; }}
Server-side:
const schema = `type Tag { id: Int label: String} type Query { tags: [Tag]} type Mutation { addTag(label: String!): Tag} schema { query: Query mutation: Mutation}`; // Fake word generator; // Let's generate some tagsvar id = 0;var tags = ;for let i = 0; i < 42; i++ ; { let t = id: id++ label ; tags; return t;} const resolvers = Query: { return tags; } Mutation: { console; return ; } ;
Subscriptions
To make enable the websocket-based subscription, a bit of additional setup is required:
;// New Imports;; // quick way to add the subscribe and unsubscribe functions to the network interfaceconst addGraphQLSubscriptions = Object; // Create the network interfaceconst networkInterface = ; // Create the subscription websocket clientconst wsClient = 'ws://localhost:3030'; // Extend the network interface with the subscription clientconst networkInterfaceWithSubscriptions = ; // Create the apollo client with the new network interfaceconst apolloClient = networkInterface: networkInterfaceWithSubscriptions; // Your app is now subscription-ready!
Use the $apollo.subscribe()
method to subscribe to a GraphQL subscription that will get killed automatically when the component is detached. To disable this feature set onReady = true. :
{ const subQuery = gql`subscription tags($type: String!) { tagAdded(type: $type) { id label type } }`; const observer = this$apollo; observer;}
You can declare subscriptions in the apollo
option with the subscribe
keyword:
static { return cityComputed: type: Object computed: 'getCity(city)' ;} { return // Subscriptions subscribe: // When a tag is added tags: query: gql`subscription tags($type: String!) { tagAdded(type: $type) { id label type } }` options: 'cityComputed' // Reactive variables // Success hook { console; // Let's update the local data thistags; } ;} { return variables: // This works just like regular queries // and will re-subscribe with the right variables // each time the values change type: city ;}
You can then access the subscription ObservableQuery
object with this.$apollo.subscriptions.<name>
.
fetchMore
Pagination with Use the fetchMore()
method on the query:
<template> <div> <h2>Pagination</h2> <div class="tag-list" hidden="{{!tagsPage}}"> <template is="dom-repeat" items="[[tagsPage.tags]]" as="tag"> <div class="tag-list-item"> tagid - taglabel - tagtype </div> </template> <div class="actions"> <paper-button hidden="{{!showMoreEnabled}}" on-tap="showMore">Show more</paper-button> </div> </div> </div></template> <script>;;; apolloClient PolymerElement static { return 'example-element' } static { return page: type: Number value: 0 pageSize: type: Number value: 10 showMoreEnabled: type: Number value: true } { return // Pages tagsPage: // GraphQL Query query: gql`query tagsPage ($page: Int!, $pageSize: Int!) { tagsPage(page: $page, size: $pageSize) { tags { id label type } hasMore } }` options: // Initial variables variables: page: 'page' pageSize: 'pageSize' ; } { thispage ++; // Fetch more data and transform the original result this$apolloqueriestagsPage; };</script>
Similar to fetchMore the following methods can be used. for queries $apollo.queries[name] for subscriptions $apollo.subscriptions[name]
- refetch()
- fetchMore()
- updateQuery()
- startPolling()
- stopPolling()
- subscribeToMore()
- currentResult()
- variables : an object containing variables used to get this result.
- loading : boolean, useful if you set notifyOnNetworkStatusChange to true in query options.
- networkStatus : the status of the request ,useful if you set notifyOnNetworkStatusChange to true in query options
Like it?
⭐️ this repo
Found a bug?
Raise an issue!
Contributors
Anthony Hinsinger (@atoy40)
Arun Kumar T K (@aruntk)
Edward Watson (@edge0701)