Expert · Careers and interviews · topic 45 of 46 · 50 min
Your portfolio project: a production-style Go API
Explanation
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
| Project | Shows | Stretch goals |
|---|---|---|
| URL shortener | REST API, PostgreSQL, unique codes, redirects, caching | Click stats, rate limiting per IP, expiry dates |
| Expense tracker API | CRUD, validation, pagination, reports with SQL GROUP BY | Monthly budgets, CSV export, user accounts with hashed passwords |
| Job queue / worker service | Concurrency, retries, graceful shutdown | Prometheus metrics, a CLI to enqueue jobs |
The URL shortener, step by step
- 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.
- Create the table: id BIGSERIAL, code TEXT UNIQUE, url TEXT, clicks BIGINT, created_at TIMESTAMPTZ.
- Generate codes by base62-encoding the database id (short and unique), or random codes with a retry on conflict.
- Validate URLs with net/url (scheme must be http or https) and limit their length.
- Write handlers, middleware (logging, recovery, request ID) and a Store interface with a PostgreSQL implementation.
- Write table-driven tests for base62 and validation, and httptest tests for handlers using a fake store.
- Add config from env, graceful shutdown, /healthz and /readyz.
- Add a multi-stage Dockerfile and a docker-compose.yml that starts the API and PostgreSQL together.
- Add CI (below), a README with curl examples, and a short "design decisions" section.
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)
}CI with GitHub Actions
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 ./...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 at | Make sure |
|---|---|
| main.go | It only wires things together and shuts down gracefully |
| Error handling | No ignored errors; wrapped with context; no internal details leaked to clients |
| SQL | Placeholders everywhere; rows closed; context passed |
| Tests | Table-driven, meaningful names, pass with -race |
| Commits | Small, clear messages over several days, not one giant "final" commit |
| Secrets | No .env or passwords committed; config from env vars |
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
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.
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)Practice (0/4 done)
Using the base62 function in this topic, what is base62(62)?
Which is the strongest signal in a fresher's Go repository?
Why might a URL shortener redirect with 302 instead of 301?
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Go careers in India and a 30-day revision planCareers and interviews · same module
- Go language interview questionsCareers and interviews · same module
- Your portfolio projectFrontend Web Development · Build, deploy and get hired
- Your portfolio and GitHubFull-Stack Development · Capstone, portfolio and getting work
- Your portfolio project: a tested Web API with EF CoreC# and .NET · Interviews, portfolio and careers
- Capstone project: from commit to monitored productionDevOps: Git, Docker, Kubernetes and CI/CD · GitOps, platform engineering and DevOps careers
Questions people ask about this
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.
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.
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.
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.
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 more topic in “Careers and interviews” before its exam: Go careers in India and a 30-day revision plan.
- Module 10 exam: Careers and interviews · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
- 46 topics left in the course before the final exam.
← Previous: Concurrency interview questions and coding rounds