Jillian Hoenig
Jillian Hoenig

Reputation: 247

Cannot access rails backend with fetch (500 Internal Server Error)

I'm trying to access an api backend in a React/Rails app. I'm referencing this tutorial (it's a little outdated, but works with a few tweaks). I can't seem to connect to the backend. How can I resolve / troubleshoot these errors?

Fetch console error:

Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

Rails server log error:

Started GET "/api/v1/playlists/index" for ::1 at 2024-09-05 08:59:11 -0400
Processing by Api::V1::PlaylistsController#index as */*
  Playlist Load (0.4ms)  SELECT "playlists".* FROM "playlists"
  ↳ app/controllers/api/v1/playlists_controller.rb:5:in `index'
  ActiveStorage::Attachment Load (0.2ms)  SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ?  [["record_id", 1], ["record_type", "Playlist"], ["name", "image"], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/playlists_controller.rb:5:in `index'
  ActiveStorage::Blob Load (0.1ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/playlists_controller.rb:5:in `index'
Completed 500 Internal Server Error in 51ms (ActiveRecord: 0.7ms | Allocations: 7845)



fatal (exception reentered):

javascript/components/Playlists.jsx (truncated for clarity)

import { Table, message, Popconfirm } from "antd";
import React from "react";

class Playlists extends React.Component {

  ...

  loadPlaylists = () => {
    const url = "api/v1/playlists/index";
    fetch(url)
      .then((data) => {
        if (data.ok) {
          return data.json();
        }
        console.log(data.json())
        throw new Error("Network error.");
      })

      ...

  };

  ...

  render() {
    return (
      <>
        <Table className="table-striped-rows" dataSource={this.state.playlists} columns={this.columns} pagination={{ pageSize: 5 }} />

      </>
    );
  }
}

export default Playlists;

controllers/api/v1/playlists_controller.rb:

class Api::V1::PlaylistsController < ApplicationController
  # GET /playlists or /playlists.json
  def index
    @playlists = Playlist.all
    render json: @playlists
  end
end

routes.rb

Rails.application.routes.draw do
  root 'page#index'

  namespace :api do
    namespace :v1 do
      get 'playlists/index'
      post 'playlists/create'
      delete 'playlists/:id', to: 'playlists#destroy'
    end
  end
end

Let me know if I'm missing anything here. Thank you!

***UPDATE: I'm finding that all other models work, when I replace "Playlist.all" in the controller. For example, using the Track model, which has a youtube video ID, and a reference to the playlist(s) it belong to:

controllers/api/v1/playlists_controller.rb:

class Api::V1::PlaylistsController < ApplicationController
  # GET /playlists or /playlists.json
  def index
    @playlists = Track.all
    render json: @playlists
  end
end

Works perfectly fine. Obviously the table above isn't filled out because the fields are different, but the app is able to access Tracks without returning a 500 error..

Upvotes: 0

Views: 106

Answers (1)

phuzi
phuzi

Reputation: 13061

The problem is here and caused by assuming an unsuccessful response contains JSON. Your example clearly contains an HTML error page.

    fetch(url)
      .then((data) => {
        if (data.ok) {
          return data.json();
        }
        console.log(data.json())
        throw new Error("Network error.");
      })

You would be better off logging data.text():

    fetch(url)
      .then((data) => {
        if (data.ok) {
          return data.json();
        }
        console.log(data.text()) // UPDATE THIS
        throw new Error("Network error.");
      })

Also, I wouldn't assume that a failed request is only caused by a network error either.

Upvotes: 0

Related Questions