Easily generate TypeScript schemas, JSON Schemas, or any schema of your choice from cerebris/jsonapi-resources JSONAPI::Resource classes.
Ideally, API schemas have the types of each payload fully specified.
jsonapi-resources-anchor provides:
- Type inference via the underlying ActiveRecord model of a resource
- Type annotation, e.g.
attribute :name_length, Anchor::Types::Integer - Configuration, e.g. setting the case (camel, snake, etc.) of properties and deriving TypeScript comments from database comments
- TypeScript and JSON Schema generators via
Anchor::TypeScript::SchemaGeneratorandAnchor::JSONSchema::SchemaGenerator
See the example Rails app for a fully functional app using Anchor.
gem 'jsonapi-resources-anchor'bundle installGiven:
ActiveRecord Schema:
create_table "comments", force: :cascade do |t| t.string "text", null: false t.string "commentable_type" t.bigint "commentable_id" t.bigint "user_id", null: false t.bigint "deleted_by_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["commentable_type", "commentable_id"], name: "index_comments_on_commentable" t.index ["deleted_by_id"], name: "index_comments_on_deleted_by_id" t.index ["user_id"], name: "index_comments_on_user_id" end create_table "posts", force: :cascade do |t| t.string "description", null: false t.bigint "user_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["user_id"], name: "index_posts_on_user_id" end create_table "users", force: :cascade do |t| t.string "name", null: false t.integer "integer" t.decimal "decimal" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "role" endJSONAPI::Resource classes:
class ApplicationResource < JSONAPI::Resource abstract include Anchor::SchemaSerializable end class CommentResource < ApplicationResource attribute :text attribute :created_at attribute :updated_at attribute :inferred_unknown attribute :type_given, Anchor::Types::String relationship :user, to: :one relationship :commentable, Anchor::Types::Relationship.new(resources: [UserResource, PostResource], null: true), polymorphic: true, to: :one end class UserResource < ApplicationResource attribute :name attribute :role, UserRoleEnum relationship :comments, to: :many relationship :posts, to: :many end class UserRoleEnum < Anchor::Types::Enum anchor_schema_name "UserRole" value :admin, "admin" value :content_creator, "content_creator" value :external, "external" value :guest, "guest" value :system, "system" end class PostResource < ApplicationResource attribute :description relationship :user, to: :one relationship :comment, to: :many end class Schema < Anchor::Schema resource CommentResource resource UserResource resource PostResource enum UserRoleEnum endAnchor::TypeScript::SchemaGenerator.call(register: Schema.register) will return the schema below in a String:
type Maybe<T> = T | null; export type Comment = { id: number; type: "comments"; text: string; created_at: string; updated_at: string; inferred_unknown: unknown; type_given: string; relationships: { user: User; commentable: Maybe<User | Post>; }; }; export type User = { id: number; type: "users"; name: string; role: UserRole; relationships: { comments: Array<Comment>; posts: Array<Post>; }; }; export type Post = { id: number; type: "posts"; description: string; relationships: { user: User; comment: Array<Comment>; }; }; export enum UserRole { Admin = "admin", ContentCreator = "content_creator", External = "external", Guest = "guest", System = "system", }