Skip to main content

Generate clients and OpenAPI

Overview

The HTTP contract is website/static/openapi.json. RSwag request specs generate it; ReDoc serves it at /api/.

The TypeScript client (contrib/decidim-node-client, @octree/decidim-sdk) is generated from this file. See TypeScript SDK.

When to use

  • After any route, schema, or security change.
  • Before release, CI, or publishing the doc site.

Example

1. Add or update request specs

See RSwag — every route needs a spec under decidim-restfull-<gem>/spec/requests/decidim/api/rest_full/.

2. Register OpenAPI schemas

See Test definitionsext.open_api_definitions + DefinitionRegistry.

3. Regenerate the spec file

docker compose exec rest_full bash -lc 'cd /home/module && yarn gen:openapi-spec'

Writes website/static/openapi.json via bin/openapi-stale --yesbin/swaggerize.

4. Validate the spec (optional)

yarn openapi-generator-cli validate -i website/static/openapi.json

5. Generate the Node client (optional)

yarn gen:node-client

Output: contrib/decidim-node-client.

6. Commit and run the full gate

git add website/static/openapi.json
yarn postcommit

CI stale check without generating:

bin/openapi-stale --check -o website/static/openapi.json

Subset of specs only:

export DECIDIM_REST_FULL_SWAGGER_SPEC_PATHS="decidim-restfull-forms/spec/requests/decidim/api/rest_full/forms/**/*_spec.rb"
bin/swaggerize --out /tmp/openapi.json

Host app (merged spec)

Decidim host applications ship extra paths via Extension.register in an initializer. They merge the monorepo base OpenAPI with local RSwag specs instead of re-running every gem spec. See Host app extensions.

Rules

RuleDetail
No hand-edited pathsMissing route = missing RSwag example.
Stale checkbin/openapi-stale --check / yarn gen:openapi-spec:check for CI.
operationId{verb}{Resource} camelCase: listAssemblies, showAssembly, getProposal, castProposalVote. No snake_case (proposal_component). No bare nouns (userslistUsers).
SecurityUse describe_api_endpoint — sets credentialFlowBearer / resourceOwnerFlowBearer. Do not duplicate an Authorization header parameter in OpenAPI.
ResponsesEvery 200 / 202 must $ref a named schema (examples alone do not generate TypeScript types).
Request bodiesNamed payloads (:blog_post_create_payload, :questionnaire_update_body), not type: :object.
RelationshipsUse item_schema_key: :component_relationship_identifier (or :resource_relationship_identifier) in has_many_relation to avoid HasManyRelationItem1 in clients.
Async 202$ref :rest_full_api_job_accepted or :submission_request_accepted_response.
OAuth token$ref :oauth_token_response on createToken 200.
ErrorsReuse :error_response, :forms_validation_error_response.
Full pipelineyarn postcommit — format, openapi, node client, ReDoc HTML.
CasePath
Swagger pathsdecidim-restfull-core/spec/lib/decidim/rest_full/core/swagger_spec_paths_spec.rb
Exampledecidim-restfull-proposals/spec/requests/.../proposals_controller_show_spec.rb

See also