error SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

created at 01-30-2022 views: 119

project

  • backend: django rest-framework
  • frontend: React/Next js

complete code example at the end.

problem

Got this problem when post data with React/Next js.

The most possible reason you get this error is the fetch() haven't get the right response.

Based on my case, the problem happened because of the url path.

fetch url

make sure your fectch url is right. here is a wrong example of using relative path:

fetch('/blogs/',options)
    .then(res => {
            console.log(res) // only for debugging
            return res.json()
   })
   .then(response => console.log(`response`,response))
   .catch(error => console.log(`error`,error))

make a post and get result:

Response { 
  type: "basic", 
  url: "http://localhost:3000/blogs", 
  redirected: true, 
  status: 200, 
  ok: true, 
  statusText: "OK", 
  headers: Headers, 
  body: ReadableStream, bodyUsed: false 
}
error SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

Haha! we got status code 200 and ok is true. But what it means is actually a get success:

  • 200: get success
  • 201: post success

where is the problem? look at the url:

  1. the relative path made the fetching happen on http://localhost:3000/blogs !
  2. but our REST backend is running on port http://127.0.0.1:8000

solution

so instead of using relative path, we should use the absolute path of our REST API.

fetch('http://127.0.0.1:8000/blogs/',options)
    .then(...)

trailing slash

note in the above we use domain/blogs/ rather than domain/blogs.

if you use fetch url without a trailling slash, you can not get right response either, but this error is easy to be found since you will get an error in the backend:

RuntimeError: You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redi
rect to the slash URL while maintaining POST data. Change your form to point to 127.0.0.1:8000/blogs/ (note the trailing slash)
, or set APPEND_SLASH=False in your Django settings.

as it suggests,

  1. you should append a / to your path
  2. or set APPEND_SLASH=False in your settings

This is also a point we'ed know when debugging.

complete code example

const Post = () => {
    const [title, setTitle] = useState("");
    const [description, setDescription] = useState("");

    const submitPost = async (event) => {
        event.preventDefault();
        const options = {
                method:"POST",
                body:JSON.stringify({
                    title: title,
                    description: description
                }),
                headers:{
                    "Content-Type":"application/json"
                },
            }
        fetch('http://127.0.0.1:8000/tools/',options)
            .then(res => {
                console.log(res)
                return res.json()
            })
            .then(response => console.log(`response`,response))
            .catch(error => console.log(`error`,error))

    }

    return (
      <form className={styles.postForm}
            onSubmit={submitPost}>
          {/*<CSRFToken />*/}
          <p>
              <label htmlFor="title">Title</label>
              <input
                  id="title"
                  name="title"
                  type="text"
                  autoComplete="name"
                  required
                  onChange = {(e) => setTitle(e.target.value)}
              />
          </p>
          <p>
              <label htmlFor="description">Description</label>
              <textarea
                  id="description"
                  name="description"
                  onChange={(e) => setDescription(e.target.value)}
              >
              </textarea>
          </p>
          <button className={styles.postSubmit} type="submit">submit</button>
      </form> 
    )
}
export default Post

success response example:

Response { type: "cors", url: "http://127.0.0.1:8000/tools/", redirected: false, status: 201, ok: true, statusText: "Created", headers: Headers, body: ReadableStream, bodyUsed: false }
post.js:25:20
response: Object { id: 6, title: "post example", description: "this is the content", created_at: "2022-01-30T20:14:04.337325Z", updated_at: "2022-01-30T20:14:04.337325Z" }

note the url(http://127.0.0.1:8000/blogs/) and status code (201).

created at:01-30-2022
edited at: 01-30-2022: