Update the ‘start’ script in the package.json file:
123
"scripts":{
"start":"supervisor ./bin/www"
},
Run the app:
1
$ npm start
Then navigate to http://localhost:3000/ in your browser. You should see the "Welcome to Express" text.
Postgres Setup
Need to setup Postgres? On a Mac? Check out Postgres.app.
With your Postgres server up and listening on port 5432, making a database connection is easy with the pg library:
1
$ npm install pg --save
Now let’s set up a simple table creation script:
1234567
varpg=require('pg');
varconnectionString=process.env.DATABASE_URL||
'postgres://localhost:5432/todo'
;
varclient=newpg.Client(connectionString);
client.connect();
varquery=client.query(
'CREATE TABLE items(id SERIAL PRIMARY KEY, text VARCHAR(40) not null, complete BOOLEAN)'
);
query.on('end',function(){client.end();});
Save this as database.js in a new folder called "models".
Here we create a new instance of Client to interact with the database and then establish communication with it via the connect() method. We then set run a SQL query via the query() method. Communication is closed via the end() method. Be sure to check out the documentation for more info.
Make sure you have a database called "todo" setup, and then run the script to setup the table and subsequent fields:
id | integer | not null default nextval('items_id_seq'::regclass) | plain | |
text | character varying(40) | not null | extended | |
complete | boolean | | plain | |
Indexes:
"items_pkey" PRIMARY KEY, btree (id)
With the database connection setup along with the "items" table, we can now configure the CRUD portion of our app.
Server-Side: Routes
Let’s keep it simple by adding all endpoints to the index.js file within the "routes" folder. Make sure to update the imports:
1234
varexpress=require('express');
varrouter=express.Router();
varpg=require('pg');
varconnectionString=process.env.DATABASE_URL||
'postgres://localhost:5432/todo'
;
Now, let’s add each endpoint.
Function
URL
Action
CREATE
/api/v1/todos
Create a single todo
READ
/api/v1/todos
Get all todos
UPDATE
/api/v1/todos/:todo_id
Update a single todo
DELETE
/api/v1/todos/:todo_id
Delete a single todo
Follow along with the inline comments below for an explanation of what’s happening. Also, be sure to check out the pg documentation to learn about connection pooling. How does that differ from pg.Client?
Add a few more rows of data via Curl, and then test the endpoint out in your browser at http://localhost:3000/api/v1/todos. You should see an array of JSON objects:
Before we jump to the client-side to add Angular, be aware that our
code should be refactored to address a few issues. We’ll handle this
later on in this tutorial, but this is an excellent opportunity to
refactor the code on your own. Good luck!
Client-Side: Angular
Let’s dive right in to Angular.
Keep in mind that this is not meant to be an exhaustive tutorial. If
you’re new to Angular I suggest following my "AngularJS by Example"
tutorial - Building a Bitcoin Investment Calculator.
Module
Create a file called app.js in the "public/javascripts" folder. This file will house our Angular module and controller:
$scope.formData={};$scope.todoData={};// Get all todos
$http.get('/api/v1/todos')
.success(function(data){
$scope.todoData=data;
console.log(data);
})
.error(function(error){
console.log('Error: '+error);
});});
Here we define our module as well as the controller. Within the controller we are using the $http service to make an AJAX request to the '/api/v1/todos' endpoint and then updating the scope accordingly.
What else is going on?
Well, we’re injecting the $scope and $http services. Also, we’re defining and updating $scope to handle binding.
Update / Route
Let’s update the main route in index.js within the "routes" folder:
So when the end user hits the main endpoint, we send the index.html file. This file will contain our HTML and Angular templates.
Make sure to add the following dependency as well:
1
varpath=require('path');
View
Now, let’s add our basic Angular view within index.html:
12345678910111213141516171819
ng-app="nodeTodo">
Todo App - with Node + Express + Angular + PostgreSQL
This should all be straightforward. We bootstrap Angular - ng-app="nodeTodo", define the scope of the controller - ng-controller="mainController" - and then use ng-repeat to loop through the todoData object, adding each individual todo to the page.
Module (round two)
Next, let’s update the module to handle the Create and Delete functions:
This uses the ng-click directive to call the deleteTodo() function - which we still need to define - that takes a unique id associated with each todo as an argument.
Module (round three)
Update the controller:
1234567891011
// Delete a todo
$scope.deleteTodo=function(todoID){
$http.delete('/api/v1/todos/'+todoID)
.success(function(data){
$scope.todoData=data;
console.log(data);
})
.error(function(data){
console.log('Error: '+data);
});};
We simply wrapped the delete functionality in the deleteTodo() function. Test this out. Make sure that when you click a check box the todo is removed.
View (round three)
To handle the creation of a new todo, we need to add an HTML form:
1234567891011121314
class="container">
class="form-group">
type="text"class="form-control input-lg"placeholder="Add a todo..."ng-model="formData.text">
How’s that? Not up to par? Continue working on it on your end.
Refactoring (for real)
Now that we added the front-end functionality, let’s update our application’s structure and refactor parts of the code.
Structure
Since our application is logically split between the client
and server, let’s do the same for our project structure. So, make the
following changes to your folder structure:
Next, let’s move the connectionString variable - which specifies the database URI (process.env.DATABASE_URL || 'postgres://localhost:5432/todo';) - to a configuration file since we are reusing the same same connection throughout our application.
Create a file called config.js in the root directory, and then add the following code to it:
123
varconnectionString=process.env.DATABASE_URL||
'postgres://localhost:5432/todo'
;
module.exports=connectionString;
Then update the connectionString variable in both server/models/database.js and server/routes/index.js:
We should abstract that out into a utility function so we're
not duplicating code. Do this on your own, and then post a link to your
code in the comments for review.
Conclusion and next steps
That's it! Now, since there's a number of moving pieces
here, please review how each piece fits into the overall process and
whether each is part of the client or server-side. Comment below with
questions. Grab the code from the repo.
Finally, this app is far from finished. What else do we need to do?
Comments
Post a Comment