databases

command
v0.0.0-...-c9f4763 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 13, 2016 License: Apache-2.0 Imports: 6 Imported by: 0

README

Databases

One of the most asked questions I get about web development in Go is how to connect to a SQL database. Thankfully, Go has a fantastic SQL package in the standard library that allows us to use a whole slew of drivers for different SQL databases. In this example we will connect to a SQLite database, but the syntax (minus some small SQL semantics) is the same for a MySQL or PostgreSQL database.

Below is an example web application that has two endpoints: POST /books to create a book and GET /books to show all books that have been created.

To create a new book, run:

curl -vX POST http://localhost:8080/books \
--header "Content-Type: application/json" \
-d "{\"author\": \"George Orwell\", \"title\": \"1984\"}"

To create another:

curl -vX POST http://localhost:8080/books \
--header "Content-Type: application/json" \
-d "{\"author\": \"Victor Hugo\", \"title\": \"Les Misérables\"}"

To view all books:

curl -v http://localhost:8080/books --header "Content-Type: application/json"
package main

import (
	"database/sql"
	"encoding/json"
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
	_ "github.com/mattn/go-sqlite3"
)

type book struct {
	Author string `json:"author"`
	Title  string `json:"title"`
}

type errResponse struct {
	Message string `json:"message"`
}

func main() {
	db, err := newDB()
	if err != nil {
		log.Fatalln("Could not connect to database")
	}

	r := httprouter.New()
	r.GET("/books", getHandler(db))
	r.POST("/books", postHandler(db))

	log.Println("Listening on :8080")
	http.ListenAndServe(":8080", r)
}

func getHandler(db *sql.DB) httprouter.Handle {
	return func(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
		books, err := getBooks(db)
		if err != nil {
			respondError(rw, err)
			return
		}

		rw.Header().Set("Content-Type", "application/json")

		if err := json.NewEncoder(rw).Encode(books); err != nil {
			respondError(rw, err)
			return
		}
	}
}

func postHandler(db *sql.DB) httprouter.Handle {
	return func(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
		var b book
		if err := json.NewDecoder(r.Body).Decode(&b); err != nil {
			respondError(rw, err)
			return
		}

		if err := createBook(db, b); err != nil {
			respondError(rw, err)
			return
		}

		rw.WriteHeader(http.StatusNoContent)
	}
}

func newDB() (*sql.DB, error) {
	db, err := sql.Open("sqlite3", "example.sqlite")
	if err != nil {
		log.Println(err)
		return nil, err
	}

	q := "CREATE TABLE IF NOT EXISTS books(title TEXT, author TEXT)"
	if _, err := db.Exec(q); err != nil {
		log.Println(err)
		return nil, err
	}

	return db, nil
}

func getBooks(db *sql.DB) ([]book, error) {
	q := "SELECT title, author FROM books"
	rows, err := db.Query(q)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	var books []book
	for rows.Next() {
		var b book
		if err := rows.Scan(&b.Title, &b.Author); err != nil {
			log.Println(err)
			return nil, err
		}

		books = append(books, b)
	}

	return books, nil
}

func createBook(db *sql.DB, b book) error {
	q := "INSERT INTO books(title, author) VALUES ($1, $2)"
	if _, err := db.Exec(q, b.Title, b.Author); err != nil {
		log.Println(err)
		return err
	}

	return nil
}

func respondError(rw http.ResponseWriter, err error) {
	rw.Header().Set("Content-Type", "application/json")
	rw.WriteHeader(http.StatusInternalServerError)

	er := errResponse{
		Message: err.Error(),
	}

	if err := json.NewEncoder(rw).Encode(er); err != nil {
		log.Println(err)
	}
}

Exercises

  1. Make use of the Query function on our sql.DB instance to extract a collection of rows and map them to structs.
  2. Add the ability to insert new records into our database by using an HTML form.
  3. go get github.com/jmoiron/sqlx and observe the improvements made over the existing database/sql package in the standard library.

Documentation

The Go Gopher

There is no documentation for this package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL