Project

reqcord

0.0
The project is in a healthy, maintained state
Reqcord captures HTTP requests and responses from Rails integration tests and generates static API documentation with executable cURL examples.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

Runtime

>= 7.1, < 9.0
>= 7.1, < 9.0
 Project Readme

Reqcord

CI Gem

Turn your Rails integration tests into API documentation.

Reqcord runs your test suite, watches the HTTP requests and responses the tests make, and writes the documentation from what it saw — Markdown, runnable cURL, a Postman collection and an OpenAPI document. No DSL, no annotations, no second copy of every request: the tests are the source of truth.

flowchart LR
    subgraph tests["Your integration tests"]
        direction TB
        T1["creates customer<br/>POST /api/v2/customers → 201"]
        T2["rejects unknown status<br/>POST /api/v2/customers → 422"]
        T3["requires authentication<br/>GET /api/v2/customers → 401"]
    end

    R["Rails route table"]

    subgraph reqcord["Reqcord"]
        direction TB
        C["capture · sanitize · infer"]
        D[("dataset.json")]
        C --> D
    end

    subgraph out["Generated"]
        direction TB
        MD["Markdown pages"]
        CU["cURL scripts"]
        PM["Postman collection<br/>(Hoppscotch)"]
        OA["OpenAPI 3.1"]
    end

    SC["Scalar<br/>mount Reqcord::Web"]

    tests --> C
    R --> C
    D --> MD
    D --> CU
    D --> PM
    D --> OA
    OA --> SC
Loading

Quick start

# Gemfile
group :development, :test do
  gem "reqcord"
end
bundle install
bin/rails reqcord:init        # writes reqcord.yml — point test.paths at your API tests
bin/rails reqcord:generate    # runs them with capture on, writes docs/api/
[reqcord] captured 87 request(s), 85 matched a documented route
[reqcord] captured a successful 2xx request for 15 of 16 endpoint(s)
[reqcord] routes: 18 = 15 documented + 1 uncovered + 2 skipped

Every route ends in exactly one bucket, so nothing goes missing quietly. In CI, bin/rails reqcord:check fails when the committed docs are behind the tests.

Optionally, browse it inside the app with Scalar:

# config/routes.rb
mount Reqcord::Web => "/api-docs" if Rails.env.development?

What you get

From an ordinary test —

test "creates customer" do
  post "/api/v2/customers",
    params: { customer: { name: "John Doe", email: "john@example.com", status: "active" } },
    headers: { "Authorization" => "Bearer test-token" },
    as: :json

  assert_response :created
end

— a page like this, plus a create.sh, a Postman request and an OpenAPI operation built from the same captured request:

# Create Customer

`POST /api/v2/customers`

## Body Parameters

| Field | Type | Required | Values |
| --- | --- | --- | --- |
| `customer.name` | string | yes | `"John Doe"` |
| `customer.email` | string | yes | `"john@example.com"` |
| `customer.status` | string | yes | `"active"` \| `"passive"` |

## cURL

```bash
curl --request POST \
  --url "http://localhost:3000/api/v2/customers" \
  --header "Authorization: Bearer {{token}}" \
  --header "Content-Type: application/json" \
  --data '{"customer":{"name":"John Doe","email":"john@example.com","status":"active"}}'
```

## Responses

### 201 Created
### 401 Unauthorized
### 422 Unprocessable Content

The parameter table is inferred from the requests the application accepted: two tests sent "active" and "passive", a third sent "inactive" and got a 422, so the page lists the two values that work and keeps the rejection as a response example. Credentials never reach a file — Bearer test-token became Bearer {{token}} before anything was stored.

Documentation

Getting started install, configure, generate, read the output
Configuration every key in reqcord.yml, defaults and environment overrides
Exporters Markdown, cURL, Postman / Hoppscotch, OpenAPI — what each contains
Reqcord::Web serve the docs from the app with Scalar
Route coverage how the route table becomes endpoints; resource, match via:, engines, filters
Capture and inference what is captured, sanitization, how parameter tables and response fields are derived, the dataset
Troubleshooting when the output looks thin
Architecture pipeline, modules, design principles, working on Reqcord
Changelog

Examples

Four runnable applications under examples/, each with the documentation it generates committed next to it:

Example Tests Shows
test-app Minitest three small resources: auth, closed value sets, PATCH/PUT folding, a member action
spec-app RSpec the same API from request specs
complex-test-app Minitest a store API: products, cart, orders, nested notes, array bodies, filter[category], a form login, X-Api-Key admin namespace, two API versions, 400/403/404/409
complex-spec-app RSpec the store API from request specs

examples/reqcord.yml is an annotated configuration file.

Supported versions

Ruby 3.2, 3.3, 3.4
Rails 7.1, 7.2, 8.0, 8.1
Tests Minitest integration tests, RSpec request specs

Every Ruby × Rails pair Rails itself supports runs in CI.

Principles

  • Tests are the source of truth. Reqcord never reads models, serializers or contracts; what the application accepted and answered is the spec.
  • Capture once, export anywhere. One dataset, any number of formats.
  • Nothing is lost silently. routes = documented + uncovered + skipped, reconciled on every run.
  • Generated docs are safe. Sanitization runs before anything is stored.

License

MIT.