Project 8: api-forge

Build a CLI that generates API clients or server stubs from schemas.

Quick Reference

Attribute Value
Difficulty Level 3 (Advanced)
Time Estimate 2 weeks
Language Rust (Alternatives: Go, Python)
Prerequisites CLI basics, HTTP, JSON/YAML
Key Topics Schema parsing, code generation, templates

1. Learning Objectives

By completing this project, you will:

  1. Parse and validate OpenAPI-like schemas.
  2. Build a code generation pipeline from schema to files.
  3. Handle local and remote schema sources safely.
  4. Produce deterministic output that is stable across runs.
  5. Design template-based generation for extensibility.

2. Theoretical Foundation

2.1 Core Concepts

  • Schemas: OpenAPI defines endpoints, methods, parameters, and responses. Your generator reads a subset.
  • Validation: Without validation, code generation emits invalid or incomplete output.
  • Code Generation: Structured templates produce consistent output with predictable naming.
  • Determinism: Generated code must be stable to avoid unnecessary diffs.

2.2 Why This Matters

Schema-driven tooling powers SDKs, docs, and mocks. Building a generator teaches you to map abstract definitions into concrete code artifacts.

2.3 Historical Context / Background

Swagger/OpenAPI popularized schema-first design. Tools like openapi-generator and swagger-codegen automate client SDK creation; your tool recreates core mechanics.

2.4 Common Misconceptions

  • “Parsing YAML is enough”: You must validate structure and required fields.
  • “Generation is trivial”: Naming conventions, imports, and types are complex.

3. Project Specification

3.1 What You Will Build

A CLI named api-forge that can:

  • Load a schema from file or URL
  • Validate required schema fields
  • Generate client stubs for a chosen language
  • Emit JSON metadata for tooling

3.2 Functional Requirements

  1. Schema input: --schema supports file path or URL.
  2. Validation: Check required sections (paths, components).
  3. Generation: Output client stubs in chosen language.
  4. Output modes: Table log or JSON summary.

3.3 Non-Functional Requirements

  • Determinism: Same schema yields same output order.
  • Safety: Do not overwrite existing output without --force.
  • Performance: Handle schemas with 100+ endpoints.

3.4 Example Usage / Output

$ api-forge generate --schema openapi.yaml --lang go --out ./client
Generated client/client.go
Generated client/models.go

3.5 Real World Outcome

After generation, the output directory contains:

  • client.go with a typed API client
  • models.go with request/response structs
  • README.md documenting usage

You can then import the client in an app and call endpoints with structured types.


4. Solution Architecture

4.1 High-Level Design

+-------------+     +-----------------+     +------------------+
| Schema Load | --> | Validator       | --> | Generator        |
+-------------+     +-----------------+     +------------------+
          |                   |                    |
          +-------------------+--------------------+
                        Templates

4.2 Key Components

Component Responsibility Key Decisions
Loader Fetch schema URL vs file
Validator Check required fields fail-fast vs warnings
Model Normalize schema naming rules
Generator Render templates template engine

4.3 Data Structures

struct Endpoint {
    method: String,
    path: String,
    request_type: Option<String>,
    response_type: Option<String>,
}

4.4 Algorithm Overview

Key Algorithm: Schema -> code

  1. Load schema (file or URL).
  2. Validate required fields and normalize types.
  3. Build internal model of endpoints.
  4. Render templates into output files.

Complexity Analysis:

  • Time: O(E) for E endpoints
  • Space: O(E) for model storage

5. Implementation Guide

5.1 Development Environment Setup

cargo new api-forge
cargo add clap reqwest serde_yaml tera

5.2 Project Structure

api-forge/
├── src/
│   ├── main.rs
│   ├── load.rs
│   ├── validate.rs
│   ├── model.rs
│   └── generate.rs
├── templates/
│   ├── client.rs.tmpl
│   └── models.rs.tmpl
└── README.md

5.3 The Core Question You Are Answering

“How do I transform abstract API definitions into stable, usable code artifacts?”

5.4 Concepts You Must Understand First

  1. OpenAPI schema basics
  2. HTTP method semantics
  3. Template rendering
  4. Naming and type mapping

5.5 Questions to Guide Your Design

  1. How will you map schema types to language types?
  2. How do you ensure deterministic ordering of endpoints?
  3. Should generation overwrite existing files?

5.6 Thinking Exercise

Given a simple schema with two endpoints, manually sketch the generated client functions and types.

5.7 The Interview Questions They Will Ask

  1. Why is deterministic output important in generators?
  2. How do you validate schema correctness?
  3. What are the tradeoffs of template-based generation?

5.8 Hints in Layers

Hint 1: Start with a tiny schema and one endpoint.

Hint 2: Generate a single file first, then split into models and client.

Hint 3: Add sorting by path/method to keep output stable.

5.9 Books That Will Help

Topic Book Chapter
Web APIs “Design and Build Great Web APIs” Ch. 3
Data modeling “Designing Data-Intensive Applications” Ch. 4

5.10 Implementation Phases

Phase 1: Foundation (3-4 days)

Goals:

  • Schema loading
  • Basic validation

Checkpoint: Schema errors are detected.

Phase 2: Generation (5-6 days)

Goals:

  • Internal model
  • Template rendering

Checkpoint: Client stubs generated.

Phase 3: Polish (2-3 days)

Goals:

  • JSON output mode
  • Deterministic ordering

Checkpoint: Re-running produces identical output.


6. Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Validator missing fields
Integration Tests End-to-end schema -> files
Edge Cases Large schema 100+ endpoints

6.2 Critical Test Cases

  1. Missing paths should error.
  2. Endpoint with unknown type should warn or map to string.
  3. Output is deterministic across runs.

7. Common Pitfalls and Debugging

Pitfall Symptom Solution
Non-deterministic output Flaky diffs Sort endpoints
Weak validation Broken code Enforce required fields
Overwriting files Data loss Require --force

8. Extensions and Challenges

8.1 Beginner Extensions

  • Add --dry-run mode
  • Add --list-endpoints

8.2 Intermediate Extensions

  • Add docs generator
  • Add mock server stubs

8.3 Advanced Extensions

  • Add multiple language targets
  • Add plugin-based templates

9. Real-World Connections

  • SDK generation in API platforms
  • CI pipeline validation of schemas

10. Resources

  • OpenAPI spec
  • openapi-generator source for ideas

11. Self-Assessment Checklist

  • I can explain schema validation
  • I can keep generated output deterministic

12. Submission / Completion Criteria

Minimum Viable Completion:

  • Validate schema and generate basic stub

Full Completion:

  • Deterministic output + JSON summary

Excellence (Going Above and Beyond):

  • Multiple language targets and plugin templates