Uranio CORE is a Typescript repo that provides the Business Logic Layer (BLL) classes for an API service.
Uranio CORE can be extended to Uranio API for deploying a full webserice.
It can also be used for developing application that do not need a webservices, like native Apps.
It has built-in Access Control Layer (ACL) classes and Data Access Layer (DAL) classes.
For now it can interacts with MongoDB but more DB will be available in the future.
In URANIO, a database record is called Atom
.
For example there can be a Product Atom type.
The type of the object that represents the Product Atom will be Atom<'product'>
.
The type Atom<T extends AtomName>
accepts as generic the type AtomName
.
The type AtomName
is the union of all the Atom names.
The Atom names are auto generated by uranio-cli
that reads the directory
names inside src/atoms
.
For example with this folder structure:
node_modules
src
`--atoms
|--product
| `--index.ts
`--customer
`--index.ts
There will be generated an Atom
with name product
and an Atom
with name
customer
.
type AtomName
will be 'product' | 'customer'
.
And Atom
can be of type Atom<'product'>
or Atom<'customer'>
;
The Atom Atom<'product'>
can be defined inside src/atoms/product/index.ts
:
For example:
import uranio from 'uranio';
export default uranio.register.atom({
properties: {
title: {
type: uranio.types.PropertyType.TEXT,
label: 'Title'
},
price: {
type: uranio.tyoes.PropertyType.FLOAT,
label: 'Price'
},
// ...
},
// ...
});
It will make Atom<'product'>
type:
const product:Atom<'product'> = {
_id: '61d81a12f3e4ea6edbdcdd1e',
_date: '2022-01-07T10:46:42.584Z',
title: 'Product title',
price: 119.99
};
Type Atom
represents the type of the object stored in the database. Therefore
it has, among the user defined properties, also the following ones:
_id
_date
_r
(optional) - Reading permission [see section ACL]_w
(optional) - Writing permission [see section ACL]
An AtomShape
has only the user defined properties. So it will be like so:
const product_shape:AtomShape<'product'> = {
title: 'Product title',
price: 119.99
};
This type is useful for insert a new Atom
in the database.
If an Atom has as parameter value another Atom
is called Molecule.
Molecule<A,D>
accept two generics. The first is the AtomName
, the second is
how deep goes the object definition.
For example if an Atom
is defined like so:
// src/atoms/order/index.ts
import uranio from 'uranio';
export default uranio.register.atom({
properties:{
products: {
type: uranio.types.PropertyType.ATOM_ARRAY,
atom: 'product',
label: 'Products'
},
customer: {
type: uranio.types.PropertyType.ATOM,
atom: 'customer',
label: 'Customer'
},
}
});
The type Molecule<'order', 1>
will be:
const product:Molecule<'order', 1> = {
_id: '61dec7150529224d13ea7994',
_date: '2022-01-12T12:18:29.617Z',
products: [
{
title: 'Trousers',
price: 119.99
},
{
title: 'Shirt',
price: 9.99
}
],
customer: {
first_name: 'John',
email: 'john@email.com',
...
}
};
Molecule<'order', 0>
is exactly like Atom<'order'>
:
const product:Molecule<'order', 0> = {
_id: '61dec7150529224d13ea7994',
_date: '2022-01-12T12:18:29.617Z',
products: ['61dec7150529224d13ea7997', '61de9f518fb75c70ad33310a'],
customer: '61dc3434a99090002c28cb4b'
};
Uranio CORE provides BLL classes for Atoms
.
import uranio from 'uranio';
const products_bll = uranio.bll.create('product');
const product = await products_bll.find_by_id('61dec7150529224d13ea7997');
The BLL provides the following methods to each realtion:
find
find_by_id
find_one
count
insert_new
update_by_id
update_one
remove_by_id
remove_one
authorize
upload
(available only for Atommedia
)presigned
(available only for Atommedia
)
Uranio CORE provides a BLL for authentication:
const auth_bll = uranio.bll.auth.create('superuser');
const urn_response = await auth_bll.authenticate('email@email.com', '[PASSOWRD]');
if(urn_response.success){
const token = urn_response.payload.token;
}
bll.auth.create
accept only AuthAtom
.
See
AuthAtoms
The method authenticate
returns a token that can be use for authorization.
const passport = auth_bll.get_passort(token);
const products_bll = uranio.bll.create('product', passport);
const products = await products_bll.find({});
AuthAtoms are Atoms that can authenticate. In order to define an AuthAtom,
it must have the attribute authenticate
equal to true
in book.ts
.
// src/atoms/customer/index.ts
import uranio from 'uranio';
export default uranio.register.atom({
authenticate: true,
properties:{
// ...
}
});
Type AuthName
is the union of all the Atom names that can authenticate.
AuthAtoms must have the properties email
, password
and groups
defined like so:
// src/atoms/customer/index.ts
import uranio from 'uranio';
export default uranio.register.atom({
authenticate: true,
properties:{
email:{
type: uranio.types.PropertyType.EMAIL,
...
},
password:{
type: uranio.types.PropertyType.ENCRYPTED,
...
},
groups:{
type: uranio.types.PropertyType.ATOM_ARRAY,
...
}
}
});
When a new AuthAtom is created, it will be created also the Group for it, so that each AuthAtom has at least its own group.
Groups are necessary for passing the ACL (Access Control Layer).
See ACL Section
Uranio CORE provides out of hte box the following Atom
s
superuser
group
user
media
It is possible to initialize Uranio without them by opting them out in the config file
uranio.toml
In order to use the ACL]superuser
andgroup
must be imported.
Superusers are user that bypass the ACL (Access Control Layer). They can interact with the DB without authentication.
Superuser are AuthAtom
Users are entities that can interact with the DB after they have been authenticated.
User are AuthAtom
Each AuthAtom
can have multiple groups. The ACL (Access Control Layer) uses groups
to give permission to the user.
The Media relation has an additional method upload
for uploading files.
Uranio CORE can upload media to AWS S3.
More platform will be adedd - i.e. Google Cloud Storage, Local, ...
The Access Control Layer is an Access Layer that will check if it is possible to make the query and filters the results with only the accessible data.
The permission on each Relation can be UNIFORM
or GRANULAR
.
Default is UNIFORM
.
UNIFORM
permission will check on a Relation level.
GRANULAR
permission will check on a Record level.
In order to the ACL to work, it needs User and Group Relations. Each request is made by an User. Each User has Groups.
Each Relation and each Record have two attributes _r
and _w
, respectively
for reading and writing permission. The value of these attributes is a
Group ID Array.
_r
will narrow from Everybody
_w
will widen from Nobody
_r == nullish
-> Everybody can read
_w == nullish
-> Nobody can write
Uranio CORE creates 3 connections to 3 different databases:
main
log
trash
The main
db is where all the realations are stored by default.
The log
db is made for storing logs.
The trash
db stores a copy of all deleted records.
When using MongoDB each Atom's property can have a key named search
.
If the key search
is set to true
MongoDB will make a text index
on that key.
See Mongo docs
When the method search
is called on a BLL class, URANIO will create a query
in this fashion:
{$or: [{atom_key1: {$regex: query, $options: 'i'}}, {atom_key2: {$regex: query, $options: 'i'}}, ...]}
This will make a regex search on all the Atom's properties with search
equal
to true
.