Skip to content

Instantly share code, notes, and snippets.

@aaronksaunders
Forked from pixelhandler/app.js
Created February 10, 2012 21:06
Show Gist options
  • Save aaronksaunders/1792878 to your computer and use it in GitHub Desktop.
Save aaronksaunders/1792878 to your computer and use it in GitHub Desktop.
Develop a RESTful API Using Node.js With Express and Mongoose
var application_root = __dirname,
express = require("express"),
path = require("path"),
mongoose = require('mongoose');
var app = express.createServer();
// database
mongoose.connect('mongodb://localhost/ecomm_database');
// config
app.configure(function () {
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(application_root, "public")));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
var Schema = mongoose.Schema; //Schema.ObjectId
// Schemas
var Sizes = new Schema({
size: { type: String, required: true },
available: { type: Number, required: true, min: 0, max: 1000 },
sku: {
type: String,
required: true,
validate: [/[a-zA-Z0-9]/, 'Product sku should only have letters and numbers']
},
price: { type: Number, required: true, min: 0 }
});
var Images = new Schema({
kind: {
type: String,
enum: ['thumbnail', 'catalog', 'detail', 'zoom'],
required: true
},
url: { type: String, required: true }
});
var Variants = new Schema({
color: String,
images: [Images],
sizes: [Sizes]
});
var Categories = new Schema({
name: String
});
var Catalogs = new Schema({
name: String
});
// Product Model
var Product = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
style: { type: String, unique: true },
images: [Images],
categories: [Categories],
catalogs: [Catalogs],
variants: [Variants],
modified: { type: Date, default: Date.now }
});
// validation
Product.path('title').validate(function (v) {
console.log("validate title");
console.log(v);
return v.length > 10 && v.length < 70;
});
Product.path('style').validate(function (v) {
console.log("validate style");
console.log(v);
return v.length < 40;
}, 'Product style attribute is should be less than 40 characters');
Product.path('description').validate(function (v) {
console.log("validate description");
console.log(v);
return v.length > 10;
}, 'Product description should be more than 10 characters');
var ProductModel = mongoose.model('Product', Product);
/* Product Document
[
{
"title": "My Awesome T-shirt",
"description": "All about the details. Of course it's black.",
"images": [
{
"kind": "thumbnail",
"url": "images/products/1234/main.jpg"
}
],
"categories": [
{ "name": "Clothes" },
{ "name": "Shirts" }
],
"style": "1234",
"variants": [
{
"color": "Black",
"images": [
{
"kind": "thumbnail",
"url": "images/products/1234/thumbnail.jpg"
},
{
"kind": "catalog",
"url": "images/products/1234/black.jpg"
}
],
"sizes": [
{
"size": "S",
"available": 10,
"sku": "CAT-1234-Blk-S",
"price": 99.99
},
{
"size": "M",
"available": 7,
"sku": "CAT-1234-Blk-M",
"price": 109.99
}
]
}
],
"catalogs": [
{ "name": "Apparel" }
]
}
]
*/
// REST api
app.get('/api', function (req, res) {
res.send('Ecomm API is running');
});
// POST to CREATE
app.post('/api/products', function (req, res) {
var product;
console.log("POST: ");
console.log(req.body);
product = new ProductModel({
title: req.body.title,
description: req.body.description,
style: req.body.style,
images: req.body.images,
categories: req.body.categories,
catalogs: req.body.catalogs,
variants: req.body.variants
});
product.save(function (err) {
if (!err) {
return console.log("created");
} else {
return console.log(err);
}
});
return res.send(product);
});
// PUT to UPDATE
app.put('/api/products/:id', function (req, res) {
return ProductModel.findById(req.params.id, function (err, product) {
product.title = req.body.title;
product.description = req.body.description;
product.style = req.body.style;
product.images = req.body.images;
product.categories = req.body.categories;
product.catalogs = req.body.catalogs;
product.variants = req.body.variants;
return product.save(function (err) {
if (!err) {
console.log("updated");
} else {
console.log(err);
}
return res.send(product);
});
});
});
// GET to READ
app.get('/api/products', function (req, res) {
return ProductModel.find(function (err, products) {
if (!err) {
return res.send(products);
} else {
return console.log(err);
}
});
});
app.get('/api/products/:id', function (req, res) {
return ProductModel.findById(req.params.id, function (err, product) {
if (!err) {
return res.send(product);
} else {
return console.log(err);
}
});
});
// DELETE to DESTROY
app.delete('/api/products/:id', function (req, res) {
return ProductModel.findById(req.params.id, function (err, product) {
return product.remove(function (err) {
if (!err) {
console.log("removed");
return res.send('');
} else {
console.log(err);
}
});
});
});
// launch server
app.listen(4242);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>API index</title>
</head>
<body>
<section>
<h1>Nouns...</h1>
<p>
/products<br>
/products/:id
</p>
</section>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
</body>
</html>
// jQuery snippets used in the console to use the REST api created with app.js
// CREATE
jQuery.post("/api/products", {
"title": "My Awesome T-shirt",
"description": "All about the details. Of course it's black.",
"images": [
{
"kind": "thumbnail",
"url": "images/products/1234/main.jpg"
}
],
"categories": [
{ "name": "Clothes" },
{ "name": "Shirts" }
],
"style": "1234",
"variants": [
{
"color": "Black",
"images": [
{
"kind": "thumbnail",
"url": "images/products/1234/thumbnail.jpg"
},
{
"kind": "catalog",
"url": "images/products/1234/black.jpg"
}
],
"sizes": [
{
"size": "S",
"available": 10,
"sku": "CAT-1234-Blk-S",
"price": 99.99
},
{
"size": "M",
"available": 7,
"sku": "CAT-1234-Blk-M",
"price": 109.99
}
]
}
],
"catalogs": [
{ "name": "Apparel" }
]
}, function(data, textStatus, jqXHR) {
console.log("Post resposne:"); console.dir(data); console.log(textStatus); console.dir(jqXHR);
});
// generated a product document with automatically assigned ID, e.g. 4f34734d21289c1c28000007
// READ
jQuery.get("/api/products/", function(data, textStatus, jqXHR) {
console.log("Post resposne:");
console.dir(data);
console.log(textStatus);
console.dir(jqXHR);
});
jQuery.get("/api/products/4f34734d21289c1c28000007", function(data, textStatus, jqXHR) {
console.log("Post resposne:");
console.dir(data);
console.log(textStatus);
console.dir(jqXHR);
});
// UPDATE
jQuery.ajax({
url: "/api/products/4f34734d21289c1c28000007",
type: "PUT",
data: {
"title": "My Awesome T-shirt",
"description": "All about the details. Of course it's black, and longsleeve.",
"images": [
{
"kind": "thumbnail",
"url": "images/products/1234/main.jpg"
}
],
"categories": [
{ "name": "Clothes" },
{ "name": "Shirts" }
],
"style": "1234",
"variants": [
{
"color": "Black",
"images": [
{
"kind": "zoom",
"url": "images/products/1234/zoom.jpg"
}
],
"sizes": [
{
"size": "L",
"available": 77,
"sku": "CAT-1234-Blk-L",
"price": 99.99
}
]
}
],
"catalogs": [
{ "name": "Apparel" }
]
},
success: function(data, textStatus, jqXHR) {
console.log("PUT resposne:");
console.dir(data);
console.log(textStatus);
console.dir(jqXHR);
}
});
// Delete
jQuery.ajax({url: "/api/products/4f34734d21289c1c28000007", type: "DELETE", success: function(data, textStatus, jqXHR) { console.dir(data); }});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment