facera 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.github/workflows/gem-push.yml +42 -0
- data/.github/workflows/ruby.yml +35 -0
- data/.gitignore +39 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +137 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/README.md +309 -0
- data/Rakefile +6 -0
- data/examples/01_core_dsl.rb +132 -0
- data/examples/02_facet_system.rb +216 -0
- data/examples/03_api_generation.rb +117 -0
- data/examples/04_auto_mounting.rb +182 -0
- data/examples/05_adapters.rb +196 -0
- data/examples/README.md +184 -0
- data/examples/server/README.md +376 -0
- data/examples/server/adapters/payment_adapter.rb +139 -0
- data/examples/server/application.rb +17 -0
- data/examples/server/config/facera.rb +33 -0
- data/examples/server/config.ru +10 -0
- data/examples/server/cores/payment_core.rb +82 -0
- data/examples/server/facets/external_facet.rb +38 -0
- data/examples/server/facets/internal_facet.rb +33 -0
- data/examples/server/facets/operator_facet.rb +48 -0
- data/facera.gemspec +30 -0
- data/img/facera.png +0 -0
- data/lib/facera/adapter.rb +83 -0
- data/lib/facera/attribute.rb +95 -0
- data/lib/facera/auto_mount.rb +124 -0
- data/lib/facera/capability.rb +117 -0
- data/lib/facera/capability_access.rb +59 -0
- data/lib/facera/configuration.rb +83 -0
- data/lib/facera/context.rb +29 -0
- data/lib/facera/core.rb +65 -0
- data/lib/facera/dsl.rb +41 -0
- data/lib/facera/entity.rb +50 -0
- data/lib/facera/error_formatter.rb +100 -0
- data/lib/facera/errors.rb +40 -0
- data/lib/facera/executor.rb +265 -0
- data/lib/facera/facet.rb +103 -0
- data/lib/facera/field_visibility.rb +69 -0
- data/lib/facera/generators/core_generator.rb +23 -0
- data/lib/facera/generators/facet_generator.rb +25 -0
- data/lib/facera/generators/install_generator.rb +64 -0
- data/lib/facera/generators/templates/core.rb.tt +49 -0
- data/lib/facera/generators/templates/facet.rb.tt +23 -0
- data/lib/facera/grape/api_generator.rb +59 -0
- data/lib/facera/grape/endpoint_generator.rb +316 -0
- data/lib/facera/grape/entity_generator.rb +89 -0
- data/lib/facera/grape.rb +14 -0
- data/lib/facera/introspection.rb +111 -0
- data/lib/facera/introspection_api.rb +66 -0
- data/lib/facera/invariant.rb +26 -0
- data/lib/facera/loader.rb +153 -0
- data/lib/facera/openapi_generator.rb +338 -0
- data/lib/facera/railtie.rb +51 -0
- data/lib/facera/registry.rb +34 -0
- data/lib/facera/tasks/routes.rake +66 -0
- data/lib/facera/version.rb +3 -0
- data/lib/facera.rb +35 -0
- metadata +137 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f537d48a2710c89255f9c09da919bc6bba7be4569c3cb92e0b1830a583b708ad
|
|
4
|
+
data.tar.gz: aabc5be766d5039722c23becb91242da22b0e67f72f4521c9ac1d54d11a67335
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e667c5784b928f1f3747bd368521d85cb2227112d18c9ea8f1b86459fe1d15f0756c01757595a5cb29fae925095ba9441beb4aa461b74b50abf292ace3ea12f1
|
|
7
|
+
data.tar.gz: e7a1286414b83d21a0ffc2a15781e9c6e4608be4c998dfdcf7a2caea20fcf43a7d9ad90d4f63da61409cf077b163921378f616d80fa4f9396576bc0e6a52d584
|
data/.DS_Store
ADDED
|
Binary file
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Ruby Gem
|
|
2
|
+
|
|
3
|
+
on: workflow_dispatch
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
name: Build + Publish
|
|
8
|
+
runs-on: ubuntu-22.04
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
packages: write
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- name: Set up Ruby 3.2
|
|
16
|
+
uses: ruby/setup-ruby@v1
|
|
17
|
+
with:
|
|
18
|
+
ruby-version: '3.2'
|
|
19
|
+
|
|
20
|
+
- name: Get Gem Version
|
|
21
|
+
id: get-version
|
|
22
|
+
run: |
|
|
23
|
+
VERSION=$(ruby -r './lib/facera/version.rb' -e "puts Facera::VERSION")
|
|
24
|
+
echo "::set-output name=version::$VERSION"
|
|
25
|
+
shell: bash
|
|
26
|
+
|
|
27
|
+
- name: Publish to RubyGems
|
|
28
|
+
run: |
|
|
29
|
+
gem fetch facera -v ${{ steps.get-version.outputs.version }}
|
|
30
|
+
if [ $? -eq 1 ]; then
|
|
31
|
+
echo "Gem version already exists on RubyGems. Skipping the push to RubyGems."
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
mkdir -p $HOME/.gem
|
|
35
|
+
touch $HOME/.gem/credentials
|
|
36
|
+
chmod 0600 $HOME/.gem/credentials
|
|
37
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
|
38
|
+
gem build *.gemspec
|
|
39
|
+
gem push *.gem
|
|
40
|
+
shell: bash
|
|
41
|
+
env:
|
|
42
|
+
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
|
2
|
+
# They are provided by a third-party and are governed by
|
|
3
|
+
# separate terms of service, privacy policy, and support
|
|
4
|
+
# documentation.
|
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
|
7
|
+
|
|
8
|
+
name: Ruby
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [ "main" ]
|
|
13
|
+
pull_request:
|
|
14
|
+
branches: [ "main" ]
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
test:
|
|
21
|
+
|
|
22
|
+
runs-on: ubuntu-22.04
|
|
23
|
+
strategy:
|
|
24
|
+
matrix:
|
|
25
|
+
ruby-version: ['3.2', '3.3', '3.4', '4.0']
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
- name: Set up Ruby
|
|
30
|
+
uses: ruby/setup-ruby@v1
|
|
31
|
+
with:
|
|
32
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
33
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: bundle exec rake
|
data/.gitignore
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/tmp/
|
|
10
|
+
/test/version_tmp/
|
|
11
|
+
/tmp/
|
|
12
|
+
|
|
13
|
+
# RSpec files
|
|
14
|
+
.rspec_status
|
|
15
|
+
|
|
16
|
+
# Bundler
|
|
17
|
+
Gemfile.lock
|
|
18
|
+
.bundle/
|
|
19
|
+
vendor/bundle
|
|
20
|
+
|
|
21
|
+
# Documentation cache and generated files
|
|
22
|
+
/.yardoc/
|
|
23
|
+
/_yardoc/
|
|
24
|
+
/doc/
|
|
25
|
+
/rdoc/
|
|
26
|
+
|
|
27
|
+
# Environment files
|
|
28
|
+
/.env
|
|
29
|
+
/.env.local
|
|
30
|
+
|
|
31
|
+
# macOS
|
|
32
|
+
.DS_Store
|
|
33
|
+
|
|
34
|
+
# IDE files
|
|
35
|
+
/.idea/
|
|
36
|
+
/.vscode/
|
|
37
|
+
*.swp
|
|
38
|
+
*.swo
|
|
39
|
+
*~
|
data/.rspec
ADDED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-03-09
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
#### Core Framework
|
|
15
|
+
- **Core DSL** - Define domain models with entities, capabilities, and invariants
|
|
16
|
+
- Entity definitions with typed attributes (string, integer, uuid, money, enum, etc.)
|
|
17
|
+
- Four capability types: create, get, list, action
|
|
18
|
+
- Business invariants with validation blocks
|
|
19
|
+
- State transitions and preconditions
|
|
20
|
+
- Field setters and required/optional parameters
|
|
21
|
+
|
|
22
|
+
- **Facet System** - Consumer-specific API projections
|
|
23
|
+
- Field visibility control (explicit fields, hide fields, expose all)
|
|
24
|
+
- Capability access control (allow/deny capabilities)
|
|
25
|
+
- Computed fields with custom logic
|
|
26
|
+
- Error verbosity levels (minimal, detailed, structured)
|
|
27
|
+
- Audit logging configuration
|
|
28
|
+
- Capability scoping for filtering
|
|
29
|
+
|
|
30
|
+
- **Adapter Pattern** - Business logic implementation
|
|
31
|
+
- Adapter base module for implementing capabilities
|
|
32
|
+
- Auto-discovery from `adapters/` directory
|
|
33
|
+
- Auto-linking to cores by naming convention
|
|
34
|
+
- Inline execute blocks for simple logic
|
|
35
|
+
- Priority system (execute block > adapter > mock)
|
|
36
|
+
- Full method naming convention support
|
|
37
|
+
|
|
38
|
+
- **API Generation** - Auto-generated REST APIs using Grape
|
|
39
|
+
- REST endpoints for all capabilities (POST, GET, LIST)
|
|
40
|
+
- Action endpoints (POST /{entity}/:id/{action})
|
|
41
|
+
- Health check endpoints
|
|
42
|
+
- Automatic parameter validation
|
|
43
|
+
- Automatic precondition checking
|
|
44
|
+
- Invariant validation
|
|
45
|
+
- Field filtering by facet
|
|
46
|
+
|
|
47
|
+
- **Auto-Mounting** - Convention over configuration
|
|
48
|
+
- Auto-discovery from `cores/`, `adapters/`, and `facets/` directories
|
|
49
|
+
- Support for multiple directory structures (app/, lib/, root)
|
|
50
|
+
- Automatic Grape API generation and mounting
|
|
51
|
+
- Rack::Builder integration
|
|
52
|
+
- Rails Railtie integration
|
|
53
|
+
- Startup logging with emoji indicators 💎🔌ðŸŽðŸš€ðŸ“šâœ¨
|
|
54
|
+
|
|
55
|
+
- **Introspection API** - Runtime API exploration
|
|
56
|
+
- Full introspection endpoint (`/facera/introspect`)
|
|
57
|
+
- Core inspection (`/facera/cores`, `/facera/cores/:name`)
|
|
58
|
+
- Facet inspection (`/facera/facets`, `/facera/facets/:name`)
|
|
59
|
+
- Mounted configuration endpoint (`/facera/mounted`)
|
|
60
|
+
- Programmatic introspection via `Facera::Introspection`
|
|
61
|
+
|
|
62
|
+
- **OpenAPI Generation** - Auto-generated API documentation
|
|
63
|
+
- OpenAPI 3.0 spec generation for all facets
|
|
64
|
+
- Complete paths, schemas, parameters, and responses
|
|
65
|
+
- Per-facet specs (`/facera/openapi/:facet`)
|
|
66
|
+
- All facets spec (`/facera/openapi`)
|
|
67
|
+
- Programmatic generation via `Facera::OpenAPIGenerator`
|
|
68
|
+
|
|
69
|
+
- **Configuration System**
|
|
70
|
+
- Base path and versioning
|
|
71
|
+
- Custom facet paths
|
|
72
|
+
- Conditional facet enabling/disabling
|
|
73
|
+
- Feature flags (introspection, dashboard, docs)
|
|
74
|
+
- Authentication hooks per facet
|
|
75
|
+
|
|
76
|
+
#### Developer Experience
|
|
77
|
+
- **Examples** - Five complete working examples
|
|
78
|
+
- 01_core_dsl.rb - Core definition basics
|
|
79
|
+
- 02_facet_system.rb - Multiple facets from one core
|
|
80
|
+
- 03_api_generation.rb - Auto-generated APIs
|
|
81
|
+
- 04_auto_mounting.rb - Zero-config mounting
|
|
82
|
+
- 05_adapters.rb - Business logic implementation
|
|
83
|
+
- Runnable server in examples/server/
|
|
84
|
+
|
|
85
|
+
- **Documentation** - Comprehensive wiki
|
|
86
|
+
- Home - Complete navigation and quick reference
|
|
87
|
+
- Core Concepts - Understanding the facet model
|
|
88
|
+
- Defining Cores - Entity and capability guide
|
|
89
|
+
- Defining Facets - Field visibility and access control
|
|
90
|
+
- Implementing Business Logic - Adapter pattern guide
|
|
91
|
+
- API Generation - REST endpoint documentation
|
|
92
|
+
- Auto-Mounting - Convention-based discovery guide
|
|
93
|
+
- Configuration - Authentication and feature flags
|
|
94
|
+
- Introspection - Runtime exploration guide
|
|
95
|
+
- Examples - Complete working examples
|
|
96
|
+
- Deployment - Production deployment guides
|
|
97
|
+
- Architecture - Design principles and internals
|
|
98
|
+
- Contributing - Contribution guidelines
|
|
99
|
+
|
|
100
|
+
- **Testing** - Complete test suite
|
|
101
|
+
- 82 RSpec examples covering all components
|
|
102
|
+
- Core DSL tests
|
|
103
|
+
- Facet system tests
|
|
104
|
+
- Loader and registry tests
|
|
105
|
+
- Configuration tests
|
|
106
|
+
- 100% test coverage for critical paths
|
|
107
|
+
|
|
108
|
+
- **CI/CD** - GitHub Actions workflow
|
|
109
|
+
- Ruby CI for versions 3.2, 3.3, 3.4, 4.0
|
|
110
|
+
- Automated test runs on push/PR
|
|
111
|
+
- Build status badge in README
|
|
112
|
+
|
|
113
|
+
#### Internal Infrastructure
|
|
114
|
+
- Registry system for cores and facets
|
|
115
|
+
- Loader with auto-discovery
|
|
116
|
+
- Executor with capability execution logic
|
|
117
|
+
- Error formatter with verbosity levels
|
|
118
|
+
- Custom Context class (Ruby 4 compatible, replaces OpenStruct)
|
|
119
|
+
- Grape API generator
|
|
120
|
+
- Grape entity generator with computed fields
|
|
121
|
+
|
|
122
|
+
### Technical Details
|
|
123
|
+
- **Ruby Version**: Requires Ruby >= 3.2.0
|
|
124
|
+
- **Dependencies**:
|
|
125
|
+
- grape ~> 2.0
|
|
126
|
+
- grape-entity ~> 1.0
|
|
127
|
+
- **License**: MIT
|
|
128
|
+
- **Framework Integration**: Rack, Rails, Sinatra
|
|
129
|
+
|
|
130
|
+
### Breaking Changes
|
|
131
|
+
- This is the initial release, no breaking changes
|
|
132
|
+
|
|
133
|
+
### Migration Guide
|
|
134
|
+
- N/A (initial release)
|
|
135
|
+
|
|
136
|
+
### Contributors
|
|
137
|
+
- Juan Carlos Garcia (@jcagarcia)
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Juan Carlos GarcÃa del Canto
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# Facera
|
|
2
|
+
|
|
3
|
+
**One semantic core. Multiple API facets. Zero duplication.**
|
|
4
|
+
|
|
5
|
+
Facera is a Ruby framework for building **multi-facet APIs** from a single semantic core. Define your domain model once, then expose different views for different consumers—all guaranteed consistent by design.
|
|
6
|
+
|
|
7
|
+
<img src="img/facera.png" alt="Facera logo" width="250"/>
|
|
8
|
+
|
|
9
|
+
[](https://badge.fury.io/rb/facera)
|
|
10
|
+
[](https://github.com/jcagarcia/facera/actions/workflows/ruby.yml)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Why Facera?
|
|
16
|
+
|
|
17
|
+
Modern systems expose APIs to many different consumers, leading to duplicated endpoints, inconsistent representations, and maintenance burden. **Facera solves this** by letting you define your system **once** as a semantic core, then automatically generate multiple consistent API facets.
|
|
18
|
+
|
|
19
|
+
### Before Facera
|
|
20
|
+
```
|
|
21
|
+
3 separate APIs × 5 endpoints = 15 implementations
|
|
22
|
+
+ 3 serializers + 3 auth systems + 3 test suites
|
|
23
|
+
= ~2000 lines of code
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### With Facera
|
|
27
|
+
```
|
|
28
|
+
1 core definition + 3 facet files + 1 config
|
|
29
|
+
= ~300 lines of code
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**85% less code, 100% consistency guaranteed.**
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
gem install facera
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or add to your Gemfile:
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
gem 'facera'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 1. Define Your Core
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
# cores/payment_core.rb
|
|
54
|
+
Facera.define_core(:payment) do
|
|
55
|
+
entity :payment do
|
|
56
|
+
attribute :id, :uuid, immutable: true
|
|
57
|
+
attribute :amount, :money, required: true
|
|
58
|
+
attribute :currency, :string, required: true
|
|
59
|
+
attribute :status, :enum, values: [:pending, :confirmed, :cancelled]
|
|
60
|
+
attribute :merchant_id, :uuid, required: true
|
|
61
|
+
attribute :customer_id, :uuid, required: true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
capability :create_payment, type: :create do
|
|
65
|
+
entity :payment
|
|
66
|
+
requires :amount, :currency, :merchant_id, :customer_id
|
|
67
|
+
validates { amount > 0 }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
capability :confirm_payment, type: :action do
|
|
71
|
+
entity :payment
|
|
72
|
+
requires :id
|
|
73
|
+
precondition { status == :pending }
|
|
74
|
+
transitions_to :confirmed
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 2. Define Facets
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
# facets/external_facet.rb
|
|
83
|
+
Facera.define_facet(:external, core: :payment) do
|
|
84
|
+
description "Public API for external clients"
|
|
85
|
+
|
|
86
|
+
expose :payment do
|
|
87
|
+
fields :id, :amount, :currency, :status
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
allow_capabilities :create_payment
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
# facets/internal_facet.rb
|
|
96
|
+
Facera.define_facet(:internal, core: :payment) do
|
|
97
|
+
description "Service-to-service API"
|
|
98
|
+
|
|
99
|
+
expose :payment do
|
|
100
|
+
fields :all
|
|
101
|
+
computed :processing_time do |payment|
|
|
102
|
+
Time.now - payment.created_at
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
allow_capabilities :all
|
|
107
|
+
end
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3. Implement Business Logic
|
|
111
|
+
|
|
112
|
+
Create an adapter to implement the actual logic:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
# adapters/payment_adapter.rb
|
|
116
|
+
class PaymentAdapter
|
|
117
|
+
include Facera::Adapter
|
|
118
|
+
|
|
119
|
+
def create_payment(params)
|
|
120
|
+
# Your business logic here
|
|
121
|
+
Payment.create!(
|
|
122
|
+
amount: params[:amount],
|
|
123
|
+
currency: params[:currency],
|
|
124
|
+
merchant_id: params[:merchant_id],
|
|
125
|
+
customer_id: params[:customer_id],
|
|
126
|
+
status: :pending
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def get_payment(params)
|
|
131
|
+
Payment.find(params[:id])
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def confirm_payment(params)
|
|
135
|
+
payment = Payment.find(params[:id])
|
|
136
|
+
payment.update!(status: :confirmed, confirmed_at: Time.now)
|
|
137
|
+
|
|
138
|
+
# Send confirmation email
|
|
139
|
+
PaymentMailer.confirmation(payment).deliver_later
|
|
140
|
+
|
|
141
|
+
payment
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Or use inline blocks for simple logic:
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
capability :simple_action, type: :action do
|
|
150
|
+
execute do |params|
|
|
151
|
+
# Simple inline logic
|
|
152
|
+
{ result: "done" }
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 4. Mount and Run
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
# config.ru
|
|
161
|
+
require 'facera'
|
|
162
|
+
|
|
163
|
+
Facera.configure do |config|
|
|
164
|
+
config.base_path = '/api'
|
|
165
|
+
config.version = 'v1'
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
app = Rack::Builder.new do
|
|
169
|
+
Facera.auto_mount!(self)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
run app
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Start your server:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
rackup -p 9292
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**That's it!** You now have multiple APIs auto-generated:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# External API (limited fields)
|
|
185
|
+
curl http://localhost:9292/api/v1/health
|
|
186
|
+
curl -X POST http://localhost:9292/api/v1/payments \
|
|
187
|
+
-H 'Content-Type: application/json' \
|
|
188
|
+
-d '{"amount": 100.0, "currency": "USD", ...}'
|
|
189
|
+
|
|
190
|
+
# Internal API (all fields + computed)
|
|
191
|
+
curl http://localhost:9292/api/internal/v1/payments/:id
|
|
192
|
+
|
|
193
|
+
# Introspection
|
|
194
|
+
curl http://localhost:9292/api/facera/introspect
|
|
195
|
+
curl http://localhost:9292/api/facera/openapi/external
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Key Features
|
|
201
|
+
|
|
202
|
+
- 💎 **Single Source of Truth** - Define domain model once
|
|
203
|
+
- 🎠**Multiple Facets** - Different views for different consumers
|
|
204
|
+
- 🚀 **Auto-Generated APIs** - REST endpoints created automatically
|
|
205
|
+
- 📦 **Zero Configuration** - Convention-based auto-discovery
|
|
206
|
+
- 📚 **Built-in Introspection** - Explore your APIs at runtime
|
|
207
|
+
- 📄 **OpenAPI Generation** - Auto-generated API documentation
|
|
208
|
+
- 🔒 **Type Safety** - Strong typing for entities and capabilities
|
|
209
|
+
- ✅ **Business Rules** - Invariants and validations in the core
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Documentation
|
|
214
|
+
|
|
215
|
+
Comprehensive documentation available in the [wiki](https://github.com/jcagarcia/facera/wiki):
|
|
216
|
+
|
|
217
|
+
- **[Core Concepts](https://github.com/jcagarcia/facera/wiki/Core-Concepts)** - Understanding cores, facets, and projections
|
|
218
|
+
- **[Defining Cores](https://github.com/jcagarcia/facera/wiki/Defining-Cores)** - Entities, capabilities, and invariants
|
|
219
|
+
- **[Defining Facets](https://github.com/jcagarcia/facera/wiki/Defining-Facets)** - Field visibility and capability access
|
|
220
|
+
- **[Implementing Business Logic](https://github.com/jcagarcia/facera/wiki/Implementing-Business-Logic)** - Adapters and execute blocks
|
|
221
|
+
- **[API Generation](https://github.com/jcagarcia/facera/wiki/API-Generation)** - Auto-generated REST endpoints
|
|
222
|
+
- **[Auto-Mounting](https://github.com/jcagarcia/facera/wiki/Auto-Mounting)** - Convention-based discovery
|
|
223
|
+
- **[Configuration](https://github.com/jcagarcia/facera/wiki/Configuration)** - Authentication, paths, and feature flags
|
|
224
|
+
- **[Introspection](https://github.com/jcagarcia/facera/wiki/Introspection)** - Runtime introspection and OpenAPI
|
|
225
|
+
- **[Deployment](https://github.com/jcagarcia/facera/wiki/Deployment)** - Production deployment guides
|
|
226
|
+
- **[Architecture](https://github.com/jcagarcia/facera/wiki/Architecture)** - Design principles and framework integration
|
|
227
|
+
- **[Examples](https://github.com/jcagarcia/facera/wiki/Examples)** - Complete working examples
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Example Structure
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
your_app/
|
|
235
|
+
├── cores/
|
|
236
|
+
│ └── payment_core.rb # Domain model
|
|
237
|
+
├── adapters/
|
|
238
|
+
│ └── payment_adapter.rb # Business logic
|
|
239
|
+
├── facets/
|
|
240
|
+
│ ├── external_facet.rb # Public API
|
|
241
|
+
│ ├── internal_facet.rb # Service API
|
|
242
|
+
│ └── operator_facet.rb # Admin API
|
|
243
|
+
└── config.ru # Rack config
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Facera auto-discovers everything and generates:
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
GET /api/v1/health
|
|
250
|
+
POST /api/v1/payments
|
|
251
|
+
GET /api/v1/payments/:id
|
|
252
|
+
|
|
253
|
+
GET /api/internal/v1/health
|
|
254
|
+
POST /api/internal/v1/payments
|
|
255
|
+
GET /api/internal/v1/payments/:id
|
|
256
|
+
POST /api/internal/v1/payments/:id/confirm
|
|
257
|
+
|
|
258
|
+
GET /api/facera/introspect
|
|
259
|
+
GET /api/facera/cores
|
|
260
|
+
GET /api/facera/facets
|
|
261
|
+
GET /api/facera/openapi
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Examples
|
|
267
|
+
|
|
268
|
+
See the [examples/](examples/) directory for complete working examples:
|
|
269
|
+
|
|
270
|
+
- **Phase Examples** - `01_core_dsl.rb` through `04_auto_mounting.rb`
|
|
271
|
+
- **Runnable Server** - `examples/server/` with multiple facets
|
|
272
|
+
|
|
273
|
+
Run the server:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
cd examples/server
|
|
277
|
+
rackup -p 9292
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Contributing
|
|
283
|
+
|
|
284
|
+
Contributions welcome! Please read [CONTRIBUTING.md](https://github.com/jcagarcia/facera/wiki/Contributing) for guidelines.
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
git clone https://github.com/yourusername/facera.git
|
|
288
|
+
cd facera
|
|
289
|
+
bundle install
|
|
290
|
+
bundle exec rspec
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## License
|
|
296
|
+
|
|
297
|
+
MIT License - see [LICENSE](LICENSE) for details
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Credits
|
|
302
|
+
|
|
303
|
+
Created by [Juan Carlos Garcia](https://github.com/jcagarcia)
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
**One semantic core. Multiple API facets. Zero duplication.**
|
|
308
|
+
|
|
309
|
+
Start building better APIs today! 💎
|