A simple RESTful API for managing products built with Go, SQLite, sqlc, and goose.
Before you begin, ensure you have the following installed on your system:
# macOS
brew install sqlc
# Linux
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
# Or download binary from: https://github.com/sqlc-dev/sqlc/releases# Using go install
go install github.com/pressly/goose/v3/cmd/goose@latest
# Or using brew (macOS)
brew install goosegit clone <repository-url>
cd go-apigo mod downloadCopy the example environment file:
cp .env.example .envThe .env file configures goose with the following settings:
GOOSE_DRIVER=sqlite3- Database driverGOOSE_DBSTRING=./products.db- Database file pathGOOSE_MIGRATION_DIR=./internal/adapters/sqlite/migrations- Migration files directory
The project uses goose for database migrations. With the .env file configured, you can run goose commands without passing arguments:
# Load environment variables (for current shell session)
source .env
# Run migrations (creates products.db database)
goose up
# Check migration status
goose statusAvailable goose commands:
goose up- Run all pending migrationsgoose down- Roll back the last migrationgoose status- Show migration statusgoose reset- Roll back all migrations
Note: If you prefer not to use the .env file, you can still pass arguments directly:
goose -dir internal/adapters/sqlite/migrations sqlite3 products.db upThe project uses sqlc to generate type-safe Go code from SQL queries.
# Generate Go code from SQL queries
sqlc generateThis will generate the following files in internal/adapters/sqlite/sqlc/:
db.go- Database interfacemodels.go- Go structs for database tablesqueries.sql.go- Type-safe query functions
# Run the API server
go run ./cmd
# Or build and run
go build -o bin/api ./cmd
./bin/apiThe server will start on http://localhost:8080
GET /healthGET /productsGET /products/{id}POST /products
Content-Type: application/json
{
"id": "product-123",
"name": "Apple",
"price_in_cents": 250,
"quantity": 10,
"created_at": 1738944000
}You can test the API using the provided HTTP requests in http/products.http. These can be executed with:
- Kulala (Neovim plugin)
- REST Client (VS Code extension)
- cURL or any HTTP client
Example with cURL:
# Health check
curl http://localhost:8080/health
# List products
curl http://localhost:8080/products
# Create product
curl -X POST http://localhost:8080/products \
-H "Content-Type: application/json" \
-d '{
"id": "product-123",
"name": "Apple",
"price_in_cents": 250,
"quantity": 10,
"created_at": 1738944000
}'- Make sure your
.envis loaded:
source .env- Create a new migration file:
goose create add_new_table sql-
Edit the generated migration file in
internal/adapters/sqlite/migrations/ -
Run the migration:
goose up-
Add your SQL query to
internal/adapters/sqlite/sqlc/queries.sql -
Regenerate Go code:
sqlc generate- Use the generated functions in your Go code
# Make sure your .env is loaded
source .env
# Roll back the last migration
goose down
# Roll back all migrations
goose resetMake sure sqlc is installed and in your PATH:
export PATH=$PATH:$(go env GOPATH)/binMake sure goose is installed and in your PATH:
export PATH=$PATH:$(go env GOPATH)/binIf you get a "database is locked" error, make sure no other process is accessing products.db.
- Go - Programming language
- Chi - HTTP router
- SQLite - Database
- sqlc - Type-safe SQL code generation
- goose - Database migrations
- slog - Structured logging