Files
go-simple-api/docs/API.md
T
2026-07-16 10:13:46 +03:30

5.1 KiB

API Reference

Base URL (local dev): http://localhost:8080

All request/response bodies are JSON. Authenticated endpoints rely on the session_id cookie set by /login or the Google OAuth callback - include it automatically by using a cookie-aware HTTP client (browsers do this natively; with curl, use -c cookies.txt -b cookies.txt).


GET /health

Liveness check. No authentication, no rate limiting beyond the global limit.

Response 200

{ "status": "ok" }
curl http://localhost:8080/health

POST /register

Creates a new password-based account.

Rate limited to 5 requests/minute per IP (shared with /login).

Request body

{ "email": "hamid@example.com", "password": "secret123" }
  • email - required, must be unique across all accounts.
  • password - required, minimum 8 characters.

Response 201

{ "id": 1, "email": "hamid@example.com" }

Errors

Status Body Cause
400 {"error":"invalid request body"} Malformed JSON
400 {"error":"email and password are required"} Missing field
400 {"error":"password must be at least 8 characters"} Password too short
409 {"error":"email already registered"} Email already taken
429 (rate limit response) Too many requests from this IP
500 {"error":"internal error"} Unexpected server/database failure
curl -X POST http://localhost:8080/register \
  -H "Content-Type: application/json" \
  -d '{"email":"hamid@example.com","password":"secret123"}'

POST /login

Authenticates with email + password and starts a server-side session.

Rate limited to 5 requests/minute per IP (shared with /register).

Request body

{ "email": "hamid@example.com", "password": "secret123" }

Response 200

{ "id": 1, "email": "hamid@example.com" }

Also sets a session_id cookie (HttpOnly, SameSite=Lax, Secure in production).

Errors

Status Body Cause
400 {"error":"invalid request body"} Malformed JSON
401 {"error":"invalid email or password"} No such email, OR wrong password (identical message for both, deliberately - see Security notes in the README)
429 (rate limit response) Too many requests from this IP
500 {"error":"internal error"} Unexpected server/database failure
curl -c cookies.txt -X POST http://localhost:8080/login \
  -H "Content-Type: application/json" \
  -d '{"email":"hamid@example.com","password":"secret123"}'

POST /logout

Destroys the current session (deletes it from Redis, expires the cookie). Not rate-limited beyond the global limit - deliberately excluded from the strict /login//register limit so a legitimate user can always log out.

Response 200

{ "message": "logged out" }
curl -b cookies.txt -c cookies.txt -X POST http://localhost:8080/logout

GET /me

Requires authentication (a valid session_id cookie from a prior login). Returns the currently logged-in user.

Response 200

{ "id": 1, "email": "hamid@example.com" }

Errors

Status Body Cause
401 {"error":"unauthorized"} No session, expired session, or the session's user no longer exists
curl -b cookies.txt http://localhost:8080/me

GET /auth/google/login

Redirects the browser to Google's OAuth2 consent screen. Must be opened in an actual browser - this endpoint returns an HTTP redirect, and the subsequent Google login page cannot be driven via curl.

Response: 307 Temporary Redirect to accounts.google.com.

open http://localhost:8080/auth/google/login

GET /auth/google/callback

Google redirects here automatically after the user approves access. Not meant to be called directly - state and code query parameters are supplied by Google.

On success: creates a new user (or links Google to an existing email-matched account), starts a session exactly like /login does, and returns:

Response 200

{ "id": 2, "email": "hamid@gmail.com" }

Errors

Status Body Cause
400 {"error":"invalid oauth state"} Missing/mismatched CSRF state - usually means the flow wasn't started via /auth/google/login, or the session expired mid-flow
400 {"error":"missing code"} Google didn't include an authorization code
500 {"error":"internal error"} Token exchange, Google API call, or database failure

General notes

  • CORS: browser-based requests from an origin not listed in ALLOWED_ORIGINS will be blocked by the browser itself, before this API's own logic ever runs. Non-browser clients (curl, mobile apps, server-to-server) are unaffected by CORS entirely.
  • Rate limiting: exceeding a limit returns HTTP 429 Too Many Requests. The global limit (100/min/IP) applies to every route; the strict limit (5/min/IP) applies only to /register and /login, and stacks with the global limit.
  • All error responses share the same shape: {"error": "<message>"}.