Initial commit
This commit is contained in:
27
api/.gitignore
vendored
Normal file
27
api/.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
# env file
|
||||
.env
|
||||
|
||||
*.db
|
||||
7
api/context/context.go
Normal file
7
api/context/context.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package context
|
||||
|
||||
import "database/sql"
|
||||
|
||||
type Context struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
41
api/context/db.go
Normal file
41
api/context/db.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database/sqlite3"
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
func InitializeDB() *sql.DB {
|
||||
|
||||
db, err := sql.Open("sqlite3", "./data.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
runMigrations(db)
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func runMigrations(db *sql.DB) {
|
||||
driver, err := sqlite3.WithInstance(db, &sqlite3.Config{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
m, err := migrate.NewWithDatabaseInstance(
|
||||
"file://./migrations/",
|
||||
"",
|
||||
driver)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
m.Up()
|
||||
}
|
||||
15
api/go.mod
Normal file
15
api/go.mod
Normal file
@@ -0,0 +1,15 @@
|
||||
module api
|
||||
|
||||
go 1.22.5
|
||||
|
||||
require (
|
||||
github.com/golang-migrate/migrate/v4 v4.17.1
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
)
|
||||
18
api/go.sum
Normal file
18
api/go.sum
Normal file
@@ -0,0 +1,18 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
|
||||
github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
71
api/main.go
Normal file
71
api/main.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"api/context"
|
||||
"api/middleware"
|
||||
"api/utils"
|
||||
"database/sql"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
ID int
|
||||
Name string
|
||||
}
|
||||
|
||||
type Context context.Context
|
||||
|
||||
func main() {
|
||||
|
||||
context.InitializeDB()
|
||||
|
||||
db, err := sql.Open("sqlite3", "./data.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
var context = Context{
|
||||
DB: db,
|
||||
}
|
||||
|
||||
var router = http.NewServeMux()
|
||||
router.HandleFunc("GET /", context.HelloWorld)
|
||||
|
||||
var server = http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: middleware.Logging(router),
|
||||
}
|
||||
log.Println("Starting server at", server.Addr)
|
||||
|
||||
err = server.ListenAndServe()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *Context) HelloWorld(w http.ResponseWriter, r *http.Request) {
|
||||
sqlStmt := `select COUNT(*) from person;`
|
||||
|
||||
result, err := ctx.DB.Query(sqlStmt)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var count int
|
||||
if result.Next() {
|
||||
if result.Scan(&count) != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
log.Fatal("No rows found")
|
||||
}
|
||||
|
||||
err = utils.WriteJSON(w, count)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
30
api/middleware/logger.go
Normal file
30
api/middleware/logger.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WrappedWriter struct {
|
||||
http.ResponseWriter
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (w *WrappedWriter) WriteHeader(code int) {
|
||||
w.ResponseWriter.WriteHeader(code)
|
||||
w.StatusCode = code
|
||||
}
|
||||
|
||||
func Logging(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
|
||||
wrapped := &WrappedWriter{
|
||||
ResponseWriter: w,
|
||||
StatusCode: http.StatusOK,
|
||||
}
|
||||
next.ServeHTTP(wrapped, r)
|
||||
log.Println(wrapped.StatusCode, r.Method, r.URL.Path, time.Since(start))
|
||||
})
|
||||
}
|
||||
5
api/migrations/001_initial_schema.up.sql
Normal file
5
api/migrations/001_initial_schema.up.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
create table person (id integer not null primary key, name text);
|
||||
|
||||
insert into person (id, name)
|
||||
values (1, 'John');
|
||||
4
api/migrations/002_initial_schema.up.sql
Normal file
4
api/migrations/002_initial_schema.up.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
insert into person (id, name)
|
||||
values (2, 'John');
|
||||
4
api/migrations/003_initial_schema.up.sql
Normal file
4
api/migrations/003_initial_schema.up.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
insert into person (id, name)
|
||||
values (3, 'Katja');
|
||||
11
api/utils/http-utils.go
Normal file
11
api/utils/http-utils.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func WriteJSON(w http.ResponseWriter, data interface{}) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
return json.NewEncoder(w).Encode(data)
|
||||
}
|
||||
Reference in New Issue
Block a user