
Backend development often involves repetitive boilerplate code, especially when dealing with database queries and API server implementations. Writing and maintaining this code manually can be error-prone and time-consuming. Code generation (codegen) tools help automate these tasks by generating type-safe, efficient, and maintainable code from declarative specifications.
In this article, we'll explore how to simplify backend logic in Go by using two popular codegen tools:
sqlc is a tool that generates Go code from SQL queries. You write your SQL queries in .sql files, and sqlc generates Go functions that execute those queries with type-safe parameters and results.
sqlc.yaml to specify input/output.sqlc generate to produce Go code.Suppose you have a simple users table:
-- schema.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);And a query to get a user by email:
-- queries.sql
-- name: GetUserByEmail :one
SELECT id, name, email FROM users WHERE email = $1;Your sqlc.yaml config:
version: "1"
packages:
- name: "db"
path: "./db"
queries: "./queries.sql"
schema: "./schema.sql"
engine: "postgresql"Run:
sqlc generateThis generates Go code with a method like:
func (q *Queries) GetUserByEmail(ctx context.Context, email string) (User, error)You can use it in your backend:
user, err := dbQueries.GetUserByEmail(ctx, "alice@example.com")
if err != nil {
// handle error
}
fmt.Println("User:", user.Name)This eliminates manual SQL string handling and scanning rows, making your code cleaner and safer.
oapi-codegen generates Go server (and client) code from an OpenAPI (Swagger) specification. It creates interfaces and request/response types, so you can focus on implementing business logic.
oapi-codegen to generate Go server code.Consider a simple OpenAPI spec api.yaml:
openapi: 3.0.0
info:
title: User API
version: 1.0.0
paths:
/users/{email}:
get:
summary: Get user by email
parameters:
- name: email
in: path
required: true
schema:
type: string
responses:
"200":
description: User found
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"404":
description: User not found
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
email:
type: stringGenerate server code:
oapi-codegen -generate types,server -package api -o api.gen.go api.yamlThis generates:
User struct)ServerInterface with method:GetUsersEmail(ctx context.Context, email string) (api.User, error)Implement the interface:
type ServerImpl struct {
db *db.Queries
}
func (s *ServerImpl) GetUsersEmail(ctx context.Context, email string) (api.User, error) {
user, err := s.db.GetUserByEmail(ctx, email)
if err != nil {
return api.User{}, err
}
return api.User{
Id: int64(user.ID),
Name: user.Name,
Email: user.Email,
}, nil
}Wire up the server:
router := api.NewRouter(&ServerImpl{db: dbQueries})
http.ListenAndServe(":8080", router)Using sqlc and oapi-codegen together can greatly simplify backend development in Go by automating the generation of database access and API server code. This approach reduces boilerplate, improves safety, and accelerates development, allowing you to focus on what matters most: your application's core logic.
© Melvin Laplanche - All rights reserved.