Проблемы с выполнением POST-запроса API в Next.js

Вопросы и ответы

Я новичок в вопросах, связанных с бэкендом, и только начинаю разбираться с Next.js и TypeScript. Я пытаюсь сделать POST-запрос к API, который должен получить formData и создать новый список на основе этих данных формы. Я пытаюсь сделать это с помощью серверных действий и обработчиков маршрутов Next.js.

Вот мой код:

Это часть из компонента формы:

    const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();

        const form = e.currentTarget as HTMLFormElement;
        const formData = new FormData(form);

        const address = formData.get("address");
        const mail = formData.get("mail");
        const region_id = selectedRegion?.id; // эти данные приходят из состояния
        const agent_id = selectedAgent?.id;  // эти данные приходят из состояния
        const city_id = selectedCity?.id;   // эти данные приходят из состояния
        const area = formData.get("area");
        const price = formData.get("price");
        const type = formData.get("type");
        const cover = formData.get("cover"); // Это поле для загрузки файла

        try {
            console.log(address, mail, region_id, agent_id, city_id, area, price, type, cover);

            const newFormData = new FormData();

            newFormData.append("address", address as string);
            newFormData.append("mail", mail as string);
            newFormData.append("region_id", region_id as any);
            newFormData.append("agent_id", agent_id as any);
            newFormData.append("city_id", city_id as any);
            newFormData.append("area", area as string);
            newFormData.append("price", price as string);
            newFormData.append("type", type as string);
            newFormData.append("cover", cover as File); 

            await addListingAction(newFormData)
        } catch (error) {
            alert(`Ошибка: ${error}`);
        }
    };

Это мое серверное действие:

    export async function addListingAction(formData: FormData) {
  try {
    await addListing(formData);
  } catch (error) {
    console.log(error);
  } finally {
    revalidatePath("/")
  }
}

мой файл api.ts:

export async function addListing(formData: FormData) {

  return await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/add-listing`, {
    method: 'POST',
    body: formData,
  })
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error('Ошибка:', error));
}

и мой файл route.ts:

import { NextResponse } from 'next/server';

export async function POST(req: Request) {
  try {
    const formData = await req.formData();

    const address = formData.get("address");
    const mail = formData.get("mail");
    const region_id = formData.get("region_id");
    const agent_id = formData.get("agent_id");
    const city_id = formData.get("city_id");
    const area = formData.get("area");
    const price = formData.get("price");
    const type = formData.get("type");
    const cover = formData.get("cover") as File | null;

    const form = new FormData();
    if (address) form.append("address", address);
    if (mail) form.append("mail", mail);
    if (region_id) form.append("region_id", region_id);
    if (agent_id) form.append("agent_id", agent_id);
    if (city_id) form.append("city_id", city_id);
    if (area) form.append("area", area);
    if (price) form.append("price", price);
    if (type) form.append("type", type);
    if (cover instanceof File) form.append("cover", cover);

    const REDBERRY_API_TOKEN = process.env.REDBERRY_API_TOKEN;

    if (!REDBERRY_API_TOKEN) {
      throw new Error("Отсутствует API токен");
    }

    const response = await fetch('https://api.real-estate-manager.redberryinternship.ge/api/real-estates', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${REDBERRY_API_TOKEN}`,
      },
      body: form,
    });

if (!response.ok) {
  let errorResponse;
  try {
    errorResponse = await response.json();
  } catch {
    errorResponse = await response.text();
  }
  console.error('Ошибка HTTP! Статус:', response.status, 'Ответ:', errorResponse);
  return NextResponse.json(
    { message: 'Запрос к API не удался', error: errorResponse },
    { status: response.status }
  );
}

  const listing = await response.json();

  return NextResponse.json({ listing }, { status: 201 });

  } catch (error) {
    const message = error instanceof Error ? error.message : 'Произошла непредвиденная ошибка';
    console.error('Ошибка при создании списка:', message);
  return NextResponse.json(
    { message: 'Не удалось создать список', error: message },
    { status: 500 }
  );
  }
}

Документация API говорит, что запрос curl выглядит так:

    curl -X 'POST' \
  'https://api.real-estate-manager.redberryinternship.ge/api/real-estates' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer API_TOKEN' \
  -H 'Content-Type: multipart/form-data' \
  -F 'region_id=1' \
  -F 'price=100000' \
  -F 'zip_code=0101' \
  -F 'area=100.5' \
  -F 'city_id=1' \
  -F 'address=пример адреса' \
  -F 'agent_id=371' \
  -F 'bedrooms=3' \
  -F 'is_rental=0' \
  -F '[email protected];type=image/png' \
  -F 'description=дом рядом со станцией метро'

и ответ выглядит следующим образом:

"price": "100000",
  "zip_code": "0101",
  "area": "100.5",
  "city_id": "1",
  "address": "пример описания",
  "agent_id": "371",
  "bedrooms": "3",
  "is_rental": "0",
  "description": "дом рядом со станцией метро",
  "image": "https://api.real-estate-manager.redberryinternship.ge/storage/images/vZ6KRjLiBIoVqwl4GMniE598mAzno8wqzCkZyg3f.png",
  "created_at": "2024-09-15T16:43:21.000000Z",
  "id": 450

Ошибка, которую я получаю:

Ошибка при создании списка: Неправильный токен ‘<‘, “<!DOCTYPE “… не является допустимым JSON
POST /api/add-listing 500 за 931мс
{
message: ‘Не удалось создать список’,
error: ‘Неправильный токен ‘<‘, “<!DOCTYPE “… не является допустимым JSON’
}

Любая помощь будет очень полезна.

Ответ

Проблема, с которой вы столкнулись, скорее всего, связана с тем, что ваш API не возвращает корректный JSON-ответ. Вместо этого вы получаете HTML-документ (возможно, это страница ошибки 404 или 500), что указывает на то, что запрос обрабатывается неправильно. Давайте рассмотрим несколько шагов для диагностики и устранения этой проблемы.

Шаг 1: Проверьте URL-адрес API

Убедитесь, что ваш URL-адрес API ${process.env.NEXT_PUBLIC_API_URL}/api/add-listing правильно установлен и доступен. Попробуйте сделать запрос к этому URL с помощью инструмента, такого как Postman или cURL, и убедитесь, что вы получаете ожидаемый ответ.

Шаг 2: Проверка тела запроса

Убедитесь, что данные, которые вы отправляете на сервер, формируются и отправляются корректно. В вашем коде вы собираете данные с формы и добавляете их в FormData. Вот как это реализовано:

const newFormData = new FormData();
newFormData.append("address", address as string);
newFormData.append("mail", mail as string);
newFormData.append("region_id", region_id as any);
newFormData.append("agent_id", agent_id as any);
newFormData.append("city_id", city_id as any);
newFormData.append("area", area as string);
newFormData.append("price", price as string);
newFormData.append("type", type as string);
newFormData.append("cover", cover as File);

Убедитесь, что region_id, agent_id, и city_id действительно имеют корректные значения, это может быть особенно важно, так как если их нет или они отсутствуют, API может вернуть ошибку.

Шаг 3: Логируйте ответы

Добавьте логирование в ваш серверный обработчик в route.ts, чтобы отследить полученные данные:

export async function POST(req: Request) {
  try {
    const formData = await req.formData();
    console.log("Received FormData:", formData);

    // Остальной код...

  } catch (error) {
    console.error('Error:', error);
    // Отправьте ответ, чтобы разъяснить проблему
  }
}

Шаг 4: Печать ошибок

В обработчике POST запроса лучше имейте дополнительное логирование, чтобы увидеть точное сообщение об ошибке:

if (!response.ok) {
  let errorResponse = await response.text(); // Меняем на text, чтобы получить HTML
  console.error('HTTP error! Status:', response.status, 'Response:', errorResponse);
  // Остальной код...
}

Шаг 5: Проверка правильности API

Убедитесь, что все необходимые поля передаются в API. Иногда небольшие ошибки, например, пропущенные поля или неверные типы данных, могут привести к ошибкам, с которыми вы сталкиваетесь. Исходя из примера cURL, убедитесь, что все необходимые параметры загрузки присутствуют.

Шаг 6: Убедитесь в корректности заголовков

Убедитесь, что заголовок Content-Type не добавляется вручную, когда вы используете FormData. Браузер автоматически устанавливает правильный заголовок, когда вы отправляете FormData.

Пример решения проблемы

Ваш код может выглядеть следующим образом с учетом всех вышеизложенных рекомендаций:

// route.ts
export async function POST(req: Request) {
  try {
    const formData = await req.formData();
    // Добавьте логирование данных, которые вы получаете
    console.log("Received FormData:", Object.fromEntries(formData));

    // Получите данные
    const address = formData.get("address");
    // Другие параметры...

    // Убедитесь, что REDBERRY_API_TOKEN существует
    const REDBERRY_API_TOKEN = process.env.REDBERRY_API_TOKEN;
    if (!REDBERRY_API_TOKEN) {
      throw new Error("Missing API token");
    }

    const response = await fetch('https://api.real-estate-manager.redberryinternship.ge/api/real-estates', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${REDBERRY_API_TOKEN}`,
      },
      body: formData,
    });

    if (!response.ok) {
      const errorResponse = await response.text(); // Получаем текст для детального анализа
      console.error('HTTP error! Status:', response.status, 'Response:', errorResponse);
      return NextResponse.json(
        { message: 'API request failed', error: errorResponse },
        { status: response.status }
      );
    }

    const listing = await response.json();
    return NextResponse.json({ listing }, { status: 201 });

  } catch (error) {
    console.error('Error creating listing:', error);
    return NextResponse.json(
      { message: 'Failed to create listing', error: error.message },
      { status: 500 }
    );
  }
}

Заключение

Следуя данным шагам, вы сможете локализовать и устранить проблему с вашими API-запросами. Если после выполнения этих шагов ошибка все еще возникает, убедитесь, что вы проверили документацию к API и, возможно, проконсультируйтесь со службой техподдержки API.

Оцените материал
Добавить комментарий

Капча загружается...