-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rfc/issue 115 build time data access (#269)
* graphql server working * apollo client connect to apollo server * connected header example using lit apollo * todo * todos * query and client + server refactor * schema refactoring * clean up console logging * alias all @greenwood/cli/data module imports * avoid paramater destructuring * graphql example in the header * multiple schemas * internal data sources documentation * shelf refactor and children query integration * refactor out ApolloQuery * ability to intercept client.query calls * basic semi-working implementation * remove extra config from server context * have puppeteer wait for graphql requests before returning content * fix and add test cases for apollo * merged resolvers not actually working * multiple queries support * everything working * todos * TODO tracking * fix fallback apollo client fetch handling * full test suite * cache json test cases * stablize test due to inconsistent data results ordering * clean up deps * todo cleanup * remove forced client call in SSG mode for client * represent graph through the schema * updated data docs * typos and grammer * typos and community link fixes
- Loading branch information
1 parent
b77ce09
commit babca10
Showing
37 changed files
with
1,890 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
const { ApolloClient } = require('apollo-client'); | ||
const createHttpLink = require('apollo-link-http').createHttpLink; | ||
const crypto = require('crypto'); | ||
const fetch = require('node-fetch'); | ||
const fs = require('fs-extra'); | ||
const { gql } = require('apollo-server'); | ||
const InMemoryCache = require('apollo-cache-inmemory').InMemoryCache; | ||
const path = require('path'); | ||
|
||
/* Extract cache server-side */ | ||
module.exports = async (req, context) => { | ||
|
||
return new Promise(async(resolve, reject) => { | ||
try { | ||
// TODO avoid having to duplicate / replay calls - #272 | ||
const client = await new ApolloClient({ | ||
link: createHttpLink({ | ||
uri: 'http://localhost:4000?q=internal', /* internal flag to prevent looping cache on request */ | ||
fetch | ||
}), | ||
cache: new InMemoryCache() | ||
}); | ||
|
||
/* Take the same query from request, and repeat the query for our server side cache */ | ||
const { query, variables } = req.body; | ||
|
||
let { data } = await client.query({ | ||
query: gql`${query}`, | ||
variables | ||
}); | ||
|
||
if (data) { | ||
const cache = JSON.stringify(client.extract()); | ||
const md5 = crypto.createHash('md5').update(cache).digest('hex'); | ||
|
||
/* Get the requests entire (full) route and rootRoute to use as reference for designated cache directory */ | ||
const { origin, referer } = req.headers; | ||
const fullRoute = referer.substring(origin.length, referer.length); | ||
const rootRoute = fullRoute.substring(0, fullRoute.substring(1, fullRoute.length).indexOf('/') + 1); | ||
const targetDir = path.join(context.publicDir, rootRoute); | ||
const targetFile = path.join(targetDir, `${md5}-cache.json`); | ||
|
||
await fs.mkdirs(targetDir, { recursive: true }); | ||
await fs.writeFile(path.join(targetFile), cache, 'utf8'); | ||
} | ||
resolve(); | ||
} catch (err) { | ||
console.error('create cache error', err); | ||
reject(err); | ||
} | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { ApolloClient } from 'apollo-client'; | ||
import { InMemoryCache } from 'apollo-cache-inmemory'; | ||
import { HttpLink } from 'apollo-link-http'; | ||
|
||
const APOLLO_STATE = window.__APOLLO_STATE__; // eslint-disable-line no-underscore-dangle | ||
const client = new ApolloClient({ | ||
cache: new InMemoryCache().restore(APOLLO_STATE), | ||
link: new HttpLink({ | ||
uri: 'http://localhost:4000' | ||
}) | ||
}); | ||
const backupQuery = client.query; | ||
|
||
client.query = (params) => { | ||
|
||
if (APOLLO_STATE) { | ||
// __APOLLO_STATE__ defined, in "SSG" mode... | ||
return fetch('./cache.json') | ||
.then(response => response.json()) | ||
.then((response) => { | ||
// mock client.query response | ||
return { | ||
data: new InMemoryCache().restore(response).readQuery(params) | ||
}; | ||
}); | ||
} else { | ||
// __APOLLO_STATE__ NOT defined, in "SPA" mode | ||
return backupQuery(params); | ||
} | ||
}; | ||
|
||
export default client; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
query($parent: String!) { | ||
children(parent: $parent) { | ||
id, | ||
title, | ||
link, | ||
filePath, | ||
fileName, | ||
template | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
query { | ||
graph { | ||
id, | ||
title, | ||
link, | ||
filePath, | ||
fileName, | ||
template | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
query { | ||
hello | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
query { | ||
navigation{ | ||
label, | ||
link | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
const { gql } = require('apollo-server-express'); | ||
|
||
const getDeriveMetaFromRoute = (route) => { | ||
// TODO hardcoded root / depth - #273 | ||
const root = route.split('/')[1] || ''; | ||
const label = root | ||
.replace('/', '') | ||
.replace('-', ' ') | ||
.split(' ') | ||
.map((word) => `${word.charAt(0).toUpperCase()}${word.substring(1)}`) | ||
.join(' '); | ||
|
||
return { | ||
label, | ||
root | ||
}; | ||
}; | ||
|
||
const getPagesFromGraph = async (root, query, context) => { | ||
const pages = []; | ||
const { graph } = context; | ||
|
||
graph | ||
.forEach((page) => { | ||
const { route, mdFile, fileName, template } = page; | ||
const id = page.label; | ||
const { label } = getDeriveMetaFromRoute(route); | ||
|
||
pages.push({ | ||
id, | ||
filePath: mdFile, | ||
fileName, | ||
template, | ||
title: label, | ||
link: route | ||
}); | ||
}); | ||
|
||
return pages; | ||
}; | ||
|
||
const getNavigationFromGraph = async (root, query, context) => { | ||
const navigation = {}; | ||
const { graph } = context; | ||
|
||
graph | ||
.forEach((page) => { | ||
const { route } = page; | ||
const { root, label } = getDeriveMetaFromRoute(route); | ||
|
||
if (root !== '' && !navigation[root]) { | ||
navigation[root] = { | ||
label, | ||
link: `/${root}/` | ||
}; | ||
} | ||
}); | ||
|
||
// TODO best format for users, hash map? #271 | ||
return Object.keys(navigation).map((key) => { | ||
return navigation[key]; | ||
}); | ||
}; | ||
|
||
const getChildrenFromParentRoute = async (root, query, context) => { | ||
const pages = []; | ||
const { parent } = query; | ||
const { graph } = context; | ||
|
||
graph | ||
.forEach((page) => { | ||
const { route, mdFile, fileName, template } = page; | ||
const root = route.split('/')[1]; | ||
|
||
if (root.indexOf(parent) >= 0) { | ||
const { label } = getDeriveMetaFromRoute(route); | ||
const id = page.label; | ||
|
||
pages.push({ | ||
id, | ||
filePath: mdFile, | ||
fileName, | ||
template, | ||
title: label, | ||
link: route | ||
}); | ||
} | ||
}); | ||
|
||
return pages; | ||
}; | ||
|
||
const graphTypeDefs = gql` | ||
type Page { | ||
id: String, | ||
filePath: String, | ||
fileName: String, | ||
template: String, | ||
link: String, | ||
title: String | ||
} | ||
type Navigation { | ||
label: String, | ||
link: String | ||
} | ||
type Query { | ||
graph: [Page] | ||
navigation: [Navigation] | ||
children(parent: String): [Page] | ||
} | ||
`; | ||
|
||
const graphResolvers = { | ||
Query: { | ||
graph: getPagesFromGraph, | ||
navigation: getNavigationFromGraph, | ||
children: getChildrenFromParentRoute | ||
} | ||
}; | ||
|
||
module.exports = { | ||
graphTypeDefs, | ||
graphResolvers | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
const { gql } = require('apollo-server'); | ||
|
||
const helloTypeDefs = gql` | ||
type HelloQuery { | ||
hello: String | ||
} | ||
`; | ||
|
||
const helloResolvers = { | ||
HelloQuery: { | ||
hello: () => 'Hello world!' | ||
} | ||
}; | ||
|
||
module.exports = { | ||
helloTypeDefs, | ||
helloResolvers | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// TODO merging resolvers not actually working, resolve as part of #21 or #270 | ||
const { makeExecutableSchema } = require('apollo-server-express'); | ||
const { helloTypeDefs, helloResolvers } = require('./hello'); | ||
const { graphTypeDefs, graphResolvers } = require('./graph'); | ||
|
||
const schema = makeExecutableSchema({ | ||
typeDefs: [ | ||
graphTypeDefs, | ||
helloTypeDefs | ||
], | ||
resolvers: Object.assign({}, | ||
graphResolvers, | ||
helloResolvers | ||
) | ||
}); | ||
|
||
module.exports = schema; |
Oops, something went wrong.