Files
Arkie-Library-Backend/docs/GO_FOR_BEGINNERS.md
2026-05-18 07:56:27 +08:00

282 lines
4.5 KiB
Markdown

# Go Beginner Guide for This Backend
This is not a full Go course. It explains only the Go ideas you need to read this project.
## 1. How a Go project starts
This repo has a `go.mod` file:
```go
module github.com/arkie/ark-database
```
That module name is used in imports:
```go
import "github.com/arkie/ark-database/internal/config"
```
The executable starts at:
```text
cmd/server/main.go
```
In Go, a runnable program has:
```go
package main
func main() {
// program starts here
}
```
## 2. Packages
Every `.go` file begins with a package name:
```go
package handlers
```
Files in the same folder usually share the same package and can call each other directly.
Example: files in `internal/handlers/` all say `package handlers`, so `public.go` can call `writeJSON` from `util.go`.
## 3. Imports
Go imports are explicit:
```go
import (
"net/http"
"github.com/go-chi/chi/v5"
)
```
If an import is unused, Go compilation fails. Run `gofmt -w .` after edits.
## 4. Structs
A struct is an object/data shape.
Example from `internal/config/config.go`:
```go
type Config struct {
Addr string
DatabaseURL string
JWTSecret string
}
```
JSON field names are controlled by tags:
```go
type ResourceDTO struct {
CategoryID int `json:"categoryId"`
}
```
The Go field is `CategoryID`, but JSON output is `categoryId`.
## 5. Functions with errors
Go commonly returns `(value, error)`:
```go
pool, err := db.Connect(ctx, cfg.DatabaseURL)
if err != nil {
log.Fatal(err)
}
```
Read this as:
1. Try connecting to DB.
2. If `err` is not nil, stop.
3. Otherwise use `pool`.
## 6. Short variable declaration `:=`
This creates a new variable:
```go
cfg := config.Load()
```
This assigns to an existing variable:
```go
cfg = config.Load()
```
Most code here uses `:=` inside functions.
## 7. HTTP handlers
A Go HTTP handler usually looks like:
```go
func ListCategories(w http.ResponseWriter, r *http.Request) {
// w writes response
// r reads request
}
```
- `w` = response writer.
- `r` = request.
Route registration in `main.go`:
```go
r.Get("/categories", handlers.ListCategories)
```
Because this is inside `r.Route("/api", ...)`, the full URL is:
```text
GET /api/categories
```
## 8. Middleware
Middleware wraps a request before it reaches the final handler.
Example in `main.go`:
```go
r.Use(middleware.Logger)
```
This logs requests.
Admin auth is also middleware:
```go
r.Use(handlers.AdminAuth(cfg.JWTSecret))
```
If token is bad, it returns `401 unauthorized` before reaching the admin handler.
## 9. Context
Context carries request-scoped values and cancellation.
This project stores the DB pool in request context:
```go
r.Use(func(next http.Handler) http.Handler {
return handlers.WithPool(next, pool)
})
```
Handlers retrieve it:
```go
pool := poolFrom(r)
```
So most handlers do not receive the DB pool as a direct function parameter.
## 10. Database queries
This project uses pgx.
One row:
```go
err := pool.QueryRow(ctx, `SELECT id FROM admins WHERE email = $1`, email).Scan(&id)
```
Many rows:
```go
rows, err := pool.Query(ctx, `SELECT id, title FROM resources`)
defer rows.Close()
for rows.Next() {
rows.Scan(&id, &title)
}
```
PostgreSQL parameters use `$1`, `$2`, etc. This protects from SQL injection when used correctly.
## 11. Pointers and nil
You will see `*string` and `*time.Time`:
```go
var pubAt *time.Time
```
This allows SQL `NULL` to become Go `nil`.
Code checks before using it:
```go
if pubAt != nil {
s := pubAt.UTC().Format(time.RFC3339)
dto.PublishedAt = &s
}
```
## 12. `defer`
`defer` runs later when the current function returns.
Examples:
```go
defer pool.Close()
defer rows.Close()
defer r.Body.Close()
```
Use it for cleanup.
## 13. JSON helpers in this project
Write JSON response:
```go
writeJSON(w, map[string]any{"ok": true})
```
Read JSON request body:
```go
var req loginReq
if err := jsonDecode(r, &req); err != nil {
http.Error(w, "bad json", http.StatusBadRequest)
return
}
```
## 14. Common edit workflow
After changing `.go` files:
```bash
gofmt -w .
go test ./...
```
`go test ./...` also compiles all packages, even if there are no test files.
## 15. Recommended reading order
1. `README.md`
2. `cmd/server/main.go`
3. `internal/config/config.go`
4. `internal/handlers/public.go`
5. `internal/handlers/admin.go`
6. `internal/handlers/wallet_auth.go`
7. `migrations/001_init.sql`
When you see a function you do not understand, search for its definition:
```bash
rg "func FunctionName" .
```