# Go - Blueprint (/docs/blueprints/go)



REST API backend built with **Go 1.23**, **Gin**, and **PostgreSQL**. A deploy-ready starting point: one table, one API endpoint, Swagger UI, full Docker support out of the box.

**Tech stack:**

| Layer           | Technology                |
| --------------- | ------------------------- |
| Language        | Go 1.23                   |
| HTTP framework  | Gin                       |
| Database driver | pgx/v5 (pgxpool)          |
| Migrations      | golang-migrate (embedded) |
| API docs        | swaggo/swag + gin-swagger |

The application starts on port **8080** (overridable via `PORT`). Opening `/` redirects to the Swagger UI at `/swagger/index.html`.

<a href="https://github.com/rock8-cloud/template-go" target="_blank" rel="noopener noreferrer">
  View on GitHub →
</a>

***

## Project Structure [#project-structure]

```
├── main.go              # Entry point: Gin router, migrations, PORT env var
├── db.go                # Connection string builder + pgxpool setup
├── migrate.go           # golang-migrate with embedded migrations/
├── handler.go           # SpaceTarget struct, infoHandler, listTargets
├── migrations/
│   ├── 000001_init.up.sql    # Creates space_target table + seed data
│   └── 000001_init.down.sql  # Drops the table
└── docs/                # Auto-generated by swag init - do not edit manually
```

**Key design decisions:**

* `db.go` builds the connection string from `DATABASE_URL` (if set) or from individual `DB_*` variables, then creates a `pgxpool.Pool` - a connection pool managed by pgx directly, without an ORM.
* `migrate.go` embeds the `migrations/` directory at compile time using `//go:embed`. On startup, `main.go` runs migrations before the server accepts requests.
* Swagger docs are generated from Go annotations in `handler.go` by `swag init`. The `docs/` directory is committed to the repo so the binary can be built without the `swag` tool at runtime. When adding new endpoints, regenerate with `swag init`.
* The Dockerfile runs `swag init` in the build stage so the final image is always up to date.
* To add a new endpoint: add a handler function with swag annotations in `handler.go` (or a new file), register the route in `main.go`, and run `swag init`.

***

## Environment Variables [#environment-variables]

The application runs on port **8080** by default.

| Variable | Required | Default | Description |
| -------- | -------- | ------- | ----------- |
| `PORT`   | no       | `8080`  | HTTP port   |

Database connection is configured via **one of two approaches**:

### Option A - Single connection URL (recommended for managed services) [#option-a---single-connection-url-recommended-for-managed-services]

| Variable       | Required | Example                                                 |
| -------------- | -------- | ------------------------------------------------------- |
| `DATABASE_URL` | yes      | `postgres://user:pass@host:5432/dbname?sslmode=require` |

### Option B - Individual variables [#option-b---individual-variables]

| Variable      | Required | Default     | Description                           |
| ------------- | -------- | ----------- | ------------------------------------- |
| `DB_HOST`     | no       | `localhost` | Database host                         |
| `DB_PORT`     | no       | `5432`      | Database port                         |
| `DB_NAME`     | no       | `spacedb`   | Database name                         |
| `DB_USER`     | no       | `postgres`  | Database user                         |
| `DB_PASSWORD` | no       | `postgres`  | Database password                     |
| `DB_SSL_MODE` | no       | `disable`   | SSL mode, e.g. `require` or `disable` |

`DATABASE_URL` takes precedence. If it is set, the individual `DB_*` variables are ignored.

***

## Running Locally [#running-locally]

### With Docker Compose [#with-docker-compose]

```bash
docker compose up
```

Starts the application together with a PostgreSQL instance and sets `DATABASE_URL` automatically. No additional configuration needed.

### Standalone [#standalone]

```bash
# install swag once (generates Swagger docs from annotations)
go install github.com/swaggo/swag/cmd/swag@latest

# generate docs and build
swag init
go build -o server .

# run - Option A
DATABASE_URL=postgres://postgres:postgres@localhost:5432/spacedb?sslmode=disable ./server

# run - Option B
DB_HOST=localhost DB_USER=postgres DB_PASSWORD=secret ./server

# or run without building
swag init && DATABASE_URL=postgres://postgres:postgres@localhost:5432/spacedb?sslmode=disable go run .
```
