Home > OS >  Why am I getting "500 (Internal Server Error)" and "Uncaught (in promise) SyntaxError
Why am I getting "500 (Internal Server Error)" and "Uncaught (in promise) SyntaxError

Time:03-22

I am trying to insert some data into the database through a fetch API POST request to a Next.js API route but I am getting the following two error messages in the browser's console:

api/addCompany/addCompany:1 Failed to load resource: the server responded with a status of 500 (Internal Server Error) register:1

Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0

These are my project's folders (it's relevant because of Next.js's routing system) folder structure

This is the component where I am doing the fetch API request (please don't judge my poor Typescript skills, I am new to it, still not finding the propper event type):

import styles from '../styles/Register.module.css'
import { NextPage } from "next"
import { prisma } from '../prisma/prisma_client';
import { Prisma } from '@prisma/client';
import { useSession } from "next-auth/react"

const Register: NextPage = () => {
  
  const createCompany: any = async (event: any) => {
    event.preventDefault()

    const company: Prisma.CompanyCreateInput = {
      companyName: event.target.companyName.value,
      gender: event.target.gender.value,
      firstName: event.target.firstName.value,
      lastName: event.target.lastName.value,
      street: event.target.street.value,
      houseNumber: parseInt(event.target.houseNumber.value),
      postcode: parseInt(event.target.postcode.value),
      city: event.target.city.value,
      country: event.target.country.value,
      countryCode: event.target.countryCode.value,
      callNumber: parseInt(event.target.callNumber.value),
      emailAddress: event.target.emailAddress.value,
      website: event.target.website.value,
      socials: {},
      companyUser: {
        connect: { id: 'cl0y4y8xo0021mwtcmwlqfif6' }
      }
    }

    const companyJSON = JSON.stringify(company)
    const endpoint = '/api/addCompany/addCompany'
    const options = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: companyJSON,
    }

    const response = await fetch(endpoint, options)

    const data = await response.json()
    console.log(data)
  }

  return (
    <form onSubmit={createCompany} className={styles.form} id="signupForm" noValidate>
      <h2>Company Information</h2>

      <div className="fieldWrapper">
        <input type="text" id="companyName" name="companyName" placeholder=" " />
        <label htmlFor="companyName">Company Name<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="text" list="genders" id="gender" name="gender" placeholder=" " />
        <label htmlFor="gender">Gender<span>*</span></label>
        <div className='errorMessage'></div>
        <datalist id="genders">
          <option>Female</option>
          <option>Male</option>
        </datalist>
      </div>

      <div className="fieldWrapper">
        <input type="text" id="firstName" name="firstName" placeholder=" " />
        <label htmlFor="firstName">First Name<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="text" id="lastName" name="lastName" placeholder=" " />
        <label htmlFor="lastName">Last Name<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="text" id="street" name="street" placeholder=" " />
        <label htmlFor="street">Street<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="number" id="houseNumber" name="houseNumber" placeholder=" " />
        <label htmlFor="houseNumber">House Number<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="number" id="postcode" name="postcode" placeholder=" " />
        <label htmlFor="postcode">Postcode<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="text" id="city" name="city" placeholder=" " />
        <label htmlFor="city">City<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="text" id="country" name="country" placeholder=" " />
        <label htmlFor="country">Country<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="text" id="countryCode" name="countryCode" placeholder=" " />
        <label htmlFor="countryCode">Country Code<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="number" id="callNumber" name="callNumber" placeholder=" " />
        <label htmlFor="callNumber">Call Number<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="email" id="emailAddress" name="emailAddress" placeholder=" " />
        <label htmlFor="emailAddress">Email Address<span>*</span></label>
        <div className='errorMessage'></div>
      </div>

      <div className="fieldWrapper">
        <input type="text" id="website" name="website" placeholder=" " />
        <label htmlFor="website">Website</label>
      </div>

      <div className="fieldWrapper">
        <input type="text" id="socials" name="socials" placeholder=" " />
        <label htmlFor="socials">Socials</label>
      </div>

      <div className="fieldWrapper">
        <button type="submit">Save</button>
      </div>
    </form>
  )
}

export default Register

And this is the the addCompany file's code which serves as the Next.js API route for my fetch API request:

import { Prisma } from '@prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';
import { prisma } from '../../../prisma/prisma_client';

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
    const {body} = req;

    const companyData: Prisma.CompanyCreateInput = JSON.parse(body);

    const addCompany = await prisma.company.create({
        data: companyData
    })
     res.status(200).json(addCompany);
}

export default handler

I appreciate any help. Thank you.

I tried to comment out const data = await response.json() console.log(data) in the Register component so the error "Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0" disappeared but that is no solution to the problem at all. I also tried to adjust the route of my fetch request to any possible option because I wasn't sure how exactly Next.js autocompletes it, for example I tried: '/api/addCompany/addCompany.ts' and so on.

I expect the problem to be something small, I hope it isn't typo. Thank you again.

PS: I also checked similar posts on this matter but couldn't find a fix for my problem.

CodePudding user response:

There is no need to reparse the body data in the API endpoint because Next.js middleware convert that data to an object already:

API routes provide built in middlewares which parse the incoming request (req). Those middlewares are:

  • req.cookies - An object containing the cookies sent by the request. Defaults to {}
  • req.query - An object containing the query string. Defaults to {}
  • req.body - An object containing the body parsed by content-type, or null if no body was sent

something like below should work:

import { Prisma } from '@prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';
import { prisma } from '../../../prisma/prisma_client';

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
    const {body: companyData} = req;

    //const companyData: Prisma.CompanyCreateInput = JSON.parse(body);<- No need to reparse the data here

    const addCompany = await prisma.company.create({
        data: companyData
    })
     res.status(200).json(addCompany);
}

export default handler

Thanks to this answer here for clarification.

  • Related