Auto-Generated API Docs: Scalar & Swagger in Grit
Every API needs documentation. Other developers (and your future self) need to know what endpoints exist, what parameters they accept, and what they return. In this course, you will learn how Grit auto-generates interactive API documentation using gin-docs — no annotations required. You'll explore the Scalar UI, test endpoints live, and export the OpenAPI spec.
What is API Documentation?
Imagine you inherit a project with 50 API endpoints. No documentation. No comments. You have to read every handler, every route, every model to figure out what the API does. That's a nightmare — and it's surprisingly common. API documentation solves this by providing a clear, browsable reference of every endpoint your API offers.
Why does documentation matter? Three reasons:
- • For other developers: Frontend developers, mobile developers, and third-party integrators need to know your API's contract without reading Go code
- • For your future self: You will forget what endpoints exist, what parameters are required, and what the response looks like. Documentation is your memory
- • For testing: Interactive docs let you test endpoints directly in the browser — no Postman, no curl, no frontend needed
Challenge: Reflect on Undocumented APIs
Have you ever used an API without documentation? How was the experience? Think about how you figured out what endpoints existed, what parameters to send, and what the response looked like. Write down 3 problems you encountered (or would encounter) when using an undocumented API.
How gin-docs Works
Most API documentation tools require you to write annotations — special comments above every handler function describing the endpoint. That's tedious and error-prone because the annotations can drift out of sync with the actual code. Grit takes a different approach.
Grit uses gin-docs to auto-generate OpenAPI 3.1 specifications. No annotations needed. It works by introspecting your Gin routes and GORM models at startup.
Here's what gin-docs does when your API starts:
- 1.Scans your Gin router. It reads every registered route — the HTTP method, the URL path, the middleware chain, and the handler function.
- 2.Reads your GORM models. It inspects the struct fields, their types, JSON tags, and GORM tags to generate request/response schemas.
- 3.Generates the OpenAPI 3.1 spec. A complete JSON specification describing every endpoint, parameter, request body, and response schema.
- 4.Serves the Scalar UI. The interactive documentation is available at
/docsin your browser.
# Start your Grit API
cd apps/api && go run cmd/server/main.go
# Open your browser
http://localhost:8080/docs
# That's it. No annotations. No swagger comments.
# No yaml files to maintain. Just your routes and models.grit generate resource, the documentation updates automatically on the next server restart. The new endpoints, request schemas, and response schemas all appear in /docs without any additional work.Challenge: Explore Your API Docs
Open http://localhost:8080/docs in your browser. How many endpoint groups do you see? List the group names (e.g., Auth, Users, etc.). How many total endpoints are documented?
The Scalar UI
When you open /docs, you see the Scalar UI — a modern, interactive documentation interface. Let's walk through its key features.
The left sidebar shows all your endpoint groups, organized by route prefix. Click a group to expand it and see individual endpoints. Each endpoint shows:
- • HTTP method badge — color-coded: green for GET, blue for POST, orange for PUT, red for DELETE
- • URL path — the full endpoint path including path parameters like
/api/users/:id - • Description — auto-generated from the handler name and route
- • Request builder — fill in parameters and body, then click Send to test the endpoint live
- • Response preview — shows the actual response with syntax highlighting
- • Authentication indicator — shows whether the endpoint requires a JWT token
Challenge: Test an Endpoint Live
Find the POST /api/auth/login endpoint in the Scalar UI. Fill in the email and password fields in the request builder. Click "Send." Does it return a token? What other fields are in the response?
Request & Response Schemas
One of gin-docs' most powerful features is automatic schema generation. It reads your GORM models and generates JSON schemas that describe the shape of request bodies and response payloads.
For example, consider a simple User model:
type User struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `gorm:"size:255;not null" json:"name" binding:"required"`
Email string `gorm:"uniqueIndex;not null" json:"email" binding:"required,email"`
Password string `gorm:"not null" json:"-"`
Role string `gorm:"default:USER" json:"role"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}From this model, gin-docs automatically generates:
- • A request schema for POST/PUT — includes name, email, role (excludes id, password, timestamps)
- • A response schema for GET — includes id, name, email, role, timestamps (excludes password)
- • Required field markers — from the
binding:"required"tag - • Type information — string, integer, boolean, datetime for each field
Fields with json:"-" (like Password and DeletedAt) are excluded from the documentation entirely. This is important — your docs never expose sensitive fields.
binding tag does double duty. It validates incoming requests AND tells gin-docs which fields are required. binding:"required" means the field shows as required in the docs, and the API returns a 422 error if it's missing.Challenge: Watch Schemas Appear
Generate a new resource with several fields:
grit generate resource Product --fields "name:string,price:float,description:text:optional,sku:string,in_stock:bool"Restart your API and refresh /docs. Does the Product schema appear? Can you see which fields are marked as required vs optional?
Authentication in Docs
Many endpoints require authentication — they expect a JWT token in the request headers. When you try to call a protected endpoint without a token, you get a 401 Unauthorized error. The Scalar UI lets you set your authentication token so you can test protected endpoints directly.
Here's the workflow:
- 1.Login via the docs. Find
POST /api/auth/login, enter your email and password, click Send. Copy theaccess_tokenfrom the response. - 2.Set the token. Look for the "Authentication" or "Auth" section in Scalar. Select "Bearer Token" and paste your access token.
- 3.Test protected endpoints. Now every request you send from the docs will include the
Authorization: Bearer <token>header automatically.
Challenge: Authenticate and Test
Login via /docs using POST /api/auth/login. Copy the access token from the response. Set it in the Scalar authentication section. Then call GET /api/users. Do you get a list of users? What happens if you remove the token and try again?
Testing Endpoints
The Scalar UI is a complete API testing tool. Let's walk through testing all five CRUD operations for a resource.
POST — Create a Resource
Find the POST endpoint for your resource (e.g., POST /api/products). The request builder shows the JSON body schema with all required fields. Fill in the values and click Send. A successful creation returns a 201 Created status with the new resource in the response body.
POST /api/products
Content-Type: application/json
Authorization: Bearer <your-token>
{
"name": "Wireless Keyboard",
"price": 79.99,
"description": "Bluetooth mechanical keyboard",
"sku": "KB-001",
"in_stock": true
}
// Response: 201 Created
{
"data": {
"id": 1,
"name": "Wireless Keyboard",
"price": 79.99,
"description": "Bluetooth mechanical keyboard",
"sku": "KB-001",
"in_stock": true,
"created_at": "2026-03-27T10:00:00Z",
"updated_at": "2026-03-27T10:00:00Z"
},
"message": "Product created successfully"
}GET — List Resources
The list endpoint supports pagination. Use query parameters ?page=1&page_size=10 to control which page of results you see. The response includes a meta object with total count, current page, and total pages.
GET — Single Resource
Use the ID from a previous creation. For example, GET /api/products/1 returns just that one product. If the ID does not exist, you get a 404 Not Found error.
PUT — Update a Resource
Send only the fields you want to change. For example, to update just the price, send {"price": 69.99} to PUT /api/products/1. Other fields remain unchanged.
DELETE — Remove a Resource
Send DELETE /api/products/1. The resource is soft-deleted (the DeletedAt timestamp is set). It disappears from list queries but remains in the database for recovery if needed.
Challenge: Full CRUD Through Docs
Using only the Scalar UI at /docs (no frontend, no curl, no Postman), perform the complete CRUD cycle:
- Create a new resource
- List all resources to verify it appears
- Get the single resource by ID
- Update one field
- Get it again to verify the update
- Delete it
- Try to get it again — what status code do you receive?
Response Format
Grit enforces a consistent JSON response format across all endpoints. This predictability makes frontend development much easier — you always know the shape of the response.
Success — Single Item
{
"data": {
"id": 1,
"name": "Wireless Keyboard",
"price": 79.99
},
"message": "Product created successfully"
}Success — List with Pagination
{
"data": [
{ "id": 1, "name": "Keyboard" },
{ "id": 2, "name": "Mouse" }
],
"meta": {
"total": 47,
"page": 1,
"page_size": 20,
"pages": 3
}
}Error Response
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Name is required",
"details": {
"name": "This field is required",
"price": "Must be greater than 0"
}
}
}The three shapes are always the same:
- • Single item:
data(object) +message(string) - • List:
data(array) +meta(pagination object) - • Error:
error.code(string) +error.message(string) + optionalerror.details(object)
Challenge: Trigger Each Response Format
Trigger all three response formats and observe the structure:
- Call
POST /api/auth/registerwith valid data — observe the "data + message" format - Call
GET /api/users?page=1&page_size=5— observe the "data + meta" format - Call
POST /api/auth/registerwith an empty body — observe the "error" format. What error code and message do you see?
Exporting the Spec
The OpenAPI specification is not just for the Scalar UI — it's a portable, machine-readable file that many tools can consume. You can export it and import it into:
- • Postman — import as a collection with all endpoints pre-configured
- • Insomnia — another popular API client that reads OpenAPI specs
- • API client generators — tools like openapi-generator can create TypeScript, Python, or Java clients from your spec
- • API testing tools — tools like Dredd or Schemathesis can validate your API against the spec
The raw OpenAPI JSON is available at:
# Raw JSON specification
http://localhost:8080/docs/openapi.json
# Copy this URL or download the file
# Import into Postman: File → Import → URL → paste the URLChallenge: Export and Import
Open http://localhost:8080/docs/openapi.json in your browser. You should see the raw JSON specification. Try importing it into Postman: File → Import → paste the URL. Does Postman create a collection with all your endpoints?
Customization
gin-docs provides several configuration options to customize the generated documentation.
Authentication Configuration
By default, gin-docs detects your JWT middleware and adds Bearer Token authentication to the spec. You can customize the auth configuration:
// gin-docs reads your middleware to determine which
// endpoints require authentication.
//
// Protected routes (behind AuthMiddleware) are marked
// with a lock icon in the Scalar UI.
//
// Public routes (like /api/auth/login) show no lock.Route Grouping
Endpoints are grouped by their route prefix. For example, all /api/users/* endpoints appear under the "Users" group. All /api/auth/* endpoints appear under "Auth." This grouping happens automatically based on your Gin route groups.
Excluding Endpoints
Some internal endpoints (like health checks or metrics) should not appear in public documentation. gin-docs excludes internal routes that are not part of your API groups. The /docs endpoint itself is also excluded — documentation does not document itself.
Challenge: Explore the Configuration
Look at how gin-docs is configured in your project. Find the setup code in your routes file or main.go. What options are being passed? Can you identify where route groups are defined and how they map to the documentation sections?
Summary
Let's review everything you've learned:
| Concept | Key Point |
|---|---|
| gin-docs | Auto-generates OpenAPI 3.1 specs by introspecting routes and models |
| Scalar UI | Interactive docs + API client at /docs |
| Schemas | Generated from GORM models, respects json:"-" and binding tags |
| Authentication | Set Bearer token in Scalar to test protected endpoints |
| Response Format | Consistent: data+message, data+meta, or error object |
| Export | Download OpenAPI JSON, import into Postman/Insomnia |
Challenge: Three Resources, Docs Only
Generate three related resources:
grit generate resource Category --fields "name:string,description:text:optional"
grit generate resource Product --fields "name:string,price:float,sku:string,category_id:belongs_to"
grit generate resource Order --fields "product_id:belongs_to,quantity:int,total:float,status:string"Restart your API and open /docs. Using ONLY the Scalar UI (no frontend, no curl, no code), complete these tasks:
- Create 5 categories
- Create 10 products, each linked to a category
- Create 3 orders for different products
- List all products filtered by category
- Update an order status
Challenge: Export Your Spec
After creating all three resources, download the OpenAPI spec from /docs/openapi.json. How many endpoints does it contain? How many schemas? Try importing it into Postman or Insomnia.
Challenge: Teach Someone Else
Explain to a teammate (or write down in your own words) how Grit's API documentation works. Cover: (1) how gin-docs generates the spec, (2) how to test endpoints in Scalar, (3) how to authenticate in the docs, and (4) how to export the spec. If you can explain it clearly, you understand it.
Enjoying the course?
Help us grow — star us on GitHub, subscribe on YouTube, and follow on LinkedIn.