Creating a Simple CRM with REST API in 10 Minutes
Whipping up a CRM with a REST API isn't too difficult. In fact, you can create a CRM in just 10 minutes. Learn how.
Join the DZone community and get the full member experience.
Join For FreeImagine that we need to store business contacts and track their status. It’s a typical CRM application feature. Let’s take a look at how AllcountJS framework could help us to solve this problem in 10 minutes.
AllcountJS is an open-source rapid application development framework. It’s built on top of the MEAN (MongoDB, Express, AngularJS, NodeJS) stack. But “M” can be replaced with another database including SQL one.
Core part of AllcountJS application is a .js configuration file with mostly declarative description of application structure: entities, their fields, relations, views, roles and permissions.
All CRUD operations, default views, user management features are available out of the box.
Built-in Role Based Access Control allows to manage access rights based on user roles.
UI is generated automatically using AngularJS, Twitter Bootstrap, Jade and Font Awesome icons.
AllcountJS also provides JSON REST API to perform all operations available to users. If you need to add some specific functionality to your application you can use Dependency Injection mechanism.
Installing and Running
You can start working with AllcountJS in several ways: as a standalone application, as a dependency of another Node.js application or run a demo app at allcountjs.com.
The easiest way to see the result is just to run the application on the demo page
If you consider to deploy application on your site you should install Node.js, MongoDB and Git. Then install AllcountJS CLI by invoking an “npm install” command and perform project init:
npm install -g allcountjs-cli
allcountjs init cusdevcrm-allcount
cd cusdevcrm-allcount
npm install
AllcountJS CLI will ask you to enter some info about your project in order to pre-fill package.json. Next, open app-config/main.js
file in the application directory and replace it’s contents with following piece of code:
A.app({
appName: "CusDev CRM",
appIcon: "phone",
onlyAuthenticated: true,
menuItems: [
{
name: "Contact",
entityTypeId: "Contact",
icon: "user"
}, {
name: "Board",
entityTypeId: "FlowBoard",
icon: "bars"
}, {
name: "Statuses",
entityTypeId: "Status",
icon: "sort"
}
],
entities: function(Fields) {
return {
Contact: {
fields: {
name: Fields.text("Name").required(),
company: Fields.text("Company").required(),
site: Fields.text("Site"),
email: Fields.text("Email"),
skype: Fields.text("Skype"),
phone: Fields.text("Phone"),
lastContactDate: Fields.date('Last contact date'),
status: Fields.fixedReference("Status", "Status")
},
views: {
FlowBoard: {
customView: "board"
}
}
},
Status: {
fields: {
name: Fields.text("Name").required(),
order: Fields.integer("Order").required()
},
sorting: [['order', 1]],
referenceName: "name"
}
}
},
migrations: function (Migrations) { return [
{
name: "statuses",
operation: Migrations.insert("Status", [
{id: "1", name: "Message Sent", order: 1},
{id: "2", name: "Answered", order: 2},
{id: "3", name: "Meeting Approved", order: 3},
{id: "4", name: "Meeting Finished", order: 4},
{id: "5", name: "Rejected", order: 5}
])
},
{
name: "demo-contacts",
operation: Migrations.insert("Contact", [
{id: "1", name: "John Doe", company: "Acme, Inc.", email: "john@acme.com", site: "acme.com", status: {id: "1"}, lastContactDate: "2015-07-18"},
{id: "2", name: "Peter Stone", company: "FooBar LLC", email: "peter@foobar.com", status: {id: "2"}, lastContactDate: "2015-07-17"}
])
}
]}
});
Now let’s take a look at how it works.
General Application Settings
The name and icon of the application are defined with the appName
and appIcon
properties. AllcountJS uses Font Awesome icons. You can select any icon and use it simply by referring to it’s name. When referring to the icon you need to remove fa-
prefix.
appName: "CusDev CRM",
appIcon: "phone",
Authentication setting configured by onlyAuthenticated
property. It declares that only authenticated users may use this application.
onlyAuthenticated: true
There is also a menuItems
property, but we’ll look at it after we define the entities and views.
Contacts and Statuses
Now we’re ready to describe our business entities. They’re defined in the entities
property. Assume that contact will have two mandatory text fields: Name and Company, some text field with contact details, last contact date and current status.
Status field references to the status
entity. Which may have values like “Message Sent”, “Answered”, “Rejected”. Status entity has name
and order
fields.
entities: function(Fields) {
return {
Contact: {
fields: {
name: Fields.text("Name").required(),
company: Fields.text("Company").required(),
site: Fields.text("Site"),
email: Fields.text("Email"),
skype: Fields.text("Skype"),
phone: Fields.text("Phone"),
lastContactDate: Fields.date('Last contact date'),
status: Fields.fixedReference("Status", "Status")
}
},
Status: {
fields: {
name: Fields.text("Name").required(),
order: Fields.integer("Order").required()
},
sorting: [['order', 1]],
referenceName: "name"
}
}
}
Board View
Every entity can have many views
. View in AllcountJS is like SQL view: they doesn’t have special storage in database and you can operate with them like with entities. Most common use case for views is to provide custom behavior, UI and access rights.
In our case we will use views
only to provide specific UI for Contact
. UI template for view or entity is defined in customView
property.
views: {
FlowBoard: {
customView: "board"
}
}
It refers to .jade
file containing template source code. AllcountJS uses jade template engine to generate resulting HTML for web view.
There is a card board template with drag and drop feature in AllcountJS. We will use it with some customizations. So let’s create board.jade
file with this piece of code:
extends project/card-board
block panelBody
.panel-body
h4 {{item.name}}
p {{item.company}}
p {{item.lastContactDate | date}}
Menu
Now it’s time to describe our application menu. There is menuItems
property of the app. It consists of links to application entities.
menuItems: [
{
name: "Contact",
entityTypeId: "Contact",
icon: "user"
}, {
name: "Board",
entityTypeId: "FlowBoard",
icon: "bars"
}, {
name: "Statuses",
entityTypeId: "Status",
icon: "sort"
}
]
REST API
Imagine that you have another application and want to integrate it with your new CRM. It is not a problem, because all application functions could be accessed by the REST API. First you need to get access token. If your CRM app located at https://localhost:9080 than you need to send HTTP POST request to https://localhost:9080/api/sign-in with
{"username": "admin", "password": "admin"}`
in the body. In response you will get token like this:
{"token":"56026b8ad7939dcb552a1668:PSDhU6x_VeIzqPYtIATXzEdMTLE"}
Next let’s try to get all contacts stored inside the CRM. Send HTTP GET request to https://localhost:9080/api/entity/FlowBoard or directly to https://localhost:9080/api/entity/Contact with
X-Access-Token: 56026b8ad7939dcb552a1668:PSDhU6x_VeIzqPYtIATXzEdMTLE
in header. And you will receive all your contacts in JSON. Also you can update, create, delete all your contacts thru API.
Result
We just created simple CRM app based on AllcountJS. As you can see, it was easy and didn’t take too much time:
This example shows a tiny part of possibilities of AllcountJS. Want to know more? Explore our documentation and feel free to ask on gitter.
Published at DZone with permission of Maxim Sorokin. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Fun Is the Glue That Makes Everything Stick, Also the OCP
-
Measuring Service Performance: The Whys and Hows
-
How To Use the Node Docker Official Image
-
Hibernate Get vs. Load
Comments