How to use PMKIN with Next.js (App Router)
This guide uses the App Router approach to integrate PMKIN with your Next.js application. All the code for this quick start guide is in our Next.js quick start repository on GitHub.
Start by adding the necessary packages to your Next.js project:
npm install @apollo/client graphql react-markdown
Set up your PMKIN API key as an environment variable. Create a .env.local file in your project root:
PMKIN_API_KEY=your_api_key_here
Create a new file app/lib/apollo-client.ts:
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
const httpLink = createHttpLink({
uri: 'https://pmkin.io/graphql'
})
const authLink = setContext((_, { headers }) => {
const pmkinApiKey = process.env.PMKIN_API_KEY
if (!pmkinApiKey) {
throw new Error('PMKIN_API_KEY is not set.')
}
return {
headers: {
...headers,
authorization: `Bearer ${pmkinApiKey}`
}
}
})
export const client = new ApolloClient({
cache: new InMemoryCache(),
link: authLink.concat(httpLink)
})
Create a new file app/blog/page.tsx:
import { gql } from '@apollo/client'
import Link from 'next/link'
import { client } from '../lib/apollo-client'
const GET_DOCUMENTS = gql`
query GetDocuments {
documents(includeDrafts: false) {
id
metaDescription
slug
title
}
}
`
interface Document {
id: string
metaDescription: string
slug: string
title: string
}
async function getDocuments(): Promise<Document[]> {
const { data } = await client.query({ query: GET_DOCUMENTS })
return data.documents
}
export default async function BlogList() {
const documents = await getDocuments()
return (
<div>
<h1>Blog Posts</h1>
{documents.map(doc => (
<article key={doc.id}>
<h2>
<Link href={`/blog/${doc.slug}`}>{doc.title}</Link>
</h2>
<p>{doc.metaDescription}</p>
</article>
))}
</div>
)
}
Create a new file app/blog/[slug]/page.tsx:
import { gql } from '@apollo/client'
import { Metadata } from 'next'
import ReactMarkdown from 'react-markdown'
import { client } from '../../lib/apollo-client'
const GET_DOCUMENT = gql`
query GetDocument($slug: String!) {
documentBySlug(slug: $slug) {
id
markdown
metaDescription
metaTitle
title
}
}
`
interface Document {
id: string
markdown: string
metaDescription: string
metaTitle: string
title: string
}
async function getDocument(slug: string): Promise<Document> {
const { data } = await client.query({
query: GET_DOCUMENT,
variables: { slug },
})
return data.documentBySlug
}
export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
const document = await getDocument(params.slug)
return {
title: document.metaTitle ?? document.title,
description: document.metaDescription,
}
}
export default async function BlogPost({ params }: { params: { slug: string } }) {
const document = await getDocument(params.slug)
return (
<article>
<h1>{document.title}</h1>
<ReactMarkdown>{document.markdown}</ReactMarkdown>
</article>
)
}
This setup provides a solid foundation for integrating PMKIN with your Next.js application using the App Router. Using PMKIN's API, you can expand on this by adding pagination, categories, or search functionality.
Note that in the App Router approach, we use React Server Components for data fetching, allowing us to fetch data directly in the component without getStaticProps or getServerSideProps. The generateMetadata function dynamically generates metadata for each blog post.