.ai/principles/distilled/rest-api.md
expose_path(...) to support relative URL installationstype for every exposed field in an entitydocumentation hash (e.g., documentation: { type: 'Integer', example: 1 })using: option when exposing a field that references another entity; pass only an API::Entities::* constantexpose calls to high-impact entities (UserBasic, ProjectIdentity, Commit, etc.); create a feature-bounded entity insteadCi::JobOwner), not after the fields they contain (e.g., UserWithNotificationEmail)api_entity_exposure_baseline.yml to allowlist new fields; open a discussion with the API Platform team if a field genuinely belongs on a high-impact entitydesc, detail, success, and tags in every endpoint's desc blockdesc summary with an action verb aligned to the HTTP method (Get, List, Create, Update, Delete)desc (DO NOT use a variable or method call)desc summary to 120 characters or fewerdetail, not in descdesc or detail strings; use route_setting :lifecycle insteadroute_setting :lifecycle, :experiment or route_setting :lifecycle, :beta for non-GA endpointsdeprecated true in the desc block when deprecating an endpoint; DO NOT use route_setting :lifecycle for deprecationaudit_events, users); DO NOT use singular or product-category-coupled namessuccess value in every endpoint's desc blockhttp_codes option to document the success responseGrape::Entity class directly or via model: for JSON responses; omit model: only for no-body responses (204, redirects)[Entities::MyEntity] or is_array: true when the endpoint returns a collectionexample: (single) or examples: (multiple, named) to illustrate response bodies; both require model: and are mutually exclusivedeclared(params, include_parent_namespaces: false) when passing the params hash to a method callparams[key] directly only when accessing a single elementcoerce_with block in Grape v1.3+coerce_nil_params_to_array! helper in before blocks to preserve empty-array behavior for nil Array paramsPATCH when updating some attributes of a resource; use PUT when replacing all attributeslib/api/helpers.rb (for example, not_found!, no_content!) for non-200 responsesdestroy_conditionally! for DELETE requests (returns 204 on success, 412 on stale If-Unmodified-Since)500404 Not Foundroute_setting :lifecycle, :experiment and use an off-by-default feature flag for experiment-stage endpoints; return 404 Not Found / ignore arguments / suppress fields when the flag is offroute_setting :lifecycle, :beta and an on-by-default feature flag for beta-stage endpointshidden option)route_setting :lifecycle, the feature flag, and experiment/beta API docs when a feature becomes generally available; add OpenAPI documentation at that pointwith_api_entity_associations scope on models to eager-load associations returned in the APIActiveRecord::QueryRecorder test for every collection-returning endpoint to verify no N+1 queries are introducedFilePath, Git SHA, Absence, IntegerNoneAny, ArrayNoneAny, EmailOrEmailList) for parameter validation before passing values downstreamlib/api/validations/validators/ inheriting from Grape::Validations::Validators::Base and register them with Grape::Validations.register_validatorspec/lib/api/validations/validators//spec/fixtures/api/schemas and match_response_schema to validate API responses/https://gitlab.example.com/api/v4/ as the endpoint and <your_access_token> as the token placeholderproject.name or projects[].name for arrays--header instead of -H), declare URLs with the --url parameter in double quotes, and use line breaks with \ for readabilityFor the full picture, see: