Architectural Overview
Architectural Overview
Docker Containers
As shown below, there are typically 2-3 "machines" in operation:
* Your local host (in grey), where the Customizable Project files (ApiLogicProject
) are stored,
and your Dev Tools (IDE etc) operate
- The ApiLogicServer Docker container (blue), which contains:
- The ApiLogicServer, with CLI (Command Language Interface) commands:
create
to create projects on your local hostrun
to execute projects, utilizing the various runtimes (Flask, SQLAlchemy, SAFRS API, Logic, Flask App Builder)
- A Python environment to support execution, and development using your IDE
-
Neither API nor logic execution creates / uses additional files or database data; your database access is via standard SQLAlchemy models
- The exception to this is Flask App Builder, which creates additional database tables for security authorization
-
The database (purple) can run as a separate Docker container, in your local host, or (for the demo) within the ApiLogicServer docker container
Pip Install - ApiLogicServer in local Python environment
Alternative option: pip install
You can also run ApiLogicServer without Docker. The familiar pip install ApiLogicServer
creates the ApiLogicServer in your venv
instead of the Docker container. The contents are identical - the ApiLogicServer create
and run
components.
We recommend, however, that you take a good look at Docker: * It avoids a sometimes-tricky Python install * It isolates your projects into containers * It is quite likely the eventual deployment architecture, so you're already in step with that
ApiLogicServer Key Components
Component | Provides |
---|---|
SQLAlchemy | Python-friendly ORM (analogous to Hiberate, JPA) |
Logic Bank | Multi-Table Derivation and Constraint Rules Python Events (e.g., send mail, message) Extensible with Python |
SAFRS | JSON:API and swagger, based on SQLAlchemy |
SAFRS-React-Admin | Executable React Admin UI, using SAFRS |
Project Structure
When you have created your project, you will find the following project directory in ~/dev/servers
on your (grey) local host (here opened in VS Code):
Your docker container (blue) files include Python, Python libraries, and API Logic Server. The Python project above utilizes IDE remote-container
support (visible at the lower left in the preceding diagram), which utilizes the docker container (not local host) version of Python.
Your docker container looks like this:
IDE Friendly
The project structure above can be loaded into any IDE for code editing, deubgging, etc. For more information on using IDEs, see here.
Tool-friendly - file-based
All project elements are files - no database or binary objects. So, you can store objects in source control systems like git, diff/merge them, etc.
Internals - How It Works
Project Creation
The ApiLogicServer CLI create
(or create-and-run
) command creates the project structure shown below - for more information, see here.
API Execution: api_logic_server_run.py
Execution begins in api_logic_server_run.py
. Your customizations are done to the files noted in the callouts below.
api_logic_server_run.py
(a file created in your ApiLogicProject) sets up a Flask app, the database, logic and api:
-
Database Setup: It imports
api/expose_api_models
which importsdatabase/models.py
, which then importsdatabase/customize_models.py
for your model extensions.api_logic_server_run.py
then sets up flask, and opens the database withdb = safrs.DB
-
Logic Setup: It then calls
LogicBank.activate
, passingdeclare_logic
which loads your declared rules into Logic Bank. -
API Setup: It next invokes
api/expose_api_models
. This calls safrs to create the end points and the swagger information, based on the createddatabase/models.py
(the models used by the SQLAlchemy ORM). It finally callsapi/customize.py
where you can add your own services. The sample includes a trivial Hello World, as well asadd_order
.
Logic Execution
SAFRS API listens for API calls, e.g., from the Admin App. When updates are issued:
-
Invokes SQLAlchemy updates: SAFRS calls SQLAlchemy, passing a set of rows comprising a database transaction
-
before_flush
: SQLAlchemy provides abefore_flush
event, where all the update rows are assembled and passed toLogic Bank
(no relation to retail!). -
Logic Execution: Logic Bank reviews the rows, and based on what has change, prunes rules for unchanged data, and executes / optimizes relevant logic in an appropriate order.
Declarative Logic is critical
Logic addresses multi-table derivations, constraints, and actions such as sending messages or emails. These can constitute nearly half the effort in transactional systems.
Admin App Execution: ui/admin/admin.yaml
http://localhost:5656/ redirects to ui/admin/index.html
which loads the react-admin single-page app into your browser.
It then loads your ui/admin/admin.yaml
, and responds to the various clicks by invoking the API (and hence the update logic), or the swagger at http://localhost:5656/api.
Key Observations: Extensible Declarative Automation
While the most striking element of ApiLogicServer is automation - a running UI and API from a database - there are some important aspects, described below.
Customizable, Declarative Models
Observe that the key files for defining API, UI and Logic are not procedural code. They are declarative: specifications of what you want to happen, not how it's implemented:
-
Logic looks more like a specification than code
-
UI looks like a list of Objects and Attributes to display
-
API looks like a list of Objects
This is important because they are orders of magnitude shorter, and therefore far easier to understand, and to customize.
For example, consider the UI, defined by ui/admin/admin.yaml
. This is in lieu of hundreds of lines of very complex HTML and JavaScript.
Extensible
ApiLogicServer makes provisions for you to add standard Python code for aspects of your project that are automated - custom end points, extensions to the data model, logic (rules plus Python).
And, of course, the API means you are unblocked for creating custom UIs and integrations.
Includes Logic
As noted above, multi-table constraints and derivations can constitute nearly half the effort in transactional systems.
Unlike most systems that address such logic with "your code goes here", ApiLogicServer provides declarative spreadsheet-like rules, extensible with Python, as described here. Rules are 40X more concise than code.
Rule execution is via a transaction logic engine, a complementary technology to traditional RETE engines. The transaction logic engine is specifically designed to optimize integrity and performance for transactional logic, which is not possible in RETE engines. See here for more information on their operation.
Technology Adoption Considerations
Standards-based
Development and runtime architectures are what programmers expect: * As noted above, the Key Project Components are standard Python packages for APIs, data access. * Projects developed in standard IDEs, and deployed in standard containers.
Near-Zero Learning Curve - no frameworks, etc
ApiLogicServer has a near-zero learning curve. You do not need to know Python, SQLAlchemy, React, or JSONapi_logic_serverPIs to get started. You have a running project in moments, customizable without requiring deep understanding of any of these frameworks. Making extensions, of course, begins to require more technical background.
Allow a few days for learning logic
Logic represents the starkest different between procedural code and declarative rules. It requires a few days to get the hang of it. We recommend you explore this documentation.
Business Agility
ApiLogicServer automation creates a running project nearly instantly, but it also is designed to help you adapt to business changes more rapidly:
- Rebuild support to update existing projects from database or data model changes
- Logic provides automatic reordering and reoptimization as logic is altered
Technology Agility - an Application Virtual Machine
Models are, somewhat by their very nature, rather technology independent. Instead of React, the UI specification could be implemented on Angular. Instead of interpreted, the logic could be code-generated onto any language. And so forth.
You can think of the Key Project Components as an Application Virtual Machine that executes ApiLogicProjects. As new underlying technology becomes available, new AVMs could be developed that migrate the declarative elements of your UI, API and Logic - without coding change. Because, they are models, not code.
This provides an unprecedented preservation of your application investment over underlying technology change.
Automation Reduces Risk
Automation not only gets results fast and simplifies adapting to change, it also reduces risk.
Coding Risk
The most troublesome bugs are silent failures - no stacktrace, but the wrong answer.
Automation address this by designing out whole classes of error:
- the UI and API just work
- logic is automatically re-used over all Use Cases
Architectural Risk
Technology complexity makes it get hard to get projects that even work, much less work right. Projects commonly suffer from a wide variety of architectural flaws:
- business logic is not shared, but repeated in each UI controller... and each integration
- pagination may not be provided for all screens
And so forth. These cause project failures, far too often.
But automation can help - since your declarative models only stipulate what, the system bears the responsibility for the how -- and getting it right. Each of the architectural items above are automated by the system.
Requirements Risk
Requirements risk can represent an even greater challenge. The reality that users may only realize the real requirements when they actually use running screens with real data. The problem, of course, is that these are often available after considerable time and effort.
That's why working software now is so important - users get screens right away. These can identify data model errors ("hey... customers have more than one address") or business logic requirements ("hey.... we need to check the credit limit").