v v
v v

Reputation: 653

Why got 404 for API endpoint with react-admin?

Created backend API use gin with go language

type Post struct {
    ID uint `json:"id"`
    Title string `json:"title"`
    Body string `json:"body"`
}

func main() {
    // ...
    r := gin.Default()
    r.GET("/posts", GetPosts)
    r.GET("/posts/:id", GetPost)
    r.POST("/posts", CreatePost)
    r.PUT("/posts/:id", UpdatePost)
    r.DELETE("/posts/:id", DeletePost)

    r.Run(":8080")
}

func GetPosts(c *gin.Context) {
    var posts []Post
    c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
    if err := db.Find(&posts).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
    } else {
            c.JSON(200, post)
    }
}

// ...

Created frontend use react with react-admin

src/App.js

import React from 'react';
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { PostList } from './posts';

const dataProvider = jsonServerProvider('http://localhost:8080');

const App = () => (
        <Admin dataProvider={dataProvider}>
    <Resource name="posts" list={PostList} />
        </Admin>
);

export default App;

src/posts.js

import React from 'react';
import { List, Datagrid, TextField } from 'react-admin';

export const PostList = (props) => (
    <List {...props}>
        <Datagrid>
            <TextField source="id" />
            <TextField source="title" />
            <TextField source="body" />
        </Datagrid>
    </List>
);

When access http://localhost:3000 from chrome browser, got Failed to fetch message. From the console I saw:

Failed to load http://localhost:8080/posts?_end=10&_order=DESC&_sort=id&_start=0: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 404. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I have tried to add Access-Control-Allow-Origin in the go API program, but the same result. From the gin output I got:

[GIN] 2018/06/12 - 18:14:50 | 404 |       1.813µs |       127.0.0.1 | OPTIONS  /posts?_end=10&_order=DESC&_sort=id&_start=0

Add

Added cors package then change source as:

package main

import (
        "fmt"

        "github.com/gin-contrib/cors"
        "github.com/gin-gonic/gin"
        // ...
)

// ...

func main() {
    r := gin.Default()

    r.Use(cors.New(cors.Config{
            AllowOrigins: []string{"http://localhost:8080"},
    }))

    r.GET("/posts", GetPosts)
    r.GET("/posts/:id", GetPost)
    r.POST("/posts", CreatePost)
    r.PUT("/posts/:id", UpdatePost)
    r.DELETE("/posts/:id", DeletePost)

    r.Run()
}

Got same error again:

Failed to load http://localhost:8080/posts?_end=10&_order=DESC&_sort=id&_start=0: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 403. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

This time, the output of gin was:

[GIN] 2018/06/13 - 11:01:59 | 403 |       7.873µs |             ::1 | OPTIONS  /posts?_end=10&_order=DESC&_sort=id&_start=0

Upvotes: 1

Views: 2699

Answers (2)

v v
v v

Reputation: 653

This way works:

func main() {
        // ...
        r := gin.Default()
        r.Use(cors.New(cors.Config{
                AllowOrigins:  []string{"http://localhost:3000"},
                AllowMethods:  []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
                AllowHeaders:  []string{"Origin", "Content-Length", "Content-Type"},
                ExposeHeaders: []string{"X-Total-Count"},
        }))
        r.GET("/posts", GetPosts)
        // ...
        r.Run()
}

func GetPosts(c *gin.Context) {
        var posts []Post
        if err := db.Find(&posts).Error; err != nil {
                c.AbortWithStatus(404)
                fmt.Println(err)
        } else {
                c.Header("X-Total-Count", "25")
                c.JSON(200, posts)
        }
}

Due to ra-data-json-server.

Upvotes: 0

Himanshu
Himanshu

Reputation: 12675

Add CORS middleware for cross origin domain requests. I would prefer to hit the api using postman to check if it is working fine. Below is the way to implement CORS middleware for gin in go:-

package main

import (
    "time"

    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    // CORS for http://localhost:8080 and https://github.com origins, allowing:
    // - PUT and PATCH methods
    // - Origin header
    // - Credentials share
    // - Preflight requests cached for 12 hours
    router.Use(cors.New(cors.Config{
        AllowOrigins:     []string{"http://localhost:8080, https://localhost:8080"},
        AllowMethods:     []string{"GET", "POST", "HEAD", "PUT", "PATCH"},
        AllowHeaders:     []string{"Origin"},
        ExposeHeaders:    []string{"Content-Length"},
        AllowCredentials: true,
        MaxAge: 12 * time.Hour,
    }))
    router.Run()
}

Edited: For allowing all origins use Default config for cors as

func main() {
    router := gin.Default()
    // same as
    // config := cors.DefaultConfig()
    // config.AllowAllOrigins = true
    // router.Use(cors.New(config))
    router.Use(cors.Default())
    router.Run()
}

For more information checkout CORS middleware for gin

Upvotes: 1

Related Questions