Dynamic Resource is a Baasic module that enables us to create and manipulate data resources by consuming a RESTful API. In profane terms, Baasic Dynamic Resources provide services which are meant for CRUD operations in AngularJS applications. For more details, read the previous blog post.
Introduction
Every application needs CRUD operations on data and using Dynamic Resources, we can do it the easy way. There is no need for creating database tables and various layers used to access the data - this is accomplished by creating Dynamic Resources and Dynamic Resource Schemas.
Dynamic Resources are based on JavaScript Object Notation (JSON) format. Dynamic Resource Schema is based on a JSON Schema Draft 6 and defines the structure of the data (Resource) which is sent to the backend. A resource is a JSON object we are making using the previously defined JSON Dynamic Resource Schema.
Dynamic Resources are available in Baasic SDK as an npm package. To install it, use the following:
npm install baasic-angularjs@^2.0.0 --save
After you set everything up, proceed to the example.
Dynamic Resource Schema
In order to create Resources to perform CRUD operations on, we need to define the Dynamic Schema first - and then create the resources using the Schema.
As mentioned earlier, we have services that perform CRUD operations for us, so for the creation of the Dynamic Resource Schema, we will use the create
operation, and for the Schema managing, there is the baasicDynamicSchemaService
service.
You can find all methods the Schema service provides here.
There is one convention that Baasic adheres to when creating Dynamic Resource Schemas - it always defines a hidden read-only property named id
(in the Schema; mentioned in the previous post). It is a unique id Baasic generates for each Dynamic Resource object, so you don’t have to - but if you want to have an identifying field of a different type (e.g., integer), you have to make sure that the values are unique and name your field differently.
Here is an example - a TODO list (similar to one here), to demonstrate how easy it is to perform CRUD operations with the resources.
List Schema
First, we need to define resource properties - the list should contain multiple notes, have a title and belong to a single user.
Now that the properties are defined, we can create the look for our Dynamic Resource Schema, which we will call TODOList
:
{
"type": "object",
"properties": {
"id": {
"readonly": "true",
"type": "string"
},
"title": {
"type": "string"
},
"userId": {
"type": "string"
},
"dateCreated": {
"type": "string",
"format": "date-time",
"required": true
},
"dateUpdated": {
"type": "string",
"format": "date-time",
"required": true
}
}
}
If necessary, along with the schema object above, you can create the Dynamic Schema by calling the generate
method of the dynamicSchemaService
, or using extra properties defined below if the schema object is provided.
The Schema has an enforceSchemaValidation option, which defines if Baasic should validate inserts and updates of resource objects and reject them if they don’t adhere to the Dynamic Resource Schema. In our case, we set this option to true
, because we do not want the user to send the wrong type of data.
The description and the name are optional.
In our TODOList
schema, the description is “TODO list,” and the type of the resource is object
with previously defined properties:
var resource = {
"description": "TODO list",
"enforceSchemaValidation": true,
"name": "TODOList",
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"title": "Unique Identifier",
"hidden": true,
"readonly": true
},
"userId": {
"type": "string",
"format": "UUID",
"required": true
},
"title": {
"type": "string",
"required": true
},
"dateCreated": {
"type": "string",
"format": "date-time",
"required": true
},
"dateUpdated": {
"type": "string",
"format": "date-time",
"required": true
}
}
}
}
In the JSON object, we defined the type of property, in our case all types are string
with a certain format, and all fields are required.
To create the Dynamic Resource Schema for our resource object, we should use:
baasicDynamicSchemaService.create(resource)
.success(function (data) {
// perform success action here
})
.error(function (response, status, headers, config) {
// perform error handling here
});
The returned Baasic response contains information about the created schema:
{
"dateCreated": "2017-10-01T03:40:27.970894Z",
"dateUpdated": "2017-10-01T03:40:27.970894Z",
"description": "A TODO list, collection of notes.",
"enforceSchemaValidation": true,
"id": "1EO7og6N5qAyDj9VW3FpT3",
"name": "TODOList",
"owner": null,
"ownerId": "mL1l5dz7sgLKJr9T0DP617",
"schema": {
"properties": {
"id": {
"hidden": true,
"readonly": true,
"title": "Unique Identifier",
"type": "string"
},
"title": {"type": "string"},
"userId": {"type": "string"},
"dateCreated": {
"type": "string",
"format": "date-time",
"required": true
},
"dateUpdated": {
"type": "string",
"format": "date-time",
"required": true
}
},
"type": "object"
}
}
When the schema is created, we can modify it by calling update
, or delete it by calling the remove
method.
Now that we defined the schema with its properties, we can create the schema for the list notes.
Note Schema
The note schema contains properties like noteText
, ordinal
, checked
, and listId
, so we can connect it to the list it belongs. It is created the same way as the TODOList
schema.
By generating the schema from the note resource (JSON object) calling the generate
method, we will get properly defined JSON schema from our object in one step:
var note = {
"noteText": "Buy muffins for today\'s dessert.",
"listId": "LTpInP3M00Kdo6WyHeo1hw",
"ordinal": 0,
"checked": false
}
baasicDynamicSchemaService.generate(note)
.success(function (data) {
// perform success action here
})
.error(function (response, status, headers, config) {
// perform error handling here
});
and the Baasic response is:
var note = {
"title": "Note Schema",
"type": "object",
"properties": {
"id": {
"hidden": true,
"readonly": true,
"title": "Unique Identifier",
"type": "string"
},
"noteText": {
"type": "string"
},
"listId": {
"type": "string"
},
"ordinal": {
"type": "integer"
},
"checked": {
"type: "boolean"
}
}
}
Once the schema object is generated, we can create it using the create
method and add the needed properties, such as "enforceSchemaValidation": true
and "name": "Note"
. We can also add the name to the response object for clearer writing:
var noteSchema = {
"properties": {
"id": {
"hidden": true,
"readonly": true,
"title": "Unique Identifier",
"type": "string"
},
"listId": {"type": "string"},
"noteText": {"type": "string"},
"ordinal": {"type": "integer"},
"checked": {"type": "boolean"}
},
"type": "object"
}
baasicDynamicSchemaService.create({
schema : noteSchema,
name : 'Note',
description : 'Note Schema',
enforceSchemaValidation : true
})
.success(function (data) {
// perform success action here
})
.error(function (response, status, headers, config) {
// perform error handling here
});
And the Baasic response is:
{
"dateCreated": "2017-10-01T16:50:49.137309Z",
"dateUpdated": "2017-10-01T16:50:49.137309Z",
"description": "A TODO note.",
"enforceSchemaValidation": true,
"id": "4GZx4c2bqqUL2AJ00LaPE3",
"name": "Note",
"owner": null,
"ownerId": "mL1l5dz7sgLKJr9T0DP617",
"schema": {
"properties": {
"checked": {"type": "boolean"},
"id": {
"hidden": true,
"readonly": true,
"title": "Unique Identifier",
"type": "string"
},
"listId": {"type": "string"},
"noteText": {"type": "string"},
"ordinal": {"type": "integer"}
},
"type": "object"
}
}
Resource objects
Now that the Dynamic Resource Schemas are defined and ready, resource objects can be created by calling the baasicDynamicResourceService
service. This service provides an easy way to consume Baasic Dynamic Resource REST API end-points. To obtain needed routes, baasicDynamicResourceService
uses baasicDynamicResourceRouteService
.
Here you can find all Dynamic Resource services provided by the SDK.
List Resource
To connect the List
resource as the parent to the Note
schema, we will use the listId
property.
An example of a JSON object list resource:
var groceryShoppingList = {
"id": "LTpInP3M00Kdo6WyHeo1hw",
"title": "Weekly grocery shopping",
"userId": "D8xPO4C5rE6B66LZ8wqNBQ"
}
To create the groceryShoppingList
, we are calling the create
method:
baasicDynamicResourceService.create('List', groceryShoppingList)
.success(function (data) {
// perform success action here
})
.error(function (response, status, headers, config) {
// perform error handling here
});
- the first parameter in the
create
method is the schema name, and the second is the object being created - we can manipulate the resource object using other methods like
update
,patch
orremove
- in this case, we added the id to the example just to make it more clear (don’t forget that Baasic will provide you with the id automatically, you can’t define it yourself)
The Baasic response for the create
method is:
{
"id": "LTpInP3M00Kdo6WyHeo1hw",
"title": "Weekly grocery shopping",
"userId": "D8xPO4C5rE6B66LZ8wqNBQ"
}
Now that the List
resource is ready, we can start posting notes defined through the Note
schema.
Note Resource
A note resource is a single entry in the list. It contains the text of the note and information about the list to which it belongs.
Example of a note resource JSON object:
var muffinNote = {
"id": "zUre3yin8k289oukEQ2SRg",
"noteText": "Buy muffins for today\'s dessert.",
"listId": "LTpInP3M00Kdo6WyHeo1hw",
"ordinal": 0,
"checked": false
}
As seen above, to create a note, we use the create
method along with the schema name ‘Note’:
baasicDynamicResourceService.create('Note', muffinNote)
.success(function (data) {
// perform success action here
})
.error(function (response, status, headers, config) {
// perform error handling here
});
Working with Dynamic Resources
Once the resources are defined and the resource objects are added, they can be manipulated and queried. We have shown a way you can create resources, and in a similar way you can update, delete or fetch them using methods listed here.
For example, we can fetch list items using the page number, page size, order by, order direction, and search parameters, by calling the method find
as shown below:
baasicDynamicResourceService.find('TODOList', {
pageNumber : 1,
pageSize : 10,
orderBy : 'title',
orderDirection : 'asc',
search : "WHERE 'title' LIKE '%grocery%'"
})
.success(function (collection) {
// perform success action here
})
.error(function (response, status, headers, config) {
// perform error handling here
});
The result of querying using BQL (Baasic Query Language, a SQL-like language) and sending paging parameters as we desire looks like this:
{
"_embedded": {
"item": [
{
"_embedded": {},
"_links": {,...},
"id": "LTpInP3M00Kdo6WyHeo1hw",
"title": "Weekly grocery shopping",
"userId": "D8xPO4C5rE6B66LZ8wqNBQ"
}
]
},
"embed": null,
"page": 1,
"recordsPerPage": 10,
"searchQuery": "WHERE 'title' LIKE '%grocery%'",
"sort": 'title|asc',
"totalRecords": 1
}
The searchQuery parameter expression "WHERE 'title' LIKE '%grocery%'"
is BQL - we will dedicate a separate blog post on this important topic.
So, Baasic solves the problem of sorting, filtering and paging, all that’s left to do is handle the given data.
We can get a certain resource, in our case the list, by its identifier like this:
baasicDynamicResourceService.get('TODOList', 'LTpInP3M00Kdo6WyHeo1hw')
.success(function (data) {
// perform success action here
})
.error(function (response, status, headers, config) {
// perform error handling here
});
And with the given data from Baasic, we can delete the resource as well:
baasicDynamicResourceService.remove(dynamicResource)
.success(function (data) {
// perform success action here
})
.error(function (response, status, headers, config) {
// perform error handling here
});
Resource permissions - ACLs (access control list)
Since every application needs authorization mechanisms, Baasic offers permission-based authorization system that includes users and roles in the application. There are end-point and object level ACLs for Dynamic Schemas and Resources, and Baasic provides both solutions out of the box. Permissions have a standard set of actions: create, read, update, delete, and full. Full permission (besides the CRUD actions) allows the user to change the permissions for the resource and in most cases is assigned to a user with the administrator role.
For every Dynamic Resource created, you can set permissions of who you want the resource to be available to (by role or user). By default, the Dynamic Resource Schema allows users to read upon creation, while owner and administrators have the full permission.
For more information on permissions, stay tuned as we will provide more detail in the upcoming posts.
Summary
The examples above have shown some Dynamic Resource concepts, an easy usage of the SDK API, and with no required knowledge of how RESTful API works, we can focus on calling the methods that give us detailed response accordingly. Besides the fact that this is an AngularJS related post, note that this example can be used with the new Angular 2 or 4 because of Baasic’s Angular SDK similar API.
Here is the list of available methods needed for the Dynamic Resource Module.
For any questions, feel free to comment below.
Feel free to leave a comment
comments powered by Disqus