Інтеграція Strapi з фронтендом (React/Vue/Next.js/Nuxt.js)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Інтеграція Strapi з фронтендом (React/Vue/Next.js/Nuxt.js)
Середня
~3-5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Інтеграція Strapi з фронтендом (React/Vue/Next.js/Nuxt.js)

Strapi працює як окремий headless API-сервер. Фронтенд звертається до нього по HTTP — через REST або GraphQL. Ключові задачи інтеграції: типобезпечний клієнт, кеширування на рівні фреймворку, on-demand ревалідація та проксирування запитів через BFF для приховування API-токенів.

Базовий API клієнт

// lib/strapi.ts
const STRAPI_URL = process.env.STRAPI_URL!
const API_TOKEN = process.env.STRAPI_API_TOKEN!

interface StrapiResponse<T> {
  data: T
  meta: {
    pagination?: { page: number; pageSize: number; pageCount: number; total: number }
  }
}

export async function strapi<T>(
  endpoint: string,
  init?: RequestInit & { next?: { tags?: string[]; revalidate?: number } }
): Promise<StrapiResponse<T>> {
  const url = `${STRAPI_URL}/api${endpoint}`

  const response = await fetch(url, {
    headers: {
      Authorization: `Bearer ${API_TOKEN}`,
      'Content-Type': 'application/json',
    },
    ...init,
  })

  if (!response.ok) {
    throw new Error(`Strapi error ${response.status}: ${await response.text()}`)
  }

  return response.json()
}

// Вспомогательні функції
export function getMediaURL(path: string | null | undefined) {
  if (!path) return null
  if (path.startsWith('http')) return path
  return `${STRAPI_URL}${path}`
}

Server Components (Next.js App Router)

// app/articles/page.tsx
import { strapi } from '@/lib/strapi'
import type { Article, StrapiMedia } from '@/types/strapi'

interface ArticleListData {
  id: number
  attributes: {
    title: string
    slug: string
    excerpt: string
    publishedAt: string
    cover: { data: { id: number; attributes: StrapiMedia } | null }
  }
}

export default async function ArticlesPage({
  searchParams,
}: {
  searchParams: { page?: string; category?: string }
}) {
  const page = Number(searchParams.page) || 1
  const categoryFilter = searchParams.category
    ? `&filters[category][slug][$eq]=${searchParams.category}`
    : ''

  const { data: articles, meta } = await strapi<ArticleListData[]>(
    `/articles?populate=cover,category&sort=publishedAt:desc&pagination[page]=${page}&pagination[pageSize]=12${categoryFilter}`,
    { next: { tags: ['articles'], revalidate: 3600 } }
  )

  return (
    <div>
      <ArticleGrid articles={articles} />
      <Pagination meta={meta.pagination} />
    </div>
  )
}

export const revalidate = 3600

ISR + On-demand Revalidation

// app/articles/[slug]/page.tsx
export default async function ArticlePage({ params }: { params: { slug: string } }) {
  const { data } = await strapi<ArticleListData[]>(
    `/articles?filters[slug][$eq]=${params.slug}&populate=cover,author,category,tags`,
    { next: { tags: [`article-${params.slug}`] } }
  )

  const article = data[0]
  if (!article) notFound()

  return <Article article={article} />
}

export async function generateStaticParams() {
  const { data } = await strapi<{ attributes: { slug: string } }[]>(
    '/articles?fields[0]=slug&pagination[pageSize]=200'
  )
  return data.map(item => ({ slug: item.attributes.slug }))
}
// app/api/revalidate/route.ts — отримує вебхук від Strapi
import { revalidateTag, revalidatePath } from 'next/cache'

export async function POST(req: Request) {
  const { model, entry } = await req.json()

  // Інвалідувати по тегу
  revalidateTag(model)  // наприклад, 'article'

  // Інвалідувати конкретну сторінку
  if (entry?.slug) {
    revalidatePath(`/articles/${entry.slug}`)
    revalidateTag(`article-${entry.slug}`)
  }

  return Response.json({ revalidated: true })
}

Client-side запити (React)

// hooks/useArticles.ts
'use client'
import useSWR from 'swr'

const fetcher = (url: string) =>
  fetch(url).then(r => r.json())

export function useArticles(category?: string) {
  const query = category ? `?filters[category][slug][$eq]=${category}` : ''
  const { data, error, isLoading } = useSWR(
    `/api/articles${query}`,  // через Next.js API proxy
    fetcher
  )

  return {
    articles: data?.data || [],
    isLoading,
    error,
  }
}
// app/api/articles/route.ts — proxy для клієнтських запитів
export async function GET(req: Request) {
  const url = new URL(req.url)
  const params = url.searchParams.toString()

  const response = await fetch(
    `${process.env.STRAPI_URL}/api/articles?${params}&populate=cover`,
    { headers: { Authorization: `Bearer ${process.env.STRAPI_API_TOKEN}` } }
  )

  const data = await response.json()
  return Response.json(data)
}

TypeScript типи для Strapi відповідей

// types/strapi.ts
export interface StrapiMedia {
  name: string
  url: string
  alternativeText: string | null
  width: number
  height: number
  formats: {
    thumbnail?: StrapiMediaFormat
    small?: StrapiMediaFormat
    medium?: StrapiMediaFormat
    large?: StrapiMediaFormat
  }
}

export interface StrapiMediaFormat {
  url: string
  width: number
  height: number
}

export interface StrapiEntity<T> {
  id: number
  attributes: T
}

export interface Article {
  title: string
  slug: string
  content: string
  excerpt: string
  publishedAt: string
  cover: { data: StrapiEntity<StrapiMedia> | null }
  author: { data: StrapiEntity<{ name: string; avatar: any }> | null }
}

Часові рамки

Інтеграція Strapi з Next.js (ISR, вебхуки, TypeScript типи) — 2–3 дні.