My first Go API
Published: 2020-10-26 14:43:12

I recently branched out of our current program and built a simple API using Go. Going down this route taught me that I didn't know nearly as much about what was happening in my backend as I thought. I started to discover just how much Ruby/Rails does for you compared to building the API from scratch. I'm going to share my experience and one of the issues I ran into while creating this API. 

The first thing I needed to do in order to create my simple  API in Go was to create my entry point. In order to do this I declared a package name of main and a func main in order to execute my Go program. 

Declaring at the top
```
package main
```

```
func main() {
	connectToDatabase()
	handleRequest()
	defer db.Close()
}
```

Next up I wanted to connect my API to a PSQL database in order to POST and GET entries from my React-Redux frontend. You'll notice I called this function inside of my entry point in order to make the connection to the database whenever my package is initialized.

```
func connectToDatabase() {

	var err error
	host := os.Getenv("HOST")
	databaseUsername := os.Getenv("USERNAME")
	password := os.Getenv("PASSWORD")
	database := os.Getenv("DATABASE")
	port := os.Getenv("PORT")

	psqlInfo := fmt.Sprintf("host=%s port=%s user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, port, databaseUsername, password, database)
	db, err = sql.Open("postgres", psqlInfo)
	if err != nil {
		panic(err)
	}

	err = db.Ping()
	if err != nil {
		panic(err)
	}

	fmt.Println("Successfully connected!")
}
```

After I stop running the program I used this method in my func main in order to close any open cursors, free allocated resources, and close underlying files.

```
defer db.Close()
```

Next up was creating my routes. I am going to highlight one of them in order to showcase the issue I ran into while creating this API.

```
func addScores(w http.ResponseWriter, r *http.Request) {

	setupResponse(&w, r)

	switch r.Method {
	case "POST":
		reqBody, _ := ioutil.ReadAll(r.Body)
		fmt.Fprintf(w, "%v", string(reqBody))
		var highscore HighScore
		json.Unmarshal(reqBody, &highscore)

		username := highscore.Username
		score := highscore.Score

		var err error
		sqlStatement := `
			INSERT INTO highscores (username, score)
			VALUES ($1, $2)`
		_, err = db.Exec(sqlStatement, username, score)
		if err != nil {
			panic(err)
		}
	default:
		//method not available error.
		http.Error(w, http.StatusText(405), 405)
	}

}
```

The main issue I found while creating this API was not setting what specifically should happen whenever different types of Methods are received in the http request. I initially forgot to handle my preflight request, which led to my database receiving double entries each time I sent a POST request. A simple switch statement fixed my issue so whenever my route receives the OPTIONS method it won't create a new row in my table. It will only create the row when receiving a POST method. 

One of the final steps for creating this API was to allow access from the frontend to the backend. I set up my response using the following. 

``` 
func setupResponse(w *http.ResponseWriter, req *http.Request) {
	(*w).Header().Set("Access-Control-Allow-Origin", "*")
	(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS")
	(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}
```

Overall this was a very fun experience trying to learn a new tech on my own for the first time since joining Flatiron School. I learned quite a lot about the request and response cycle. Along with learning that its very important to tell your routes how to deal with the preflight requests, otherwise you may end up with a bunch of a blank rows in your database! 

Thanks for taking the time to read this and hope its helpful for someone out there!