Kurs vibe coding z AI · Moduł 14: Pinterest Clone

API Routes - REST & GraphQL

1 min czytania
W tej lekcji2

Tworzenie API endpoints.

REST API

// app/api/users/route.ts
export async function GET() {
  const users = await prisma.user.findMany();
  return Response.json({ users });
}

export async function POST(request: Request) {
  const body = await request.json();
  const user = await prisma.user.create({ data: body });
  return Response.json({ user }, { status: 201 });
}

Dynamic Routes

// app/api/users/[id]/route.ts
export async function GET(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params; // od Next.js 15 params to Promise
  const user = await prisma.user.findUnique({
    where: { id: parseInt(id) }
  });
  return Response.json({ user });
}

Do zobaczenia!

Kod do tej lekcji: App.tsx
'use client';

import { useState } from 'react';

const relatedSearches = ['piracki statek', 'fotografia zachodu słońca', 'fale oceanu', 'żeglarstwo', 'styl marynistyczny'];

export default function CameraSearch() {
  const [imagePreview, setImagePreview] = useState<string | null>(null);
  const [isSearching, setIsSearching] = useState(false);

  const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (event) => {
      setImagePreview(event.target?.result as string);
      setIsSearching(true);
      setTimeout(() => setIsSearching(false), 2000);
    };
    reader.readAsDataURL(file);
  };

  if (!imagePreview) {
    return (
      <div className="min-h-screen bg-white p-8">
        <div className="max-w-4xl mx-auto text-center">
          <h1 className="text-4xl font-bold mb-8">Szukaj obrazem</h1>

          <label className="inline-block cursor-pointer">
            <div className="w-64 h-64 border-4 border-dashed border-gray-300 rounded-2xl flex flex-col items-center justify-center hover:border-red-500 transition mx-auto">
              <div className="text-6xl mb-4">◆</div>
              <div className="font-semibold mb-2">Prześlij obraz</div>
              <div className="text-sm text-gray-600">lub przeciągnij i upuść</div>
            </div>
            <input type="file" accept="image/*" onChange={handleImageUpload} className="hidden" />
          </label>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-white p-8">
      <div className="max-w-6xl mx-auto">
        {/* Podgląd obrazu */}
        <div className="mb-8">
          <img src={imagePreview} alt="Obraz do wyszukania" className="max-w-sm mx-auto rounded-2xl shadow-lg" />
        </div>

        {/* Ładowanie */}
        {isSearching ? (
          <div className="text-center text-gray-600 mb-8 text-lg">
            Szukam podobnych pinów...
          </div>
        ) : (
          <>
            {/* Powiązane wyszukiwania */}
            <div className="mb-8">
              <h2 className="text-2xl font-bold mb-4">Powiązane wyszukiwania</h2>
              <div className="flex flex-wrap gap-2">
                {relatedSearches.map(search => (
                  <button
                    key={search}
                    className="px-4 py-2 bg-gray-200 rounded-full hover:bg-gray-300 font-semibold"
                  >
                    {search}
                  </button>
                ))}
              </div>
            </div>

            {/* Podobne piny */}
            <div>
              <h2 className="text-2xl font-bold mb-4">Podobne piny</h2>
              <div className="grid grid-cols-4 gap-4">
                {[1, 2, 3, 4, 5, 6, 7, 8].map(i => (
                  <div key={i} className="aspect-[3/4] bg-gray-200 rounded-2xl" />
                ))}
              </div>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Jak w Next.js App Router stworzyć endpoint odpowiadający na GET?

  2. 2. Skąd handler w app/api/users/[id]/route.ts bierze id z URL?

Zadania praktyczne w grze

  • Klikanie w kolejności

    Kliknij elementy, aby zbudować zwrócenie listy użytkowników jako JSON:

  • Układanie w poziomie

    Ułóż elementy jednej linii zwracającej utworzony rekord ze statusem 201:

  • Edytor kodu

    Stwórz REST API endpoints

Przydatne artykuły