CI Sync Enforcement
You may want to use CI to automatically enforce that the schema does not go out of sync.
This guide provides approaches for single file and multifile schemas.
This guide assumes:
- the repo uses the default
vite_railsfile structure, i.e. a monorepo with backend and frontend yarnpackage manager
However, these are not requirements. The intention of this guide is to provide a starting point for CI enforcement and should be adaptable to other repo structures, package managers, shells, etc.
The Gist
- Add
schema:generatefor local development. - Add
schema:checkfor CI.
{
"scripts": {
"schema:generate": "./bin/jsonapi-schema-generate.sh",
"schema:check": "./bin/jsonapi-schema-check.sh"
}
}yarn schema:check will fail if the schema being checked in is different from what CI generates.
Single File Quick Reference
File Structure
schema.ts
jsonapi-schema-generate.sh
jsonapi-schema-check.sh
jsonapi.rake
package.json
{
"scripts": {
"schema:generate": "./bin/jsonapi-schema-generate.sh",
"schema:check": "./bin/jsonapi-schema-check.sh"
}
}yarn schema:generate
set -e
bundle exec rails jsonapi:generate
yarn run eslint --fix ./app/frontend/models/schema.ts
yarn run prettier --write ./app/frontend/models/schema.tsyarn schema:check
set -e
bundle exec rails jsonapi:generate
yarn run eslint --fix ./app/frontend/models/schema.ts
yarn run prettier --write ./app/frontend/models/schema.ts
if [$(git status ./app/frontend/models/schema.ts --porcelain=1 | wc-l) -ne 0 ]; then
git diff
echo "Schema is out of sync. Run 'yarn schema:generate'."
exit 1
firails jsonapi:generate
namespace :jsonapi do
desc "Generate JSONAPI::Resource Anchor schema"
task generate: :environment do
puts "Generating JSONAPI::Resource Anchor schema..."
content = Anchor::TypeScript::SchemaGenerator(
register: Schema.register,
).call
path = Rails.root.join("schema.ts")
File.open(path, "w") { |f| f.write(content) }
puts "✅ #{File.basename(path)}"
end
endMultifile Quick Reference
This guide also works for manually_editable multifile schemas.
As long as manual edits are made after the // END AUTOGEN comment the strategy below is able to enforce that the generated schema is in sync.
See the Incremental Migration guide for an example use case.
User.model.ts
Post.model.ts
Comment.model.ts
shared.ts
hash.json
jsonapi-schema-generate.sh
jsonapi-schema-check.sh
jsonapi.rake
package.json
{
"scripts": {
"schema:generate": "./bin/jsonapi-schema-generate.sh",
"schema:check": "./bin/jsonapi-schema-check.sh"
}
}yarn schema:generate
set -e
FILES=$(bundle exec rails jsonapi:generate | tr ' ' '\n' | grep 'frontend' | tr '\n' ' ')
if [[ -n "{$FILES//[[:space:]]/}" ]]; then
yarn run eslint --fix $FILES
yarn run prettier --write $FILES
fi
yarn run prettier --write ./app/frontend/models/gen/hash.jsonyarn schema:check
set -e
FILES=$(bundle exec rails jsonapi:generate_no_trust | tr ' ' '\n' | grep 'frontend' | tr '\n' ' ')
if [[ -n "{$FILES//[[:space:]]/}" ]]; then
yarn run eslint --fix $FILES
yarn run prettier --write $FILES
fi
yarn run prettier --write ./app/frontend/models/gen/hash.json
if [$(git status ./app/frontend/models/gen --porcelain=1 | wc-l) -ne 0 ]; then
git diff
echo "Schema is out of sync. Run 'yarn schema:generate'."
exit 1
firails jsonapi:generate
namespace :jsonapi do
desc "Generate JSONAPI::Resource Anchor schema"
task generate: :environment do
Rails.application.eager_load!
generator = Anchor::TypeScript::MultifileSchemaGenerator.new(
register: Schema.register,
context: {},
resource_file_extension: '.model.ts'
)
modified_files = Anchor::TypeScript::MultifileSaveService.call(
generator:,
folder_path: 'app/frontend/models/gen',
force: false
)
puts modifed_files.map { |name| Rails.root.join(folder_path, name) }.join(' ')
end
desc "Generate JSONAPI::Resource Anchor schema without trusting hash.json"
task generate_no_trust: :environment do
Rails.application.eager_load!
generator = Anchor::TypeScript::MultifileSchemaGenerator.new(
register: Schema.register,
context: {},
resource_file_extension: '.model.ts'
)
modified_files = Anchor::TypeScript::MultifileSaveService.call(
generator:,
folder_path: 'app/frontend/models/gen',
force: false,
trust_hash: false
)
puts modifed_files.map { |name| Rails.root.join(folder_path, name) }.join(' ')
end
end