2

I am making axios calls to an API I have created(in Golang). The API seems to work as expected on Postman, but for some reason it doesn't work when I make the calls through React.

import React, {Component} from "react";
import Form from "./Form";
import Header from "./Header";
import axios from "axios";

let endpoint = "http://localhost:8000/";

class Dashboard extends Component {
    constructor(props){
        super(props)
        this.state = {
            currentRepository: '',
            data: {},
        }
        this.setRepository = this.setRepository.bind(this)
    }
    
    componentDidMount(){
        axios.get(
            endpoint,
            {
            headers: {
              "Content-Type": "application/json"
            }
          }
        )
        .then(res => {
          console.log(res);
        });
    }

    setRepository(url){
        console.log(url)
        this.setState({
            currentRepository: url,
        }, () => {
            axios.put(
                endpoint, 
                this.state.currentRepository, {
                headers: {
                  "Content-Type": "application/json"
                }
              }
            )
            .then(res => {
              this.setState({
                  data: res
              })
              console.log(res);
            })
        })
    }

    render(){
        return (
            <div className="m-5 border-2">
                <Header></Header>
                <Form setRepository={this.setRepository}></Form>
            </div>
        )
    }
}

export default Dashboard;

I the error I get in console is, enter image description here

Now, I double checked, and I have mentioned all the required Access Control options. A piece of my backend golang code:

func getHome(w http.ResponseWriter, r *http.Request) {
    commitTimeStamps := getCommitTimeStamps(currentRepository)
    commitTimeObjects := parseTimeStamps(commitTimeStamps)

    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Methods", "GET")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

    _ = json.NewEncoder(w).Encode(commitTimeObjects)
}



func updateRepository(w http.ResponseWriter, r *http.Request) {
    var url struct {
        URL string `json:"url"`
    }
    _ = json.NewDecoder(r.Body).Decode(&url)
    currentRepository = parseURL(&url.URL)
    
    // currentRepository looks like {bradtraversy reactcharts}
    commitTimeStamps := getCommitTimeStamps(currentRepository)
    commitTimeObjects := parseTimeStamps(commitTimeStamps)
    // commitTimeObjects looks like [{2016-04-21 2} {2016-04-23 5} {2016-04-25 1}]
    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Methods", "PUT")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

    _ = json.NewEncoder(w).Encode(commitTimeObjects)
}

func main() {
    router := mux.NewRouter()
    router.Use(mux.CORSMethodMiddleware(router))
    router.HandleFunc("/", getHome).Methods("GET", "OPTIONS")
    router.HandleFunc("/", updateRepository).Methods("PUT", "OPTIONS")

    http.ListenAndServe(":8000", router)
}

I cannot understand where the problem is, a little help would be amazing. Thank You.

UPDATE:

Replacing PUT, with POST works. But still cannot understand why PUT doesn't work.

Community
  • 1
  • 1
Karan Singh
  • 1,114
  • 1
  • 13
  • 30
  • Can you trying this in header in frontend: ```Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS``` – Shubham Verma Jun 08 '20 at 09:39
  • I added it inside headers of axios, but then GET also stopped working – Karan Singh Jun 08 '20 at 09:49
  • My bad ```Access-Control-Allow-Methods``` is response header. It will not work. try this: ``` axios.get(url, { crossdomain: true }) ``` – Shubham Verma Jun 08 '20 at 09:51
  • What's the purpose of the `CORSMethodMiddleware` call if you don't use its return value? Because as it is now, it has no effect whatsoever, so it is unclear what you believe the code is supposed to do. – mkopriva Jun 08 '20 at 10:07
  • @ShubhamVerma doesn't work. both GET and PUT work exactly the same as before. – Karan Singh Jun 08 '20 at 10:09
  • @mkopriva Sorry, fixed that – Karan Singh Jun 08 '20 at 10:15
  • 1. CORS is primarily a browser thing, Postman doesn't have to invoke pre-flight requests or care about the presence / absence of the CORS-specific headers; so don't waste your time thinking about why it doesn't work in your browser while Postman is fine. 2. The GET and POST methods are not necessarily subject to CORS-preflight requests, hence they may not trigger the OPTIONS request; so don't waste your time thinking about why it doesn't work for PUT, PATCH, or DELETE while GET and POST are fine. – mkopriva Jun 08 '20 at 11:44
  • 3. The point of using `CORSMethodMiddleware` is that you don't have to set the `Access-Control-Allow-Methods` header manually. 4. You're registering two different handlers for `"/" OPTIONS`, I'm surprised the mux router didn't panic to inform you of that. You should register only a single handler per a specific route. Depending on how the gorilla router deals with duplicate handler registrations this, together with point 3. could easily be the cause of the issue. – mkopriva Jun 08 '20 at 12:00
  • @mkopriva got it. Any tips on how I could structure my code with 2 different endpoints? I only have one single page in my application (with a form and a chart to display the information fetched from the form) – Karan Singh Jun 08 '20 at 12:47
  • @KaranSingh I'm not sure I understand what you're asking, but keep doing what you're doing with your two handlers, just don't register them *both* under the OPTIONS method. How is gorilla supposed to know which to execute? When the browser sends a request to `"/"` with method `OPTIONS`, how is the router supposed to know which handler to execute? Should it execute `getHome` or `updateRepository`? You do not know, and neither does gorilla. Be specific, don't let the code *guess* what you want. – mkopriva Jun 08 '20 at 13:11

3 Answers3

0

CORS does pre-flight requests sending an OPTIONS request to any URL, so to handle a POST request you first need to handle an OPTIONS request to that same URL. On GET endpoints this is not an issue, but it is for POST and PUT and DELETE requests.

You can check this post enable-cors-in-golang

Vanish
  • 1
  • 2
0

This is definitely a CORS issue. GET and POST is supported without CORS. but PUT, PATCH, DELETE require pre-flight requests and setting up CORS on your golang server.

If you look at the error in your network console it says it too - 1. That it has been blocked by CORS policy 2. Method PUT is not allowed.

Here is a good package to install into your api and enable CORS on your endpoints: https://pkg.go.dev/github.com/rs/cors

Druhin Bala
  • 772
  • 7
  • 12
0

I reinstalled NodeJS on my system after uninstalling and the same code seems to work now. I was on WSL Ubuntu, so that might be a bug from their side!

Karan Singh
  • 1,114
  • 1
  • 13
  • 30