Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

A full-stack backend API for a Twitter clone ("Chirpy") built in Go. Implements a REST API, JWT authentication, password hashing, and a type-safe Postgres database layer using sqlc.

Notifications You must be signed in to change notification settings

shreyasganesh0/chirpy

Repository files navigation

Chirpy: A Go Backend API

This is a full-stack, production-ready backend service for a Twitter-like application called Chirpy, built entirely in Go.

This project was built to gain hands-on experience with the full lifecycle of a modern backend application: from designing a REST API and securing it, to managing a persistent database and handling auth, all the way to containerizing the final application with Docker.

Features Implemented

  • RESTful API: A clean, idiomatic Go API built using the chi router for all core application logic (users, chirps, etc.).
  • User Authentication: Full authentication and authorization system using JSON Web Tokens (JWTs) for both access and refresh tokens.
  • Password Security: User passwords are never stored in plaintext. They are securely hashed using the bcrypt algorithm.
  • Protected Endpoints: A custom authentication middleware (middlewareAuth.go) is used to protect specific API endpoints, validating the JWT bearer token on incoming requests.
  • Persistent Postgres Database: All application data (users, chirps) is stored in a Postgres database.
  • Type-Safe Database Queries: Uses sqlc to generate type-safe Go code directly from raw SQL queries, providing the speed of raw SQL with the safety of an ORM.
  • Database Migrations: The database schema is version-controlled and managed using a series of SQL migration files.
  • Containerized: Includes a Dockerfile for building and shipping the final application as a lightweight container.

Technical Deep Dive

1. JWT Generation & Authentication

A core part of this project is the internal/auth package, which is responsible for creating and validating tokens. New access tokens are created for users upon successful login and are signed using a JWT secret.

// From: internal/auth/auth.go
// MakeJWT generates a new JWT for a user
func MakeJWT(userID int, tokenSecret string, expiresIn time.Duration) (string, error) {
	signingKey := []byte(tokenSecret)

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{
		Issuer:    "chirpy",
		IssuedAt:  jwt.NewNumericDate(time.Now().UTC()),
		ExpiresAt: jwt.NewNumericDate(time.Now().UTC().Add(expiresIn)),
		Subject:   fmt.Sprintf("%d", userID),
	})

	return token.SignedString(signingKey)
}
This token is then validated by a middleware on protected routes, which checks the signature and extracts the userID from the token's claims.
  1. Secure User Creation with bcrypt When a new user is created, their password is processed by bcrypt before being stored in the database. This ensures that even if the database is compromised, the user passwords are not.
// From: internal/database/db.go
// CreateUser creates a new user and saves it to the database
func (db *DB) CreateUser(email, password string) (User, error) {
	hashedPassword, err := HashPassword(password) // Hash the password
	if err != nil {
		return User{}, err
	}

	params := CreateUserParams{
		Email:    email,
		HashedPassword: hashedPassword, // Store the hash, not the password
	}

	user, err := db.DB.CreateUser(context.Background(), params)
	if err != nil {
		return User{}, err
	}

	return user, nil
}
  1. Type-Safe SQL with sqlc Instead of using a heavy ORM or writing raw SQL strings in Go, this project uses sqlc. I write standard SQL queries (schema and queries), and sqlc generates idiomatic, type-safe Go code to execute them. This prevents SQL injection and catches errors at compile-time.

SQL Query:

-- name: CreateUser :one
INSERT INTO users (email, hashed_password)
VALUES ($1, $2)
RETURNING *;
  1. Auto-Generated Go Code (internal/database/users.sql.go):
const createUser = `-- name: CreateUser :one
INSERT INTO users (email, hashed_password)
VALUES ($1, $2)
RETURNING id, email, hashed_password
`

func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
	row := q.db.QueryRowContext(ctx, createUser, arg.Email, arg.HashedPassword)
	var i User
	err := row.Scan(&i.Id, &i.Email, &i.HashedPassword)
	return i, err
}

How to Run

  1. Make sure you have Go and Docker installed.

  2. A database.json file is required to run (or you can modify main.go to connect to a live Postgres instance).

  3. Build and run the server:

go run .
The server will start on http://localhost:8080.

About

A full-stack backend API for a Twitter clone ("Chirpy") built in Go. Implements a REST API, JWT authentication, password hashing, and a type-safe Postgres database layer using sqlc.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages