# Snippet Sharing API A Go + PostgreSQL REST API for sharing code snippets (Assignment 3), with a full test suite (Assignment 4). **Name:** Zagar Nashrullah **NRP:** 5803025048 Module: `5803025048/W04` ## Run the server Set the database variables, then start the server. It listens on `PORT` (default `8080`). ```powershell $env:DB_HOST="..."; $env:DB_PORT="..." $env:DB_USER="..."; $env:DB_PASSWORD="..."; $env:DB_NAME="..." go run ./cmd/server/main.go ``` `PORT` is the HTTP port of the API. `DB_PORT` is the PostgreSQL port. ## Run the tests Each layer has its own command: ``` go test ./internal/auth/... # unit tests go test ./internal/middleware/... # unit tests, hand-written fake go test ./internal/handler/... # unit tests, hand-written fakes go test ./internal/store/... # integration tests, real PostgreSQL go test ./e2e/... # black-box tests over HTTP ``` What each layer needs: - **auth, middleware, handler:** nothing. - **store:** the `DB_*` variables, and `DB_NAME` **must end in `_test`**. - **e2e:** a running server. It uses `API_BASE_URL` (default `http://localhost:8080`). To run everything the way the grader does (start the server first, because `./...` includes e2e): ``` go vet ./... go test -race -shuffle=on -count=2 ./... go test -coverpkg=./internal/... -coverprofile=cover.out ./internal/... ``` ### Warning: store tests wipe the database The store tests `TRUNCATE` all tables at the start of every test. For safety, `TestMain` in `internal/store` refuses to run unless `DB_NAME` ends in `_test` (for example `w04_5803025048_test`). Never point them at a real database. If the `DB_*` variables are missing or the database is unreachable, the tests fail. They never skip. The e2e tests create their own unique usernames, so they work against a server that already has data. ## Bugs My Tests Found Defects in my Assignment 3 code that these tests exposed, and how I fixed them: 1. **Errors were not JSON.** Every 400/401/403/404/409/500 used `http.Error`, which sends `text/plain`. *Fix:* a JSON error writer in the handlers and in the middleware. 2. **A token without the `Bearer` scheme was accepted.** The middleware and logout used the whole header as the token. *Fix:* one strict `middleware.BearerToken` helper. A missing scheme, `Basic ...`, or an empty token now gives 401. 3. **Logout returned 204 for tokens that did not exist.** *Fix:* logout checks that the session exists and returns 401 otherwise. 4. **"Not found" leaked the database driver.** Handlers compared against `pgx.ErrNoRows`, and `SnippetStore.Delete` returned `nil` for an unknown id. *Fix:* added `store.ErrNotFound`, returned by every lookup. `Delete` returns it when no row was affected. 5. **Passwords longer than 72 bytes caused a 500 on `/register`** (bcrypt rejects them). *Fix:* they now return 400. 6. **Username length was counted in bytes, not characters.** *Fix:* it is now counted in runes. 7. **`GET /snippets` could return `null` for an empty list.** *Fix:* the handler always returns `[]`, even if the store returns a nil slice. 8. **Any login lookup error was reported as 401.** *Fix:* a real database failure is now 500. Only "user not found" and "wrong password" give the (identical) 401. ## Refactor for testability No behavior change. Handlers depend on the `UserStore`, `SessionStore` and `SnippetStore` interfaces (package `handler`). The middleware depends on a small `SessionLookup` interface. The concrete types in `internal/store` satisfy them without importing `handler` or `middleware`.