# API Patterns

Builds REST APIs using respond_to blocks with Jbuilder templates following the...

- Repository: https://github.com/ThibautBaissac/rails_ai_agents (671 stars)
- Category: Engineering
- License: MIT
- Last updated: 2026-06-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add ThibautBaissac/rails_ai_agents --skill api-patterns -g -a claude-code -y`
Codex: `npx skills add ThibautBaissac/rails_ai_agents --skill api-patterns -g -a codex -y`
Cursor: `npx skills add ThibautBaissac/rails_ai_agents --skill api-patterns -g -a cursor -y`
Gemini CLI: `npx skills add ThibautBaissac/rails_ai_agents --skill api-patterns -g -a gemini-cli -y`

## Description

Builds REST APIs using respond_to blocks with Jbuilder templates following the 37signals same-controllers-different-formats philosophy. Use when adding API endpoints, JSON responses, token authentication, pagination, or when user mentions API, JSON, REST, or Jbuilder. WHEN NOT: For HTML-only controllers (use crud-patterns), for webhook delivery (use event-tracking).

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# API Patterns

## Philosophy: Same Controllers, Different Formats

- One controller serves both HTML (web) and JSON (API)
- Use `respond_to` blocks for format-specific responses
- RESTful routes only (no GraphQL, no custom endpoints unless necessary)
- Jbuilder for JSON templates (like ERB for HTML)
- HTTP status codes for success/errors
- Token-based authentication for API (not OAuth unless required)

## Project Knowledge

**Stack:** Jbuilder for JSON views, RESTful routes, token-based API auth,
same controllers for HTML and JSON, HTTP caching with ETags for API.

**Multi-tenancy:** API uses same account scoping (`/accounts/:account_id/...`),
token scoped to account.

**Commands:**
```bash
# Generate API token model
rails generate model ApiToken user:references account:references \
  token:string last_used_at:datetime

# Test API endpoints
curl -H "Authorization: Bearer TOKEN" \
     -H "Accept: application/json" \
     http://localhost:3000/boards
```

## Pattern 1: Respond To Blocks

```ruby
class BoardsController < ApplicationController
  before_action :set_board, only: [:show, :edit, :update, :destroy]

  def index
    @boards = Current.account.boards.includes(:creator).order(created_at: :desc)

    respond_to do |format|
      format.html  # renders index.html.erb
      format.json  # renders index.json.jbuilder
    end
  end

  def show
    respond_to do |format|
      format.html
      format.json
    end
  end

  def create
    @board = Current.account.boards.build(board_params)
    @board.creator = Current.user

    respond_to do |format|
      if @board.save
        format.html { redirect_to @board, notice: "Board created" }
        format.json { render :show, status: :created, location: @board }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @board.errors, status: :unprocessable_entity }
      end
    end
  end

The rest: https://github.com/ThibautBaissac/rails_ai_agents/blob/HEAD/.claude_37signals/skills/api-patterns/SKILL.md
