Resources and Properties
A resource is an object with member properties that is intended to be exposed and manipulated by a REST API, manipulated via a REST api. Resources may be created, read, updated, or destroyed (CRUD) based on policies.
A resource implements the Rhino::Resource interface. Most common is an ActiveRecord based resource, but Rhino also provides other built in resources.
The list of resources is contained in config/initializers/rhino.rb
and is used to generate the OpenAPI spec and the front end. Additional resources
can be added to the config/initializers/rhino.rb
file by adding a new line with the resource name and the class name.
Rhino.setup do |config|
# Add Blog and BlogPost resources
config.resources += ["Blog", "BlogPost"]
end
Ownership
Every resource must have an owner. Ownership allows for the creation of a hierarchy of resources. For instance a blog post may be owned by a blog. In the case of an Active Record based resource, ownership is usually a belongs_to relationship.
class BlogPost < ApplicationRecord
belongs_to :blog
rhino_owner :blog
end
Always use the name of association as the owner.
class BlogPost < ApplicationRecord
belongs_to :author, class_name: 'User'
rhino_owner :author
end
The resource owner must be explicitly specified for every resource.
Base Owner
At the top of the hierarchy is the base owner resource. The base owner owns the all the data under it. By default the built-in 'User' resource is the base owner.
class Blog < ApplicationRecord
belongs_to :user
rhino_owner_base
end
The rhino_organization module configures a different resource as the base owner, the built-in 'Organization' resource. This allows a company or organization to own the blogs while individual users may come and go from the organization.
Global Owner
If a resource is shared across multiple base owners, it can be designated as a global resource.
class Category < ApplicationRecord
rhino_owner_global
end
Global resources may still have child resources:
class SubCategory < ApplicationRecord
rhino_owner :category
end
The SubCategory
resource will still be designated as a global resource for access purposes.
Auth Owner
The auth owner is the resource that controls authentication and authorization. By default the built-in 'User' resource is the auth owner. It is not common for the auth owner to own a resource in the hierarchy (though the base owner and auth owner can be the same resource), but it is possible.
Properties
Properties are the member values of a resource. They are defined by the resource class and are used to describe the resource in the OpenAPI spec. Rhino introspects the attributes of the model to determine the properties as well as the type and format of each. The properties are then used to generate an OpenAPI compliant spect spec and the front end.
Types & Formats
Types are defined by the OpenAPI spec and are used to describe the type of a property. Formats are used to describe the format of a property. For instance a string property may be a date, email, url, etc.
Rhino does add additional types and formats to the OpenAPI spec. While formats are open and extendable, types are not so technically Rhino is not compliant with the OpenAPI spec, but this is not an issue in practice currently and the additional types are useful.
Readable & Writeable Properties
Properties can be designated as read only, write only or both. Write properties can be further subdivided into create only and update only, though it is less common to use these.
Reference properties
Reference properties link to related resources and must be explicitly configured to be included in the API response in order to protect against infinite recursion and performance issues. The REST API will include the full referenced object as part of the referenced response. Both 'one' and 'many' relationships can be included.
class BlogPost < ApplicationRecord
belongs_to :blog
rhino_owner :blog
rhino_references [:blog]
end
class Blog < ApplicationRecord
has_many :blog_posts
rhino_owner_base
rhino_references [:blog_posts]
end
Referencing 'many' relationships can significantly impact performance
Owner reference
A reference to the owner of a resource should always be included so that resources can be created.
Not including a reference to the owner will not allow the resource to be created via the API
Nullable properties
Properties can be designated as nullable. This is useful for properties that are not required in the database. ActiveRecord based resources will automatically translate the null: true
option on migrations and validations to the nullable property.
Default values
The OpenAPI spec default descriptor is supported. ActiveRecord and ActiveModel based resources will automatically translate default values from the attributes and database.
Validations
The OpenAPI spec minimum, maximum, minLength, maxLength, exclusiveMin, exclusiveMax and enum constraints are all supported.
Active Record based resources will automatically translate some validations automatically such as:
- ActiveModel::Validations::NumericalityValidator
- ActiveRecord::Validations::LengthValidator
- ActiveModel::Validations::InclusionValidator
Array properties
Array properties are support both for database arrays and for 'many' references. The OpenAPI spec array is used and ActiveRecord and ActiveModel based resources will automatically translate array properties from the attributes and database.
Built-in resources
Rhino includes a number of built-in resources that can be used to provide data as a resource.
Rhino::Resource
The abstract resource interface to be implemented. Implementations can include it directly and supply a few additional methods or create new module which can then itself be included. See rhino/rhino/app/resources/rhino/open_api_info.rb
for an example.
Rhino::Resource::ActiveRecordExtension
An ActiveRecord resource implementation that exposes all attributes (including relations) and validations of the model.
Rhino::Resource::ActiveStorage
Inherits from Rhino::Resource::ActiveRecordExtension and supports ActiveStorage to provide API responses for attachments. Read more on adding file attachments to your resources in the file attachments tutorial and in the properties guide.
Rhino::Resource::ActiveRecordTree
Inherits from Rhino::Resource::ActiveRecordExtension and supports the ancestry gem to return API response in a tree format.
Rhino::Resource::ActiveModelExtension
An ActiveModel resource implementation that exposes all attributes and validations of the model. ActiveModels must also implement the BackingStore interface for storage.
ActiveRecord actually inherits from ActiveModel and many attribute and validation behaviour is shared