Skip to content

Expert · Careers and interviews · topic 45 of 46 · 50 min

Your portfolio project: a production-style Go API

Explanation

One finished, well-tested project beats ten half-done tutorials. Build a URL shortener or an expense API in Go with PostgreSQL, tests, a Dockerfile, CI that runs go vet and go test -race, graceful shutdown, structured logs and a clear README. Interviewers will open your repository and ask you to explain your choices.

Why a portfolio project matters

Go jobs for freshers are fewer than Java or Python jobs, so you must stand out. A clean Go repository proves you can use what interviewers ask about: HTTP handlers, JSON, SQL, errors, tests, concurrency and Docker. It also gives you real stories for "tell me about a challenge you faced" questions.

Pick one project

ProjectShowsStretch goals
URL shortenerREST API, PostgreSQL, unique codes, redirects, cachingClick stats, rate limiting per IP, expiry dates
Expense tracker APICRUD, validation, pagination, reports with SQL GROUP BYMonthly budgets, CSV export, user accounts with hashed passwords
Job queue / worker serviceConcurrency, retries, graceful shutdownPrometheus metrics, a CLI to enqueue jobs

The URL shortener, step by step

  1. Design the API: POST /v1/links {"url": "..."} returns {"code": "aZ3", "short_url": "..."}; GET /{code} redirects with 302; GET /v1/links/{code}/stats returns the click count.
  2. Create the table: id BIGSERIAL, code TEXT UNIQUE, url TEXT, clicks BIGINT, created_at TIMESTAMPTZ.
  3. Generate codes by base62-encoding the database id (short and unique), or random codes with a retry on conflict.
  4. Validate URLs with net/url (scheme must be http or https) and limit their length.
  5. Write handlers, middleware (logging, recovery, request ID) and a Store interface with a PostgreSQL implementation.
  6. Write table-driven tests for base62 and validation, and httptest tests for handlers using a fake store.
  7. Add config from env, graceful shutdown, /healthz and /readyz.
  8. Add a multi-stage Dockerfile and a docker-compose.yml that starts the API and PostgreSQL together.
  9. Add CI (below), a README with curl examples, and a short "design decisions" section.
go
const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

// base62 turns a positive id into a short code: 125 -> "21", 62 -> "10".
func base62(n uint64) string {
	if n == 0 {
		return "0"
	}
	var b []byte
	for n > 0 {
		b = append(b, alphabet[n%62])
		n /= 62
	}
	slices.Reverse(b)
	return string(b)
}
Small, pure functions like this are perfect for table-driven and fuzz tests.

CI with GitHub Actions

yaml
name: ci
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: stable
      - run: go vet ./...
      - run: go test -race -cover ./...
      - run: go build ./...
Save as .github/workflows/ci.yml. A green badge on every commit shows you work like a professional team.

A README that sells your work

  • One paragraph: what it does and the tech used (Go, net/http, PostgreSQL, Docker).
  • How to run it in one command: docker compose up.
  • curl examples for every endpoint, with real responses.
  • A simple architecture sketch: handler → service → store → PostgreSQL.
  • Design decisions: why base62 ids, why 302 not 301, how you avoided SQL injection, what you would do for 10x traffic (caching, read replicas).
  • What you tested and how (go test -race -cover).

What interviewers check in your repo

They look atMake sure
main.goIt only wires things together and shuts down gracefully
Error handlingNo ignored errors; wrapped with context; no internal details leaked to clients
SQLPlaceholders everywhere; rows closed; context passed
TestsTable-driven, meaningful names, pass with -race
CommitsSmall, clear messages over several days, not one giant "final" commit
SecretsNo .env or passwords committed; config from env vars
Careful: Do not copy a project from a tutorial and change the name. Interviewers ask "why did you do X?" and it becomes obvious quickly. Build it yourself, even if it is smaller, and be able to explain every line.
Tip: Write a short blog post or LinkedIn post about one problem you solved (for example the slice aliasing bug you hit, or how you made shutdown graceful). It shows communication skills, which matter as much as code.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Your portfolio project: a production-style Go API · 1/7

Your portfolio project

One finished, tested project beats ten half-done tutorials, especially when Go jobs for freshers are fewer.

Prefer a video by a teacher? Find free videos on “golang url shortener project postgres docker github actions” on YouTube ↗

In real life: From project to interview story

Priya, a final-year student from Nagpur, built a URL shortener in Go over three weekends. During testing with -race she found a data race in her in-memory click counter and fixed it with atomic.Int64, then moved counts to PostgreSQL with UPDATE ... SET clicks = clicks + 1. In her interview she told exactly this story, showed the failing race report and the fix, and was asked to extend the project live with an expiry date. That project, not her CGPA, was what the interviewers discussed.

output
expense-or-shortener/
├── .github/workflows/ci.yml
├── Dockerfile
├── docker-compose.yml
├── README.md
├── go.mod / go.sum
├── main.go
├── migrations/001_init.sql
└── internal/
    ├── link/       base62, validation (+ tests, fuzz test)
    ├── store/      PostgreSQL store
    └── httpapi/    handlers, middleware (+ httptest tests)
A layout an interviewer can understand in one minute.

Practice (0/4 done)

Task 1 · Question

Using the base62 function in this topic, what is base62(62)?

Task 2 · Question

Which is the strongest signal in a fresher's Go repository?

Task 3 · Question

Why might a URL shortener redirect with 302 instead of 301?

Task 4 · Practice

Build your portfolio project over three weeks: week 1 API and in-memory store with tests; week 2 PostgreSQL, middleware, config and graceful shutdown; week 3 Docker, docker compose, CI and README. Push to GitHub with small commits.

Quick quiz

Question 1

1.Where should database passwords for your project live?

Question 2

2.What should the CI pipeline run at minimum?

Question 3

3.Why do small, regular commits help in interviews?

Question 4

4.Which validation should a URL shortener do on input URLs?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Where should database passwords for your project live?

Answer: In environment variables, never committed

Commit an example config without real secrets, if anything.

What should the CI pipeline run at minimum?

Answer: go vet, go test -race and go build

Vet, race-enabled tests and a build catch most problems early.

Why do small, regular commits help in interviews?

Answer: They show how you worked and that you built it yourself

History tells a story of real work.

Which validation should a URL shortener do on input URLs?

Answer: Parse with net/url, allow only http/https, and limit length

Rejecting odd schemes (like javascript:) and huge inputs protects users and your database.

Your weather project needs an API key that must stay secret. Where should it go?Related

Answer: Not in front-end code at all: use a small server or an API that needs no secret key

Anything shipped to the browser, VITE_ variables included, is public. Secrets need a server.

From Your portfolio project

How do you make a GitHub profile README?Related

Answer: Create a public repository with exactly the same name as your username and add README.md

GitHub shows the README.md of the repository named after your username at the top of your profile.

From Your portfolio and GitHub

What is the best first step for a portfolio project?Related

Answer: Get a simple version working end to end, then improve it

Finish a simple, working version first.

From Your portfolio project: a tested Web API with EF Core

Why should an alert include a runbook_url?Related

Answer: The person paged can follow written first steps instead of guessing at 3 a.m.

A runbook link turns an alert into a clear next action.

From Capstone project: from commit to monitored production

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Careers and interviews” before its exam: Go careers in India and a 30-day revision plan.
  2. Module 10 exam: Careers and interviews · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. 46 topics left in the course before the final exam.

← Previous: Concurrency interview questions and coding rounds