Arsitektur Dokumentasi
Peta jalan panduan, SDK integration, dan API reference lengkap yang disiapkan secara terstruktur.
API Publik Tulis — Contoh Next.js (App Router)
Integrasi Next.js App Router minimal untuk API publik Tulis headless CMS.
Peringatan keamanan: Kunci API harus tetap di server. Bacalah dari variabel lingkungan (
TULIS_API_KEY) dan jangan pernah diawali denganNEXT_PUBLIC_. Next.js hanya mengirim variabelNEXT_PUBLIC_*ke browser; yang lainnya tetap di sisi server. Server Component dan Route Handler berjalan di server, sehingga kunci tidak pernah terekspos ke klien.
Pengaturan lingkungan
Buat .env.local di direktori root proyek Anda:
TULIS_API_KEY=your_api_key_here
TULIS_WORKSPACE_ID=your_workspace_id_here
TULIS_HOST=https://your-host.example.com⚠️ Jangan awali ini dengan
NEXT_PUBLIC_. Simpan hanya di sisi server.
Halaman beranda — ambil posting di sisi server
app/page.tsx adalah Server Component yang mengambil posting di server menggunakan fetch. Kunci API tidak pernah mencapai browser.
import { TULIS_API_KEY, TULIS_WORKSPACE_ID, TULIS_HOST } from "@/lib/env";
async function getPosts() {
const res = await fetch(
`${TULIS_HOST}/v1/posts?page=1&per_page=10`,
{
headers: {
Authorization: `Bearer ${TULIS_API_KEY}`,
"X-Workspace-ID": TULIS_WORKSPACE_ID,
},
// Revalidasi setiap 60 detik (ISR). Sesuaikan sesuai kebutuhan.
next: { revalidate: 60 },
}
);
if (!res.ok) {
throw new Error(`Gagal memuat posting: ${res.status}`);
}
const json = await res.json();
return json.data;
}
export default async function HomePage() {
const posts = await getPosts();
return (
<main>
<h1>Posting Terbaru</h1>
<ul>
{posts.map((post: any) => (
<li key={post.id}>
<a href={`/posts/${post.slug}`}>{post.title}</a>
</li>
))}
</ul>
</main>
);
}lib/env.ts (modul khusus server untuk memusatkan akses lingkungan):
export const TULIS_API_KEY = process.env.TULIS_API_KEY!;
export const TULIS_WORKSPACE_ID = process.env.TULIS_WORKSPACE_ID!;
export const TULIS_HOST = process.env.TULIS_HOST!;Detail posting — rute dinamis
app/posts/[slug]/page.tsx mengambil satu posting dan menyuntikkan json_ld untuk SEO. Ini juga menggunakan generateMetadata untuk mengatur judul dan deskripsi halaman dari seo_title / seo_desc.
import { notFound } from "next/navigation";
import { TULIS_API_KEY, TULIS_WORKSPACE_ID, TULIS_HOST } from "@/lib/env";
type Params = { slug: string };
async function getPost(slug: string) {
const res = await fetch(
`${TULIS_HOST}/v1/posts/${encodeURIComponent(slug)}`,
{
headers: {
Authorization: `Bearer ${TULIS_API_KEY}`,
"X-Workspace-ID": TULIS_WORKSPACE_ID,
},
next: { revalidate: 60 },
}
);
if (!res.ok) {
return null;
}
const json = await res.json();
return json; // { status, message, data: Post, json_ld: {...} }
}
export async function generateMetadata({ params }: { params: Params }) {
const json = await getPost(params.slug);
if (!json) return {};
const post = json.data;
return {
title: post.seo_title || post.title,
description: post.seo_desc || post.excerpt,
};
}
export default async function PostPage({ params }: { params: Params }) {
const json = await getPost(params.slug);
if (!json) notFound();
const post = json.data;
const jsonLd = json.json_ld;
return (
<main>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<h1>{post.title}</h1>
{post.feature_image ? (
<img src={post.feature_image} alt={post.title} />
) : null}
<article dangerouslySetInnerHTML={{ __html: post.content }} />
</main>
);
}Bidang
feature_imagedancontentberasal dari respons satu posting (data). Objekjson_lddi-render ke dalam blok<script type="application/ld+json">untuk data terstruktur mesin pencari. KarenagetPostdipanggil baik digenerateMetadatamaupun di halaman, pertimbangkan untuk menyimpannya dalam cache melalui Reactcache()untuk menghindari permintaan duplikat.
Lini Masa Peluncuran Fitur
Docker Compose, pengaturan file environment, dan panduan setup lokal telah lengkap dibuat.
Dokumentasi route endpoint publik, otentikasi JWT, dan kontrol hak akses telah selesai disusun.
Mempersiapkan boilerplate untuk Next.js client, manajemen revisi konten, dan optimasi query.