Skip to content

Commit 45e709b

Browse files
committed
Basic setup
1 parent 3256aa9 commit 45e709b

30 files changed

+3777
-196
lines changed

README.md

+281
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
# MEAN Skeleton
2+
This repo is a basic structure for a web application that uses the MEAN stack (MongoDB, Express, AngularJS, and NodeJS). It is made for beginners with a basic understanding of these technologies. If there are any questions, feel free to create a New Issue on the repository.
3+
4+
## Setup
5+
6+
#### Node
7+
To get this running locally, start by installing [**NodeJS**](http://nodejs.org/download/). The Node website is very good at explaining how to do this. Once installed verify that npm (Node Package Manager) came with the installation by running npm in Terminal.
8+
9+
#### Nodemon
10+
I recommend installing [Nodemon](https://github.com/remy/nodemon) to assist you in development. It will watch for changes in your server files and automatically restart the server for you. That way you can stick to developing rather than constantly restarting the process manually.
11+
12+
#### Mongo
13+
Next, download and install [**MongoDB**](http://www.mongodb.org/downloads). **Make sure to follow all the directions for installing on your respective operating system.** Verify that this is installed correctly by running the mongo server locally with the command ```mongod```. The mongod service must be running locally to point to local Mongo databases.
14+
15+
16+
## Configure
17+
Clone the repository, and you will have the structure in place to start. Begin by editting the package.json file.
18+
19+
#### Package.json
20+
```javascript
21+
// package.json
22+
{
23+
"name" : "mean-skeleton",
24+
"version" : "0.0.1",
25+
"description" : "Skeleton for an application using the MEAN stack.",
26+
"main" : "server.js",
27+
"author" : "Alfred",
28+
"dependencies" : {
29+
"express" : "latest",
30+
"mongoose" : "latest"
31+
}
32+
}
33+
```
34+
35+
**Don't forget to change**
36+
* Name
37+
* Version, if applicable
38+
* Description
39+
* Author
40+
41+
Install all listed dependencies by navigating to the repository in Terminal and running the command
42+
43+
```npm install```
44+
45+
This will install [**Express**](http://expressjs.com/4x/api.html) along with the other packages in the package.json file.
46+
47+
In the above, "latest" denotes version number. It's a string. I set it to latest to simplify use. I am also assuming that these package owners will continue to document their changes as they update their packages. Luckily [**StrongLoop**](http://strongloop.com/) is pretty good about it.
48+
49+
<Enter>
50+
<Enter>
51+
<Enter>
52+
53+
#### Connecting to a Database
54+
Replace the link below with the url for your hosted DB or keep this url for the default local MongoDB
55+
```javascript
56+
// config/db.js
57+
module.exports = {
58+
url : 'mongodb://localhost:27017/test'
59+
}
60+
```
61+
62+
#### Server Settings
63+
Right now we have a few moving parts, but they aren't connected yet. Let's change that.
64+
65+
In the root of our project you'll find a server.js file. This is the file that we will run to make our server live.
66+
67+
First, we require our dependencies. You'll notice I declare bodyParser, which is an Express middleware for parsing HTTP Responses and Requests. I also declare morgan, another Express middleware, used for logging.
68+
69+
I suggest reading up on them and other Express middlewares, but the settings I have here should work for this example.
70+
71+
```javascript
72+
// server.js
73+
74+
// Dependencies
75+
var express = require('express');
76+
var mongoose = require('mongoose');
77+
var bodyParser = require('body-parser');
78+
var morgan = require('morgan');
79+
```
80+
81+
Next, we configure our Express application. I import the database file to this one in an effort to keep the database file nice and lean.
82+
```javascript
83+
// server.js
84+
85+
// Configs
86+
var db = require('./config/db');
87+
88+
// Connect to the DB
89+
mongoose.connect(db.url);
90+
91+
// Initialize Express app
92+
var app = express();
93+
// Configure
94+
95+
// To expose public assets to the world
96+
app.use(express.static(__dirname + '/public'));
97+
98+
// log every request to the console
99+
app.use(morgan('dev'));
100+
101+
// For parsing HTTP responses
102+
app.use(bodyParser.json());
103+
app.use(bodyParser.urlencoded({
104+
extended: true
105+
}));
106+
```
107+
108+
After configuring, we add the routes by sending the application as a parameter to the require statements.
109+
110+
Lastly, start the application with listen by giving it a port number.
111+
```javascript
112+
// server.js
113+
114+
// Express Routes
115+
require('./app/routes/api')(app);
116+
require('./app/routes/routes')(app);
117+
118+
// Start the app with listen
119+
app.listen(3000);
120+
121+
```
122+
123+
#### Run our server
124+
To run this server, in the root of the project directory run
125+
126+
```node server.js``` or if using nodemon ```nodemon server.js```
127+
128+
It will start the application and you should be able to navigate to http://localhost:3000 and see our first page.
129+
130+
## Make It Yours
131+
### Defining a Model
132+
This application is designed to implement the MV* pattern. Thus, start by creating a Model for our data.
133+
134+
Each model should be defined in its own file in the app/models directory.
135+
136+
```javascript
137+
// app/models/user.js
138+
139+
var mongoose = require('mongoose'),
140+
Schema = mongoose.Schema;
141+
142+
var UserSchema = new Schema ({
143+
name : {
144+
type: String
145+
},
146+
});
147+
148+
module.exports = mongoose.model('User', UserSchema);
149+
```
150+
151+
The above is an example of a User model with a name field. We require [mongoose](http://mongoosejs.com/index.html) as our Object Modeler and then require Mongoose Schema as an object to extend and create our own Schema.
152+
153+
Then define the fields of your model. You can set the datatype, mark fields as required and validate the data before saving the document to the collection. Read more about mongoose schemas in their [docs](http://mongoosejs.com/docs/guide.html)
154+
155+
Lastly, you are going to want to export the model with a name and a Schema Object for use in our API.
156+
157+
### Defining Routes
158+
These are Express-style routes, to see all the fancy things you can do refer to the Express docs.
159+
160+
To define a simple route to serve a static HTML page:
161+
```javascript
162+
// app/routes/route.js
163+
module.exports = function(app) {
164+
app.get('/path', function(request, response) {
165+
response.sendfile('path/to.html');
166+
});
167+
}
168+
```
169+
170+
To define a route that writes to the response:
171+
```javascript
172+
// Assuming this is wrapped in the export line
173+
app.get('/path', function(request, response) {
174+
response.writeHead(200); // 200 Success Status code
175+
response.write(<h1>Hello World</h1>); // Writes to the body
176+
response.end(); // Closes the write stream
177+
});
178+
```
179+
180+
#### Defining an API
181+
Since making RESTful applications makes everything easy on everyone, let's define a way to interact with our model
182+
183+
To make a call that returns our models:
184+
```javascript
185+
/* app/routes/api.js */
186+
187+
module.exports = function(app) {
188+
/* Require mongoose, and the Model */
189+
var mongoose = require('mongoose'),
190+
Model = require('app/models/model')
191+
192+
app.get('path', function(request, response) {
193+
Model.find({conditions : 'in JSON'}, function(err, models) {
194+
response.send(models); // Sends the data in JSON in the response
195+
});
196+
});
197+
}
198+
```
199+
200+
Express also supports the other HTTP verbs like POST.
201+
To create a model and return them all after one is created.
202+
```javascript
203+
// Assuming this is wrapped in the export after the require lines
204+
205+
app.post('path', function (req, res) {
206+
Model.create({
207+
name : req.body.name // Value from form with field "name"
208+
}, function(err, model) {
209+
210+
Model.find(function(err, models) {
211+
res.send(models);
212+
});
213+
});
214+
});
215+
```
216+
217+
So far we have set up quite the backend, and gone over the M, E, and N in MEAN. Now we can finally start **A**.
218+
219+
## Make It Pretty
220+
We use [AngularJS](https://angularjs.org/) to receive all of the data sent from Node in the backend to give us a truly dynamic webpage it also offers us many directives to display this data on the frontend.
221+
222+
### Define an Angular Controller
223+
Angular follows the MVC pattern on the frontend. We won't have to really do anything to the model once it gets to Angular so, next up is the Controller. We define Angular controllers and export them as angular modules.
224+
225+
[Angular Services](https://docs.angularjs.org/api/ng/service)
226+
227+
To add more functionality to our controller, we can throw in more angular services as arguments after ```$scope```
228+
229+
I recommend adding the ```$http``` service to make frontend wrappers for our API calls.
230+
```javascript
231+
var appController = angular.module('appController', []);
232+
233+
function appCtrl($scope, $http) {
234+
...
235+
}
236+
```
237+
238+
[Angular Directives](https://docs.angularjs.org/api/ng/directive)
239+
240+
To use what we have defined in our controller, we use the ng-app directive to point to the controller for this page. We must also be sure to load angular and the controller.js file.
241+
242+
Lastly, add the ng-controller directive to the body of the document to make all of the controller methods available to the body.
243+
244+
245+
```html
246+
<!DOCTYPE html>
247+
<html ng-app="appController">
248+
<head>
249+
<!-- Angular from Google CDN -->
250+
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
251+
252+
<!-- Load AppController -->
253+
<script type="text/javascript" src="../controllers/app.js"></script>
254+
</head>
255+
<body ng-controller="appCtrl">
256+
257+
</body>
258+
</html>
259+
```
260+
261+
## Testing Your Application
262+
Making sure that our application works is an incredibly important part of developing for any platform. The entire software stack in this instance is JavaScript. This means we only need JavaScript testing libraries.
263+
264+
#### Testing Angular
265+
[Jasmine](http://jasmine.github.io/) is recommended for testing your frontend JavaScripts. If you are unfamiliar with jasmine check out the tutorial [here](http://jasmine.github.io/2.0/introduction.html)
266+
267+
You can find a very basic angular controller spec in the ``test-angular/spec/`` directory.
268+
269+
#### Testing Node
270+
[jasmine-node](https://github.com/mhevery/jasmine-node) is jasmine for your Node backend. Their documentation is brief because they assume that you are familiar with running jasmine already.
271+
272+
Install the package globally and it comes with a CLI.
273+
274+
To run Node tests:
275+
276+
```jasmine-node test-node/```
277+
278+
This will recursively run all the files named *spec.js, which means all of your specs must end with spec.js
279+
280+
## Disclaimer
281+
I do not claim to be an expert at any of the technologies used. I also do not claim to own any of the technologies mentioned in this guide.

app.js

-48
This file was deleted.

app/.DS_Store

6 KB
Binary file not shown.

app/models/model.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
var mongoose = require('mongoose'),
2+
Schema = mongoose.Schema;
3+
4+
// Validation helper methods should return booleans
5+
// and should be defined before the schema for readability
6+
7+
8+
// Model Schema
9+
var ModelSchema = new Schema ({
10+
name : {
11+
type: String
12+
},
13+
});
14+
15+
module.exports = mongoose.model('Model', ModelSchema);

app/routes/api.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Module for API Routes (serving JSON)
2+
module.exports = function(app) {
3+
var mongoose = require('mongoose'),
4+
Model = require('../models/model')
5+
6+
// Example API route
7+
app.get('/models', function(req, res) {
8+
9+
// Checks the model collection and returns all of them`
10+
Model.find(function(err, models) {
11+
12+
// returns all people in JSON format
13+
res.send(models);
14+
});
15+
});
16+
17+
// Example POST route
18+
app.post('/models', function (req, res) {
19+
Model.create({
20+
name : req.body.name // Bound using Angular
21+
}, function(err, model) {
22+
if(err) {
23+
res.send(err);
24+
}
25+
26+
Model.find(function(err, models) {
27+
res.send(models);
28+
});
29+
});
30+
});
31+
32+
// Example DELETE route
33+
app.delete('/models/:model_id', function (req, res) {
34+
Model.remove({
35+
_id: req.params.model_id
36+
}, function(err, model) {
37+
if(err) {
38+
res.send(err);
39+
}
40+
41+
Model.find(function(err, models) {
42+
res.send(models);
43+
});
44+
});
45+
});
46+
}

0 commit comments

Comments
 (0)