# Backend API (https://docs.helico.site/docs/backend-api)

The blog's API in Go. One SQLite file, posts served as JSON with the HTML rendered.

[`apps/be`](https://github.com/0xHelico/helico/tree/main/apps/be) serves the posts the landing's blog shows. Markdown files
in `content/` stay the source of truth and are seeded into one SQLite file.

```bash
cd apps/be
BE_ADMIN_TOKEN=change-me go run ./cmd/be     # :8787
go vet ./... && gofmt -l . && go test -race ./...
```

| Variable             | Default                                       |
| -------------------- | --------------------------------------------- |
| `BE_ADDR`            | `:8787`                                       |
| `BE_DB_PATH`         | `data/helico.db`                              |
| `BE_ADMIN_TOKEN`     | empty; writes refused with `503`              |
| `BE_CORS_ORIGINS`    | `http://localhost:4321,http://localhost:4322` |
| `BE_CONTENT_DIR`     | `content`                                     |
| `BE_REQUEST_TIMEOUT` | `10s`                                         |

| Route                             | Auth   | Answer                                                        |
| --------------------------------- | ------ | ------------------------------------------------------------- |
| `GET /healthz`                    |        | ok                                                            |
| `GET /api/posts?limit=20&cursor=` |        | items and a keyset cursor, newest first, `ETag`               |
| `GET /api/posts/slug`             |        | the post with `html` and `markdown`; `304` on `If-None-Match` |
| `PUT /api/posts/slug`             | bearer | create `201` or replace `200`                                 |
| `DELETE /api/posts/slug`          | bearer | `204`                                                         |

Errors are `application/problem+json`; JSON over 1 KiB is gzipped; reads carry
`Cache-Control: public, max-age=60, stale-while-revalidate=300`.
