Skip to content

Commit

Permalink
Fetch content by ID using REST API from CMS for preview
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuspontes committed Jan 24, 2022
1 parent f4abad3 commit 40fa516
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 8 deletions.
25 changes: 24 additions & 1 deletion packages/gatsby-plugin-cms/src/gatsby-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ import type {
import type { StoreCollection } from '@vtex/gatsby-source-vtex'

import { Barrier } from './utils/barrier'
import { fetchAllNodes as fetchAllRemoteNodes } from './node-api/cms/fetchNodes'
import {
fetchNodeById,
fetchAllNodes as fetchAllRemoteNodes,
} from './node-api/cms/fetchNodes'
import {
createSchemaCustomization as createCmsSchemaCustomization,
sourceNode as sourceCmsNode,
sourceRestNode,
} from './node-api/cms/sourceNode'
import { fetchAllNodes as fetchAllLocalNodes } from './node-api/cms/sourceLocalNodes'
import {
Expand All @@ -30,6 +34,7 @@ import type {
IClusterCollection,
IBrandCollection,
} from './native-types/blocks/collection'
import { PLUGIN } from './constants'

interface CMSContentType {
id: string
Expand Down Expand Up @@ -100,6 +105,9 @@ export const sourceNodes = async (
gatsbyApi: SourceNodesArgs,
options: Options
) => {
const { webhookBody }: any = gatsbyApi

// Fresh build. Let's source all data
// Warning: Do not source remote and local nodes in a different order since this
// is important for the local nodes not to overrider remote ones
const nodes = await Promise.all([
Expand All @@ -113,6 +121,21 @@ export const sourceNodes = async (
sourceCmsNode(gatsbyApi, node)
}

// Preview was triggered
if (webhookBody?.id && webhookBody.contentType) {
gatsbyApi.reporter.info(
`[${PLUGIN}]: Updating data from CMS: ${JSON.stringify(webhookBody)}`
)

const node = await fetchNodeById(gatsbyApi, options, webhookBody)

// Delete existing nodes
gatsbyApi.actions.deleteNode(gatsbyApi.getNode(node.id))

// Source the new node
sourceRestNode(gatsbyApi, node)
}

/**
* Add CMS overrides to StoreCollection Nodes
*/
Expand Down
66 changes: 64 additions & 2 deletions packages/gatsby-plugin-cms/src/node-api/cms/fetchNodes.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import type { ParentSpanPluginArgs } from 'gatsby'

import fetch from '../../utils/fetch'
import { fetch, fetchAPI } from '../../utils/fetch'
import { PLUGIN } from '../../constants'
import type { Options } from '../../gatsby-node'
import type { RelayPagination, RemotePageContent } from './types'
import type {
RelayPagination,
RemotePageContent,
RemoteRESTPageContent,
} from './types'

interface Query {
vtex: {
contents: RelayPagination<RemotePageContent>
}
}

const getApiUrl = ({ tenant, workspace }: Options) =>
`https://${workspace}--${tenant}.myvtex.com/_v/cms/api/faststore`

const LIST_PAGES_QUERY = `
query LIST_PAGES ($first: Int!, $after: String, $orderBy: VTEX_ContentsOrderInput, $filters: VTEX_ContentsFiltersInput) {
vtex {
Expand Down Expand Up @@ -173,3 +180,58 @@ export const fetchAllNodes = async (

return data
}

type ReleaseLocator = {
id: string
contentType: string
releaseId: string
}

type DraftLocator = {
id: string
contentType: string
versionId: string
}

const isReleaseLocator = (x: NodeLocator): x is ReleaseLocator =>
typeof (x as any).releaseId === 'string'

const isDraftLocator = (x: NodeLocator): x is DraftLocator =>
typeof (x as any).versionId === 'string'

export type NodeLocator = ReleaseLocator | DraftLocator

// Fetch the node on the REST API and transform it to the plugin
export const fetchNodeById = async (
gatsbyApi: ParentSpanPluginArgs,
options: Options,
locator: NodeLocator
) => {
const url = getApiUrl(options)

const activity = gatsbyApi.reporter.activityTimer(
`[${PLUGIN}]: fetching Node from remote`
)

activity.start()

const { id, contentType } = locator

const params = new URLSearchParams()

if (isReleaseLocator(locator)) {
params.set('releaseId', locator.releaseId)
}

if (isDraftLocator(locator)) {
params.set('versionId', locator.versionId)
}

const response = await fetchAPI<RemoteRESTPageContent>(
`${url}/${contentType}/${id}?${params.toString()}`
)

activity.end()

return response
}
40 changes: 37 additions & 3 deletions packages/gatsby-plugin-cms/src/node-api/cms/sourceNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ParentSpanPluginArgs } from 'gatsby'

import { PLUGIN } from '../../constants'
import type { TransformedContent } from './fetchNodes'
import type { PageContent } from './types'
import type { PageContent, RemoteRESTPageContent } from './types'

export const getTypeName = (name: string) =>
camelcase(['cms', name], { pascalCase: true })
Expand Down Expand Up @@ -43,7 +43,7 @@ export const sourceNode = (
gatsbyApi: ParentSpanPluginArgs,
node: TransformedContent
) => {
const extra = node.variant.configurationDataSets?.reduce(
const extraBlocks = node.variant.configurationDataSets?.reduce(
(acc, { name, configurations }) => ({
...acc,
[camelcase(name)]: configurations?.reduce(
Expand All @@ -58,7 +58,7 @@ export const sourceNode = (
id: gatsbyApi.createNodeId(nodeId(node)),
name: node.name,
sections: node.variant.sections,
...extra,
...extraBlocks,
} as PageContent

gatsbyApi.actions.createNode(
Expand All @@ -74,6 +74,40 @@ export const sourceNode = (
)
}

export const sourceRestNode = (
gatsbyApi: ParentSpanPluginArgs,
node: RemoteRESTPageContent
) => {
const sections = node.sections?.reduce(
(acc, section) => [
...acc,
{
name: section.name,
props: section.data,
},
],
[] as Array<{ name: string; props: any }>
)

const data = ({
...node,
sections,
id: gatsbyApi.createNodeId(`${getTypeName(node.type)}:${node.id}`),
} as unknown) as PageContent

gatsbyApi.actions.createNode(
{
...data,
internal: {
type: getTypeName(node.type),
content: JSON.stringify(data),
contentDigest: gatsbyApi.createContentDigest(data),
},
},
{ name: PLUGIN }
)
}

export const deleteNode = (
gatsbyApi: ParentSpanPluginArgs,
remoteNode: TransformedContent
Expand Down
16 changes: 16 additions & 0 deletions packages/gatsby-plugin-cms/src/node-api/cms/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,19 @@ export type PageContent = {
name: string
sections: Block[]
} & Record<string, Record<string, Block['props']>>

export type RemoteRESTPageContent = {
id: string
name: string
status: string
type: string
versionId: string
sections: Section[]
children?: string[]
parent?: string
} & Record<string, unknown>

export interface Section {
name: string
data: unknown
}
14 changes: 12 additions & 2 deletions packages/gatsby-plugin-cms/src/utils/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import unfetch from 'isomorphic-unfetch'
import retry from 'fetch-retry'

const fetch = (input: RequestInfo, init?: RequestInit) =>
export const fetch = (input: RequestInfo, init?: RequestInit) =>
retry(unfetch, {
retries: 3,
retryDelay: 500,
})(input, init)

export default fetch
export const fetchAPI = async <T>(input: RequestInfo, init?: RequestInit) => {
const response = await fetch(input, init)

if (response.ok) {
return response.json() as Promise<T>
}

console.error(await response.text())

throw new Error(`Error while fetching ${input}`)
}

0 comments on commit 40fa516

Please sign in to comment.