https://github.com/eckertalex/improved-fiesta
A Go-based API service with SQLite storage and user authentication
https://github.com/eckertalex/improved-fiesta
api authentication authorization go sqlite3 user-management
Last synced: about 1 year ago
JSON representation
A Go-based API service with SQLite storage and user authentication
- Host: GitHub
- URL: https://github.com/eckertalex/improved-fiesta
- Owner: eckertalex
- Created: 2024-10-31T21:22:20.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-23T20:50:06.000Z (over 1 year ago)
- Last Synced: 2025-02-23T21:28:42.224Z (over 1 year ago)
- Topics: api, authentication, authorization, go, sqlite3, user-management
- Language: Go
- Homepage:
- Size: 54.7 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Improved Fiesta 🎉
A Go-based API service with SQLite storage and user authentication.
## Getting Started
### Prerequisites
- Go 1.23.2
- SQLite3
- Make
### Quick Start
1. Clone the repository
2. Run `make tidy` to install dependencies
3. Copy `.env.example` to `.env`:
```sh
cp .env.example .env
```
4. Run database migrations to set up the database schema:
```sh
make db/migrations/up
```
5. Seed the database:
```sh
make db/seed
```
6. Start the development server with hot reload:
```sh
make watch/api
```
The API will be available at the port specified in your `.env` file (default: 45067).
### Available Make Commands
Run `make help` to see all available commands. Here are the most commonly used ones:
#### Development
- `make run/api` - Build and run the API
- `make watch/api` - Run the API with hot reload using Air
- `make tidy` - Format code and tidy up Go modules
#### Testing
- `make test` - Run all tests
- `make itest` - Run integration tests
- `make audit` - Run quality control checks (tests, format verification, vulnerability scanning)
#### Database Operations
- `make db/migrations/new name=migration_name` - Create a new migration
- `make db/migrations/up` - Apply all pending migrations
- `make db/migrations/down` - Revert all migrations
- `make db/seed` - Seed the database with initial data
- `make db/connect` - Connect to the SQLite database
## API Documentation
This document provides comprehensive documentation for all API endpoints, including required permissions, request/response formats, and examples.
### Table of Contents
| Method | Endpoint | Permission | Description |
| ------ | --------------------------------------------------------- | -------------- | ------------------------- |
| GET | [/v1/healthcheck](#get-v1healthcheck) | Public | Application health status |
| GET | [/v1/users](#get-v1users) | Admin | List users |
| POST | [/v1/users](#post-v1users) | Public | Create new user |
| GET | [/v1/users/:id](#get-v1usersid) | Admin or Owner | Get user details |
| PATCH | [/v1/users/:id](#patch-v1usersid) | Admin or Owner | Update user details |
| DELETE | [/v1/users/:id](#delete-v1usersid) | Admin or Owner | Delete user account |
| PATCH | [/v1/users/:id/role](#patch-v1usersid-role) | Admin | Update user role |
| POST | [/v1/users/activate](#post-v1usersactivate) | Public | Activate user account |
| POST | [/v1/users/reset-password](#post-v1usersreset-password) | Public | Reset user password |
| POST | [/v1/tokens/session](#post-v1tokenssession) | Public | Generate auth token |
| DELETE | [/v1/tokens/session](#delete-v1tokenssession) | Public | Delete auth token |
| POST | [/v1/tokens/activation](#post-v1tokensactivation) | Public | Request activation token |
| POST | [/v1/tokens/password-reset](#post-v1tokenspassword-reset) | Public | Request password reset |
| GET | [/debug/vars](#get-debugvars) | Admin | Debug metrics |
### Authentication
For endpoints requiring authentication, include the authentication token in the Authorization header:
```
Authorization: Bearer
```
Tokens can be obtained using the [/v1/auth/authentication](#post-v1tokensauthentication) endpoint.
### Endpoint Details
#### GET /v1/healthcheck
**Permission:** Public
**Description:** Check application health status and version information
**Example Request:**
```bash
curl http://localhost:45067/v1/healthcheck
```
**Response Body:**
- `status` (string): Current application status
- `system_info` (object):
- `environment` (string): Current environment
- `version` (string): Application version
**Example Response:**
```json
{
"status": "available",
"system_info": {
"environment": "development",
"version": "2024-01-15T10:30:00Z-c3418de38b57f0a8bf49d9f7759469eac37cb410"
}
}
```
#### GET /v1/users
**Permission:** Public
**Description:** List users
**Query Parameters:**
- `username` (string): Username
- `email` (string): User's email address
- `page` (number): Page
- `page_size` (number): Page size
- `sort` (number): Sort order (must be 'id', 'username', 'email', 'role', '-id', '-username', '-email', '-role')
**Request Headers:**
- `Authorization`: Bearer token
**Example Request:**
```bash
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:45067/v1/users?email=example&page=2&page_size=10&sort=-username
```
**Response Body:**
- `data` (array): User details
- `metadata` (object): Metadata details
**Example Response:**
```json
{
"data": [
{
"id": 123,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T11:45:00Z",
"username": "alice",
"email": "alice.johnson@example.com",
"activated": true,
"role": "user"
}
{
"id": 124,
"created_at": "2024-01-15T14:00:00Z",
"updated_at": "2024-01-15T14:00:00Z",
"username": "bob",
"email": "bob.smith@example.com",
"activated": false,
"role": "user"
},
],
"metadata": {
"current_page": 1,
"page_size": 20,
"first_page": 1,
"last_page": 1,
"total_records": 2
}
}
```
#### POST /v1/users
**Permission:** Public
**Description:** Create a new user account
**Request Body:**
- `username` (string): Username
- `email` (string): User's email address
- `password` (string): User's password
**Example Request:**
```bash
curl -X POST \
-d '{"username": "bob", "email": "bob.smith@example.com", "password": "SecurePass123!"}' \
http://localhost:45067/v1/users
```
**Response Body:**
- `data` (object): User details
**Example Response:**
```json
{
"data": {
"id": 124,
"created_at": "2024-01-15T14:00:00Z",
"updated_at": "2024-01-15T14:00:00Z",
"username": "bob",
"email": "bob.smith@example.com",
"activated": false,
"role": "user"
}
}
```
#### GET /v1/users/:id
**Permission:** Admin or Owner
**Description:** Retrieve user details by ID
**Path Parameters:**
- `id` (number): User ID
**Request Headers:**
- `Authorization`: Bearer token
**Example Request:**
```bash
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:45067/v1/users/124
```
**Response Body:**
- `data` (object): User details object
**Example Response:**
```json
{
"data": {
"id": 124,
"created_at": "2024-01-15T14:00:00Z",
"updated_at": "2024-01-15T14:00:00Z",
"username": "bob",
"email": "bob.smith@example.com",
"activated": false,
"role": "user"
}
}
```
#### PATCH /v1/users/:id
**Permission:** Admin or Owner
**Description:** Update user details
**Path Parameters:**
- `id` (number): User ID
**Request Headers:**
- `Authorization`: Bearer token
**Request Body:** (all fields optional)
- `username` (string): New username
- `email` (string): New email
- `password` (string): New password
**Example Request:**
```bash
curl -H "Authorization: Bearer $TOKEN" \
-X PATCH \
-d '{"username": "robert"}' \
http://localhost:45067/v1/users/124
```
**Response Body:**
- `data` (object): Updated user details
**Example Response:**
```json
{
"data": {
"id": 124,
"created_at": "2024-01-15T14:00:00Z",
"updated_at": "2024-01-15T15:30:00Z",
"username": "robert",
"email": "bob.smith@example.com",
"activated": false,
"role": "user"
}
}
```
#### DELETE /v1/users/:id
**Permission:** Admin or Owner
**Description:** Delete user account
**Path Parameters:**
- `id` (number): User ID
**Request Headers:**
- `Authorization`: Bearer token
**Example Request:**
```bash
curl -H "Authorization: Bearer $TOKEN" \
-X DELETE \
http://localhost:45067/v1/users/124
```
**Response:** 204 No Content
#### PATCH /v1/users/:id/role
**Permission:** Admin
**Description:** Update user's role
**Path Parameters:**
- `id` (number): User ID
**Request Headers:**
- `Authorization`: Bearer token
**Request Body:**
- `role` (string): New role (must be 'admin' or 'user')
**Example Request:**
```bash
curl -H "Authorization: Bearer $TOKEN" \
-X PATCH \
-d '{"role": "admin"}' \
http://localhost:45067/v1/users/124/role
```
**Response Body:**
- `data` (object): Updated user details
**Example Response:**
```json
{
"data": {
"id": 124,
"created_at": "2024-01-15T14:00:00Z",
"updated_at": "2024-01-15T16:00:00Z",
"username": "robert",
"email": "bob.smith@example.com",
"activated": false,
"role": "admin"
}
}
```
#### POST /v1/users/activate
**Permission:** Public
**Description:** Activate user account
**Request Body:**
- `token` (string): Activation token
**Example Request:**
```bash
curl -X POST \
-d '{"token": "URQXUFRJDA4KCIZ3CLZTHS3K3U"}' \
http://localhost:45067/v1/users/activate
```
**Response Body:**
- `data` (object): Updated user details
**Example Response:**
```json
{
"data": {
"id": 123,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"username": "alice",
"email": "alice.johnson@example.com",
"activated": true,
"role": "user"
}
}
```
#### POST /v1/users/reset-password
**Permission:** Public
**Description:** Reset user password
**Request Body:**
- `password` (string): New password
- `token` (string): Password reset token
**Example Request:**
```bash
curl -X POST \
-d '{"password": "SecurePass123!", "token": "K5YB7CA3KTZL4B6YXO5JLNLWWU"}' \
http://localhost:45067/v1/users/reset-password
```
**Response Body:**
- `data` (object): Updated user details
**Example Response:**
```json
{
"data": {
"id": 123,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T11:45:00Z",
"username": "alice",
"email": "alice.johnson@example.com",
"activated": true,
"role": "user"
}
}
```
#### POST /v1/tokens/session
**Permission:** Public
**Description:** Generate authentication token
**Request Body:**
- `email` (string): User's email
- `password` (string): User's password
**Example Request:**
```bash
curl -X POST \
-d '{"email": "admin@example.com", "password": "AdminPass123!"}' \
http://localhost:45067/v1/tokens/session
```
**Response Body:**
- `authentication_token` (object):
- `token` (string): Authentication token
- `expiry` (string): Token expiration timestamp
**Example Response:**
```json
{
"authentication_token": {
"token": "QNSMBHTILTB4RDRTMRYACTGCTE",
"expiry": "2024-01-15T13:30:00Z"
}
}
```
#### DELETE /v1/tokens/session
**Permission:** Authenticated
**Description:** Delete auth token
**Request Headers:**
- `Authorization`: Bearer token
**Example Request:**
```bash
curl -H "Authorization: Bearer $TOKEN" \
-X DELETE \
http://localhost:45067/v1/tokens/session
```
**Response:** 204 No Content
#### POST /v1/tokens/activation
**Permission:** Public
**Description:** Request new activation token
**Request Body:**
- `email` (string): User's email
**Example Request:**
```bash
curl -X POST \
-d '{"email": "alice.johnson@example.com"}' \
http://localhost:45067/v1/tokens/activation
```
**Response Body:**
- `message` (string): Confirmation message
**Example Response:**
```json
{
"message": "an email will be sent to you containing activation instructions"
}
```
#### POST /v1/tokens/password-reset
**Permission:** Public
**Description:** Request password reset token
**Request Body:**
- `email` (string): User's email
**Example Request:**
```bash
curl -X POST \
-d '{"email": "alice.johnson@example.com"}' \
http://localhost:45067/v1/tokens/password-reset
```
**Response Body:**
- `message` (string): Confirmation message
**Example Response:**
```json
{
"message": "an email will be sent to you containing password reset instructions"
}
```
#### GET /debug/vars
**Permission:** Admin
**Description:** Displays application metrics for debugging purposes
**Request Headers:**
- `Authorization`: Bearer token
**Example Request:**
```bash
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:45067/debug/vars
```
**Response Body:**
- Various debugging metrics and application variables
## Database Schema
The application uses SQLite as its database engine with the following schema:
### Users Table
Stores user account information and credentials.
```sql
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL,
password_hash BLOB NOT NULL,
activated BOOLEAN NOT NULL DEFAULT false,
role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('user', 'admin')),
version INTEGER NOT NULL DEFAULT 1
);
```
**Columns:**
- `id`: Unique identifier for each user
- `created_at`: Timestamp of account creation
- `updated_at`: Timestamp of last account update
- `username`: Unique username
- `email`: Unique email address
- `password_hash`: Hashed user password (stored as BLOB)
- `activated`: Account activation status
- `role`: User role (either 'user' or 'admin')
- `version`: Record version for optimistic locking
An `updated_at` trigger automatically updates the timestamp when the record changes:
```sql
CREATE TRIGGER set_updated_at
AFTER UPDATE ON users
FOR EACH ROW
BEGIN
UPDATE users SET updated_at = CURRENT_TIMESTAMP WHERE id = OLD.id;
END;
```
### Tokens Table
Stores authentication, activation, and password reset tokens.
```sql
CREATE TABLE IF NOT EXISTS tokens (
hash BLOB PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
expiry DATETIME NOT NULL,
scope TEXT NOT NULL
);
```
**Columns:**
- `hash`: Hashed token value (primary key)
- `user_id`: Associated user ID (foreign key to users table)
- `expiry`: Token expiration timestamp
- `scope`: Token purpose/scope (e.g., 'authentication', 'activation', 'password-reset')
**Relationships:**
- `user_id` references the `id` column in the `users` table
- `ON DELETE CASCADE` ensures tokens are automatically deleted when the associated user is deleted
## Todo
- [ ] Write End-to-End tests