Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(examples): with-grafbase (#42898)
- Loading branch information
Showing
21 changed files
with
891 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
GRAFBASE_API_URL=http://localhost:4000/graphql | ||
GRAFBASE_API_KEY= |
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,38 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
.pnpm-debug.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
|
||
.grafbase |
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,4 @@ | ||
{ | ||
"typescript.tsdk": "node_modules/typescript/lib", | ||
"typescript.enablePromptUseWorkspaceTsdk": true | ||
} |
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,68 @@ | ||
# Next.js with Grafbase | ||
|
||
This example shows to use [Grafbase](https://grafbase.com) with Next.js. This example features fetching from a local GraphQL backend powered by the Grafbase CLI, and GraphQL Code Generator for making type-safe queries. | ||
|
||
## Demo | ||
|
||
You can see a demo of this online at [https://grafbase-with-nextjs-rsc.grafbase-vercel.dev](https://grafbase-with-nextjs-rsc.grafbase-vercel.dev). | ||
|
||
## Deploy | ||
|
||
First deploy this to Grafbase to get your backend API URL and Key: | ||
|
||
[![Deploy to Grafbase](https://grafbase.com/button)](https://grafbase.com/new/configure?template=NextExample&source=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-grafbase) | ||
|
||
Then deploy this example using [Vercel](https://vercel.com): | ||
|
||
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-grafbase&env=GRAFBASE_API_URL,GRAFBASE_API_KEY) | ||
|
||
## How to use | ||
|
||
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: | ||
|
||
```bash | ||
npx create-next-app --example with-grafbase with-grafbase-app | ||
``` | ||
|
||
```bash | ||
yarn create next-app --example with-grafbase with-grafbase-app | ||
``` | ||
|
||
```bash | ||
pnpm create next-app --example with-grafbase with-grafbase-app | ||
``` | ||
|
||
To run the example locally you need to: | ||
|
||
1. Copy the `.env.local.example` to `.env.local` and provide your API URL and API Key: `cp .env.local.example .env.local` — the defaults will be fine for development mode. | ||
|
||
2. Run the [Grafbase CLI](https://grafbase.com/cli) using `npx grafbase@latest dev` | ||
|
||
3. Populate the backend with some `Post` entries using a GraphQL mutation: | ||
|
||
```graphql | ||
mutation { | ||
postCreate( | ||
input: { | ||
title: "I love Next.js!" | ||
slug: "i-love-nextjs" | ||
comments: [{ create: { message: "me too!" } }] | ||
} | ||
) { | ||
post { | ||
id | ||
slug | ||
} | ||
} | ||
} | ||
``` | ||
|
||
4. Run the app locally and go to [http://localhost:3000](http://localhost:3000) to navigate to each post page! This data is fetched from the local backend. | ||
|
||
5. Optionally run `npm run codegen` to watch for any changes to queries inside of the app and automatically generate types. | ||
|
||
## Learn more | ||
|
||
- [Grafbase Quickstart](https://grafbase.com/docs/quickstart/get-started) — get started with Grafbase, quickly! | ||
- [Create an account](https://grafbase.com/sign-up) — deploy to the edge with Grafbase! | ||
- [Next.js Documentation](https://nextjs.org/docs) — learn more about Next.js |
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 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; |
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,7 @@ | ||
const Head = () => ( | ||
<> | ||
<title>Grafbase + Next.js</title> | ||
</> | ||
) | ||
|
||
export default Head |
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,80 @@ | ||
import './globals.css' | ||
|
||
import Link from 'next/link' | ||
|
||
import { graphql } from '../gql' | ||
import { grafbase } from '../lib/grafbase' | ||
|
||
const GetAllPostsDocument = graphql(/* GraphQL */ ` | ||
query GetAllPosts($first: Int!) { | ||
postCollection(first: $first) { | ||
edges { | ||
node { | ||
id | ||
title | ||
slug | ||
} | ||
} | ||
} | ||
} | ||
`) | ||
|
||
const RootLayout = async ({ children }: { children: React.ReactNode }) => { | ||
const { postCollection } = await grafbase.request(GetAllPostsDocument, { | ||
first: 50, | ||
}) | ||
|
||
return ( | ||
<html lang="en"> | ||
<head> | ||
<title>Grafbase + Next.js 13</title> | ||
</head> | ||
<body> | ||
<div className="flex"> | ||
<nav className="w-[350px] flex flex-col justify-between h-screen overflow-y-auto bg-gray-100"> | ||
<ul className="p-8 space-y-2"> | ||
<li className="mb-6"> | ||
<Link | ||
href="/" | ||
className="py-2 rounded-md shadow-sm block px-3 text-gray-600 hover:text-gray-800 transition bg-white" | ||
> | ||
Home | ||
</Link> | ||
</li> | ||
<li className="px-3 py-2 uppercase text-xs text-gray-800 font-semibold"> | ||
Posts | ||
</li> | ||
{postCollection?.edges?.map((edge) => | ||
edge?.node ? ( | ||
<li key={edge.node.id}> | ||
<Link | ||
href={`/posts/${edge.node.slug}`} | ||
className="py-2 rounded-md shadow-sm block px-3 text-gray-600 hover:text-gray-800 transition bg-white" | ||
> | ||
{edge.node.title} | ||
</Link> | ||
</li> | ||
) : null | ||
)} | ||
<li> | ||
<Link | ||
href="/posts/not-found" | ||
className="py-2 rounded-md shadow-sm block px-3 text-gray-600 hover:text-gray-800 transition bg-white" | ||
> | ||
Show 404 page | ||
</Link> | ||
</li> | ||
</ul> | ||
</nav> | ||
<main className="flex-1 p-6 md:p-24"> | ||
<div className="max-w-3xl mx-auto"> | ||
<div className="prose max-w-none">{children}</div> | ||
</div> | ||
</main> | ||
</div> | ||
</body> | ||
</html> | ||
) | ||
} | ||
|
||
export default RootLayout |
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,13 @@ | ||
const Page = async () => { | ||
return ( | ||
<> | ||
<h1>Next.js 13 + Grafbase</h1> | ||
<p> | ||
Once you've added some posts using the GraphQL Playground, you can | ||
explore each post by clicking the link in the nav. | ||
</p> | ||
</> | ||
) | ||
} | ||
|
||
export default Page |
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,34 @@ | ||
import { graphql } from '../../../gql' | ||
import { grafbase } from '../../../lib/grafbase' | ||
|
||
export const revalidate = 3600 | ||
|
||
const GetPostBySlugDocument = graphql(/* GraphQL */ ` | ||
query GetPostBySlug($slug: String!) { | ||
post(by: { slug: $slug }) { | ||
id | ||
title | ||
slug | ||
} | ||
} | ||
`) | ||
|
||
const Page = async ({ params }: { params: { slug: string } }) => { | ||
const { post } = await grafbase.request(GetPostBySlugDocument, { | ||
slug: params.slug, | ||
}) | ||
|
||
if (!post) { | ||
// optionally import notFound from next/navigation | ||
return <h1>404: Not Found</h1> | ||
} | ||
|
||
return ( | ||
<> | ||
<h1>{post.title}</h1> | ||
<pre>{JSON.stringify(post, null, 2)}</pre> | ||
</> | ||
) | ||
} | ||
|
||
export default Page |
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,26 @@ | ||
import { CodegenConfig } from '@graphql-codegen/cli' | ||
|
||
const url = process.env.GRAFBASE_API_URL as string | ||
const xApiKey = process.env.GRAFBASE_API_KEY as string | ||
|
||
const config: CodegenConfig = { | ||
schema: [ | ||
{ | ||
[url]: { | ||
headers: { | ||
'x-api-key': xApiKey, | ||
}, | ||
}, | ||
}, | ||
], | ||
documents: ['app/**/*.tsx', 'app/**/*.ts'], | ||
ignoreNoDocuments: true, | ||
generates: { | ||
'./gql/': { | ||
preset: 'client', | ||
plugins: [], | ||
}, | ||
}, | ||
} | ||
|
||
export default config |
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,44 @@ | ||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core' | ||
|
||
export type FragmentType<TDocumentType extends DocumentNode<any, any>> = | ||
TDocumentType extends DocumentNode<infer TType, any> | ||
? TType extends { ' $fragmentName'?: infer TKey } | ||
? TKey extends string | ||
? { ' $fragmentRefs'?: { [key in TKey]: TType } } | ||
: never | ||
: never | ||
: never | ||
|
||
// return non-nullable if `fragmentType` is non-nullable | ||
export function useFragment<TType>( | ||
_documentNode: DocumentNode<TType, any>, | ||
fragmentType: FragmentType<DocumentNode<TType, any>> | ||
): TType | ||
// return nullable if `fragmentType` is nullable | ||
export function useFragment<TType>( | ||
_documentNode: DocumentNode<TType, any>, | ||
fragmentType: FragmentType<DocumentNode<TType, any>> | null | undefined | ||
): TType | null | undefined | ||
// return array of non-nullable if `fragmentType` is array of non-nullable | ||
export function useFragment<TType>( | ||
_documentNode: DocumentNode<TType, any>, | ||
fragmentType: ReadonlyArray<FragmentType<DocumentNode<TType, any>>> | ||
): ReadonlyArray<TType> | ||
// return array of nullable if `fragmentType` is array of nullable | ||
export function useFragment<TType>( | ||
_documentNode: DocumentNode<TType, any>, | ||
fragmentType: | ||
| ReadonlyArray<FragmentType<DocumentNode<TType, any>>> | ||
| null | ||
| undefined | ||
): ReadonlyArray<TType> | null | undefined | ||
export function useFragment<TType>( | ||
_documentNode: DocumentNode<TType, any>, | ||
fragmentType: | ||
| FragmentType<DocumentNode<TType, any>> | ||
| ReadonlyArray<FragmentType<DocumentNode<TType, any>>> | ||
| null | ||
| undefined | ||
): TType | ReadonlyArray<TType> | null | undefined { | ||
return fragmentType as any | ||
} |
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,25 @@ | ||
/* eslint-disable */ | ||
import * as types from './graphql' | ||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core' | ||
|
||
const documents = { | ||
'\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n': | ||
types.GetAllPostsDocument, | ||
'\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n': | ||
types.GetPostBySlugDocument, | ||
} | ||
|
||
export function graphql( | ||
source: '\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n' | ||
): typeof documents['\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n'] | ||
export function graphql( | ||
source: '\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n' | ||
): typeof documents['\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n'] | ||
|
||
export function graphql(source: string): unknown | ||
export function graphql(source: string) { | ||
return (documents as any)[source] ?? {} | ||
} | ||
|
||
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = | ||
TDocumentNode extends DocumentNode<infer TType, any> ? TType : never |
Oops, something went wrong.