This respository implements a small three tier web application, using ADL as the "typing glue". It's intended to demonstrate the benefits of the strong cross language type system provided by ADL, and also to serve as a template that can be forked as a starting point for new projects.
The application is a trivial messaging system, where authenticated users can post messages to a shared noticeboard.
The technology stack consists of:
- postgresql for the relational store
- rust+poem+sqlx for the application server
- typescript+react for the web user interface
ADL is a framework for building cross language data models. In this repo we use ADL to define
- the relational database schema
- the client/server http based API
- the server config file format
From these, we generate:
- the postgres SQL for the db schema
- the rust db schema binding
- the rust api binding (used here)
- the typescript api binding (used here)
Having strong types end to end in the system provides many benefits. Some of these are described below.
The ADL data model is more expressive than SQL - hence we benefit from having ADL as the db schema source of truth. For
example if we wish to store a complex structured value in a db field we can define it's type in ADL whilst persisting
it as a postgresql jsonb
value. The rust db binding will automatically map between the db json value and the ADL generated
rust type whenever reading/writing the field.
Additionally, in our ADL db model, we distinguished between db keys of different types. eg db keys for the user table (AppUserId), vs db keys for the message table(MessageId). For these we generate distinct key types in the rust server code, eliminating at compile time the possibility of mixing up key types.
Each ADL defined API endpoint declares its security policy, which is a value of type HttpSecurity. In the rust server implementation this is implemented for all endpoints (existing and future) at a single point
The typescript code has runtime type information about all ADL types. This means that it's possible to automatically generate a UI form for any ADL type, no matter how complex it's algebraic structure. Furthermore, the ADL file common/strings.adl defines specific types of strings, and any generated forms reflects the use of these. For example:
- Type
StringNE
produces a string field that must not be empty - Type
EmailAddress
produces a string field that must be a valid email - Type
Password
produces a hidden string field (with a show button) - Type
StringML
produces a multi line string editor
Also the generated forms validate the different db types, described above:
The system includes an "API workbench" which is a stand alone UI automatically derived from the ADL definition. This UI provides generated forms to execute all api endpoints, and capture their responses. As soon an an endpoint is added or modified this UI is updated accordingly.
The API Workbench references the ADL endpoint security policies (see above) to ensure that only the endpoints accessible to the current user are shown.
Currently linux and macos are supported.
Install docker and rust/cargo for your platform. Then install deno, node, pnpm, and adl into a repo local directory by sourcing the local setup script:
. deno/local-setup.sh
Check installed tool versions with:
deno --version
node --version
adlc show --version
When you've changed any ADL, regenerate rust/typescript/sql code with
deno task genadl
(cd platform/dev; docker compose up -d db)
(
cd rust/server
export DB_CONNECTION_URL=postgresql://postgres:xyzzy@localhost:5432/appdb
cargo test -- --test-threads=1
)
(
cd rust/server
export PROTOAPP_SERVER_CONFIG='{
"http_bind_addr": "0.0.0.0:8081",
"db": {
"host": "localhost",
"port": 5432,
"dbname": "appdb",
"user": "postgres",
"password": "xyzzy"
},
"jwt_access_secret": "shouldbetrulysecretbutnotrightnow",
"jwt_refresh_secret": "nottomentionthisone"
}'
export RUST_LOG=info
cargo run --bin protoapp-server
)
This will create the db schema and/or apply any necessary migrations
(
cd rust/server
export DB_CONNECTION_URL=postgresql://postgres:xyzzy@localhost:5432/appdb
cargo run --bin protoapp-tools -- create-user joe@test.com Joe xyzzy1
cargo run --bin protoapp-tools -- create-user --is-admin sarah@test.com Sarah abcdef
)
(
cd ts/ui
# note pnpm is installed by local-setup.sh
pnpm install
pnpm run dev
)
The (minimal) web application will be accessible at: http://localhost:5173 The api workbench will be accessible at: http://localhost:5173/api-dashboard