Skip to content

Commit a99e84f

Browse files
committed
added API example
1 parent d957171 commit a99e84f

7 files changed

Lines changed: 211 additions & 3 deletions

File tree

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,19 @@ Note that the application is using two environment variables to be able to deplo
156156

157157
* `process.env.PORT`
158158
* `process.env.DATABASE_URL`
159+
160+
## API basics
161+
162+
Look at the `products-api.js` file in the `api` folder to see how to create an simple API. And API endpoint returns JSON to the client using the HttpResponse Objects `json` method.
163+
164+
```javascript
165+
res.json({
166+
result: 'success'
167+
})
168+
```
169+
170+
The API end point is running at http://localhost:3000/api/products.
171+
172+
The `client.js` file in the public folder is using the API. It calls the API and renders the resulting JSON data to the screen using HandlebarsJS.
173+
174+
Go to http://localhost:3000/client.html to see the screen using the API in action. It uses [axios](https://github.com/axios/axios) to call the API endpoints using HTTP.

api/products-api.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
module.exports = function(productService) {
2+
3+
async function all(req, res) {
4+
try {
5+
let results = await productService.all();
6+
7+
res.json({
8+
status: 'success',
9+
data: results
10+
})
11+
}
12+
catch (err) {
13+
next(err);
14+
}
15+
};
16+
17+
async function add(req, res) {
18+
19+
try {
20+
await productService.create({
21+
category_id: Number(req.body.category_id),
22+
description : req.body.description,
23+
price: Number(req.body.price)
24+
});
25+
26+
res.json({
27+
status: "success",
28+
});
29+
}
30+
catch (err) {
31+
res.json({
32+
status: "error",
33+
error: err.stack
34+
});
35+
}
36+
};
37+
38+
async function get(req, res) {
39+
try {
40+
let id = req.params.id;
41+
let product = await productService.get(id);
42+
res.json({
43+
status: "success",
44+
data: product
45+
});
46+
}
47+
catch (err) {
48+
res.json({
49+
status: "error",
50+
error: err.stack
51+
});
52+
}
53+
};
54+
55+
async function update(req, res, next) {
56+
try{
57+
await productService.update({
58+
category_id: Number(req.body.category_id),
59+
description: req.body.description,
60+
price: Number(req.body.price),
61+
id: req.params.id
62+
});
63+
res.json({
64+
status: "success"
65+
});
66+
}
67+
catch(err){
68+
res.json({
69+
status: "error",
70+
error: err.stack
71+
});
72+
}
73+
};
74+
75+
async function deleteProduct (req, res, next) {
76+
try{
77+
var id = req.params.id;
78+
await productService.delete(id);
79+
res.json({
80+
status: "success"
81+
});
82+
}
83+
catch(err){
84+
res.json({
85+
status: "error",
86+
error: err.stack
87+
});
88+
}
89+
};
90+
91+
return {
92+
all,
93+
add,
94+
get,
95+
delete : deleteProduct,
96+
update
97+
}
98+
}

index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const exphbs = require('express-handlebars');
55
const bodyParser = require('body-parser');
66
const Categories = require('./routes/categories');
77
const Products = require('./routes/products');
8+
const ProductsAPI = require('./api/products-api');
9+
810
const app = express();
911
const session = require('express-session');
1012
const flash = require('express-flash');
@@ -31,6 +33,7 @@ const categoryService = CategoryService(pool);
3133
const productService = ProductService(pool);
3234
const categoryRoutes = Categories(categoryService);
3335
const productRoutes = Products(productService, categoryService);
36+
const productsAPI = ProductsAPI(productService);
3437

3538
app.use(session({
3639
secret: 'keyboard cat',
@@ -76,6 +79,8 @@ app.post('/products/add', productRoutes.add);
7679
//this should be a post but this is only an illustration of CRUD - not on good practices
7780
app.get('/products/delete/:id', productRoutes.delete);
7881

82+
app.get('/api/products', productsAPI.all);
83+
7984
app.use(errorHandler);
8085

8186
//configure the port number using and environment number

public/client.html

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
7+
<title>Document</title>
8+
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script>
9+
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.12/handlebars.js"></script>
10+
<link rel="stylesheet" href="/style.css">
11+
12+
<script type="text/x-template" class="productListTemplate">
13+
<table>
14+
<tr>
15+
<th>Product name</th>
16+
<th>Category name</th>
17+
<th>Price</th>
18+
</tr>
19+
{{#each productList}}
20+
<tr>
21+
<td>{{description}}</td>
22+
<td>{{category_description}}</td>
23+
<td>{{price}}</td>
24+
</tr>
25+
{{/each}}
26+
</table>
27+
</script>
28+
29+
</head>
30+
<body>
31+
<div id="container">
32+
<h1>Products via API</h1>
33+
<div class="products">
34+
35+
</div>
36+
</div>
37+
</body>
38+
<script src="client.js"></script>
39+
</html>

public/client.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
document.addEventListener('DOMContentLoaded', function() {
2+
3+
let productListTemplate = document.querySelector('.productListTemplate');
4+
let productListTemplateInstance = Handlebars.compile(productListTemplate.innerHTML);
5+
let productsElem = document.querySelector('.products');
6+
7+
// Client side Factory function
8+
let productService = ProductService();
9+
10+
productService
11+
.getProducts()
12+
.then(function(results){
13+
let response = results.data;
14+
let data = response.data;
15+
// console.log(data);
16+
let productTableHTML = productListTemplateInstance({
17+
productList : data
18+
});
19+
productsElem.innerHTML = productTableHTML;
20+
});
21+
});
22+
23+
24+
function ProductService() {
25+
function getProducts(){
26+
return axios.get('/api/products')
27+
}
28+
29+
return {
30+
getProducts
31+
}
32+
}

public/style.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,17 @@ input[type=submit] {
8989
margin-top : 1.0em;
9090
font-weight: bold;
9191
}
92+
93+
table, td, th {
94+
border: 1px solid #ddd;
95+
text-align: left;
96+
}
97+
98+
table {
99+
border-collapse: collapse;
100+
width: 80%;
101+
}
102+
103+
th, td {
104+
padding: 15px;
105+
}

services/product-service.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module.exports = function ProductService(pool){
22
async function all(){
3-
const query = `select p.id, p.description, p.price, c.description as category_description from products p
3+
const query = `select p.id, p.description, p.price, c.id as category_id,
4+
c.description as category_description from products p
45
join categories c on c.id = p.category_id`;
56
let results = await pool.query(query);
67
return results.rows;
@@ -29,8 +30,11 @@ module.exports = function ProductService(pool){
2930
product.id
3031
];
3132

32-
let updateQuery = `UPDATE products SET category_id = $1,
33-
description = $2, price = $3 WHERE id = $4`;
33+
let updateQuery = `UPDATE products
34+
SET category_id = $1,
35+
description = $2,
36+
price = $3
37+
WHERE id = $4`;
3438

3539
return pool.query(updateQuery, data);
3640
}

0 commit comments

Comments
 (0)