Skip to content

Commit

Permalink
Feat: API Extension (#1942)
Browse files Browse the repository at this point in the history
## What's the purpose of this pull request?

This PR groups all API Extensions related features.

[Doc
preview](https://faststore-site-git-api-extension-development-faststore.vercel.app/)

## starter.store Related PR

API Extension Example 
- vtex-sites/starter.store#199

---------

Signed-off-by: Arthur Andrade <[email protected]>
Co-authored-by: Guilherme Carvalho <[email protected]>
Co-authored-by: Arthur Andrade <[email protected]>
Co-authored-by: Beatriz Maselli <[email protected]>
Co-authored-by: vtexgithubbot <[email protected]>
Co-authored-by: Ícaro Azevedo <[email protected]>
Co-authored-by: Fanny Chien <[email protected]>
Co-authored-by: Lucas Feijó <[email protected]>
Co-authored-by: Gabriel Antiqueira <[email protected]>
Co-authored-by: Lucas Feijó <[email protected]>
Co-authored-by: Renata Motta <[email protected]>
Co-authored-by: Mariana Caetano Pereira <[email protected]>
Co-authored-by: Fanny Chien <[email protected]>
Co-authored-by: Whitney Hahn <[email protected]>
Co-authored-by: Fanny Chien <[email protected]>
Co-authored-by: Carolina Menezes <[email protected]>
Co-authored-by: Júlia Rabello <[email protected]>
Co-authored-by: Mariana-Caetano <[email protected]>
Co-authored-by: Ícaro Azevedo <[email protected]>
  • Loading branch information
19 people authored Oct 11, 2023
1 parent bfbb931 commit db3aa69
Show file tree
Hide file tree
Showing 112 changed files with 5,763 additions and 1,421 deletions.
24 changes: 24 additions & 0 deletions apps/site/components/ExtendableQueryTable/ExtendableQueryTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { PropsWithChildren } from 'react'

const ExtendableQueryTable = ({ children }: PropsWithChildren) => {
return (
<table className="nx-simple-table">
<thead>
<tr>
<th>Fragment</th>
<th>Side</th>
<th>Query operation</th>
<th>Page</th>
<th>Where is used</th>
<th>Return</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>{children}</tr>
</tbody>
</table>
)
}

export default ExtendableQueryTable
1 change: 1 addition & 0 deletions apps/site/components/ExtendableQueryTable/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ExtendableQueryTable } from "./ExtendableQueryTable"
10 changes: 5 additions & 5 deletions apps/site/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "site",
"version": "2.1.109",
"version": "2.2.0-alpha.13",
"author": "Emerson Laurentino @emersonlaurentino",
"license": "MIT",
"private": true,
Expand All @@ -10,9 +10,9 @@
"start": "next start"
},
"dependencies": {
"@faststore/api": "^2.1.107",
"@faststore/sdk": "^2.1.107",
"@faststore/ui": "^2.1.109",
"@faststore/api": "^2.2.0-alpha.13",
"@faststore/sdk": "^2.2.0-alpha.13",
"@faststore/ui": "^2.2.0-alpha.13",
"next": "13.0.7",
"nextra": "^2.8.0",
"nextra-theme-docs": "^2.8.0",
Expand All @@ -21,7 +21,7 @@
"sass": "^1.57.1"
},
"devDependencies": {
"@faststore/eslint-config": "^2.1.107",
"@faststore/eslint-config": "^2.2.0-alpha.13",
"@types/node": "^18.11.16",
"eslint": "7.32.0",
"react-docgen-typescript": "^2.2.2",
Expand Down
11 changes: 7 additions & 4 deletions apps/site/pages/docs/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,13 @@
"building-sections": {
"title": "Building and Customizing Sections"
},
"troubleshooting": "Troubleshooting",
"-- Reference --": {
"-- APIs and Reference --": {
"type": "separator",
"title": "Reference"
"title": "APIs and Reference"
},
"faststore-config-options": "Configuration options for faststore.config.js"
"faststore-api": "FastStore API",
"api-extensions": "API Extensions",

"faststore-config-options": "Configuration options for faststore.config.js",
"troubleshooting": "Troubleshooting"
}
123 changes: 123 additions & 0 deletions apps/site/pages/docs/api-extensions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
title: 'API Extensions'
sidebar_label: 'API Extensions'
---


<header>

# API extension

</header>

In this track, learn how to extend the FastStore API schema by adding new
data to the existing [queries](https://v1.faststore.dev/reference/api/queries).

While the [FastStore API](/docs/faststore-api) provides a [GraphQL schema for ecommerce](https://v1.faststore.dev/reference/api/queries) that covers a general use case,
some stores may need to access other, more specific, information.

Note that adding additional API endpoints to your storefront can potentially impact site performance, as already covered in the guide
[Best practices for fetching data](/docs/api-extensions#best-practices-for-fetching-data).
If you need to retrieve more data, you can achieve this by extending the FastStore API schema and incorporating new data into the existing [queries](https://v1.faststore.dev/reference/api/queries).

---

## Main concepts

<ul>
<li>
<details>
<summary><b>GraphQL Optimizations & types</b></summary>
<br />
GraphQL Optimizations are essential for optimizing your GraphQL server and TypeScript types. They provide benefits such as:

- Build-time generated mappings of declared queries
- Improved efficiency and security
- Enforcement of predefined operations

Without these optimizations, any modifications to the GraphQL schema, such as adding or removing fields from a query or altering a GraphQL type, won't be reflected in the store.

Additionally, GraphQL query optimizations update TypeScript types for the API to match schema changes seamlessly.
<br />
</details>
</li>

<li>
<details>
<summary><b>GraphQL Optimization automation</b></summary>
<br />
GraphQL optimizations are seamlessly executed, requiring no direct intervention from end developers.
They are automatically triggered every time you start a development server (`yarn dev`) or builds the store (`yarn build`).
Resolver changes are automatically and instantly visible, without the need for manual optimization generation.
<br />
</details>
</li>

<li>
<details>
<summary><b>Extendable queries</b></summary>
<br />
Extendable queries in FastStore's GraphQL API are predefined GraphQL queries that serve as a foundation for retrieving data from the API.
These queries allow you to add or modify fields within the query to tailor the data retrieval process to the store specific needs.
<br />
</details>
</li>
</ul>

---

## Best practices for fetching data
Site performance tends to get worse as more API requests are made by a page. Because of this, the best practices for fetching data on your storefront involve getting precisely the data you need with the minimum number possible of requests to the FastStore API. The sections below go over what you can do to minimize the API requests of your pages.

### Fetch only the data you need
GraphQL allows you to customize your query to get precisely the data you need, which reduces the data returned from the requests. Double-check your queries to make sure they are not over-fetching.

This also means that you must be mindful of the data brought into your query by [GraphQL fragments](https://graphql.org/learn/queries/#fragments). Use them only when they do not include unnecessary data.


### Do not send requests to other APIs

When building your storefront with FastStore, to avoid comprimising the website performance and lead to `504` timeout errors, do not send requests to APIs other than the FastStore API.
If you need to access other data not available in the native FastStore API schema, you must do this by using [API extension](/docs/api-extensions).

If you need data that is not available on the native [FastStore GraphQL schema](https://v1.faststore.dev/reference/api/objects), check the [root object](https://v1.faststore.dev/reference/api/objects).
The [GraphQL root object](https://graphql.org/learn/execution/#root-fields-resolvers) represents the top-level object returned to a query. You can see what data is available in the root object by typing the root param in your store code,
as you can see in the step 2 of [Creating resolvers](/docs/api-extensions/extending-api-schema#step-3---creating-resolvers).


### Avoid custom API Routes
We do not recomend using Next.js [API Routes](https://nextjs.org/docs/api-routes/introduction) other than the ones already built in FastStore.

If you do use this type of function, you must be mindful to always check which ones are actually running and remove the ones that are not.

---

<ul class="nx-card-list">
<li class="nx-card">
<a href="/docs/api-extensions/extending-api-schema">
#### Extending VTEX API schemas
Extend VTEX and third-party APIs to customize how data is managed and processed in your store.
</a>
</li>

<li class="nx-card">
<a href="/docs/api-extensions/extending-queries-using-fragments">
#### Extending queries using fragments
Extend GraphQL queries using fragments in FastStore API Extension to add custom fields to predefined queries.
</a>
</li>

<li class="nx-card">
<a href="/docs/api-extensions/consuming-api-extensions">
#### Consuming FastStore API extension with custom components
Consume FastStore API extension data with custom components, such as [Sections](/docs/building-sections/creating-a-new-section) and [Override components](/docs/building-sections/overriding-components-and-props).
</a>
</li>

<li class="nx-card">
<a href="/docs/api-extensions/troubleshooting">
#### Troubleshooting
Check for common errors that can happen while using API extensions.
</a>
</li>
</ul>
6 changes: 6 additions & 0 deletions apps/site/pages/docs/api-extensions/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extending-api-schema": "Extending API schemas",
"extending-queries-using-fragments": "Extending queries using fragments",
"consuming-api-extensions": "Consuming FastStore API extension with custom components",
"troubleshooting": "Troubleshooting"
}
135 changes: 135 additions & 0 deletions apps/site/pages/docs/api-extensions/consuming-api-extensions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
---
title: 'Consuming FastStore API extension with custom components'
sidebar_label: 'API Extensions'
---

<header>

# Consuming FastStore API extension with custom components

</header>

In this guide, learn how to consume new fields from [custom sections](/docs/building-sections/creating-a-new-section) and [overridable components](/docs/building-sections/overriding-components-and-props).

FastStore exposes the data that comes from FastStore API along with FastStore API Extensions inside a provider.
This data comes as a `context` in the provider and you can use the following hooks to access it:


<ul>
<li>
<details>
<summary>`usePDP()`: Use this hook when integrating your section with a Product Detail Page (PDP).</summary>

```ts copy
import { usePDP } from "@faststore/core"

const context = usePDP()
```
</details>
</li>
<li>
<details>
<summary>`usePLP()`: Use this hook when integrating your section with a Product Listing Page (PLP).</summary>
```ts copy
import { usePLP } from "@faststore/core"

const context = usePLP()
```
</details>
</li>
<li>
<details>
<summary>`useSearchPage()`: Use this hook when integrating your section on the Search Page.</summary>
```ts copy
import { useSearchPage } from "@faststore/core"

const context = useSearchPage()
```
</details>
</li>
<li>
<details>
<summary>`usePage()`: Use this hook when you have a single section that is used in more than one type of page.</summary>
```ts copy
import { usePage } from "@faststore/core"

const context = usePage()
```
This hook returns one of the following types as context: `PDPContext`, `PLPContext`, or `SearchPageContext`, and you can decide how to handle it depending on the page that will use this hook by passing the types as generics.

```ts copy
import { usePage } from "@faststore/core"

const context = usePage<PLPContext | SearchPageContext>()
```

</details>
</li>
</ul>

Also, you can use type assertion functions so that you can leverage the use of typescript and get the correct types

```ts copy
import { isPDP, isPLP, isSearchPage } from "@faststore/core";

const context = usePage()

isPDP(context)
isPLP(context)
isSearchPage(context)
```

## Consuming API Extensions data from custom sections

To illustrate how to consume API extension data from custom sections, we'll use the **Call To Action** example from the [Creating a new section](/docs/building-sections/creating-a-new-section) guide inside a Product Listing Page (PLP).
So, ensure to have followed this guide mentioned before to have a new section.

Once you have the `CallToAction` section, add the following import statement inside `src/components/CallToAction.tsx`:


```ts {1,12} filename="src/components/CallToAction.tsx" copy
import { usePLP } from "@faststore/core";

export interface CallToActionProps {
title: string
link: {
text: string
url: string
}
}

export default function CallToAction(props: CallToActionProps) {
const context = usePLP()
return (
<section>
<h2>{`${props.title} ${context?.data?.namedExtraData?.data}`}</h2>
</section>
)
}
```

## Consuming API Extensions data from custom components in section overrides

After [overriding native components and props](/docs/building-sections/overriding-components-and-props#overriding-a-native-component), you can also use the hooks inside custom components to consume custom data, just as in [custom sections](/docs/api-extensions/consuming-api-extensions#consuming-api-extensions-data-from-custom-sections).
In the following example, the `CustomBuyButton` component overrides the native `BuyButton` component from the `ProductDetails` section inside the Product Details Page (PDP).

```ts {2,5} filename="src/components/CustomBuyButton.tsx" copy
import { Button as UIButton } from '@faststore/ui'
import { usePDP } from "@faststore/core"

export function CustomBuyButton(props) {
const context = usePDP()

return (
<UIButton
variant="primary"
onClick={() => {
alert('Hello User!')
}}
>
{context?.data?.product.customData}
</UIButton>
)
}

```
Loading

1 comment on commit db3aa69

@vercel
Copy link

@vercel vercel bot commented on db3aa69 Oct 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.