Skip to content

Commit 1fb78fc

Browse files
committed
Section 3: Serving & Fetching Data From Express
1 parent e317416 commit 1fb78fc

File tree

10 files changed

+1952
-8
lines changed

10 files changed

+1952
-8
lines changed
File renamed without changes.

backend/server.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import express from 'express'
2+
import dotenv from 'dotenv'
3+
import products from './data/products.js'
4+
5+
const app = express()
6+
7+
dotenv.config()
8+
9+
app.get('/', (req, res) => {
10+
res.send('API is running ...')
11+
})
12+
13+
app.get('/api/products', (req, res) => {
14+
res.json(products)
15+
})
16+
17+
app.get('/api/products/:id', (req, res) => {
18+
const product = products.find((p) => p._id === req.params.id)
19+
res.json(product)
20+
})
21+
22+
const PORT = process.env.PORT || 5000
23+
24+
app.listen(
25+
PORT,
26+
console.log(`Server running in ${process.env.NODE_ENV} on port ${PORT}`)
27+
)

frontend/.eslintcache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[{"D:\\fullstack-react\\proshop\\frontend\\src\\index.js":"1","D:\\fullstack-react\\proshop\\frontend\\src\\reportWebVitals.js":"2","D:\\fullstack-react\\proshop\\frontend\\src\\App.js":"3","D:\\fullstack-react\\proshop\\frontend\\src\\components\\Header.js":"4","D:\\fullstack-react\\proshop\\frontend\\src\\components\\Footer.js":"5","D:\\fullstack-react\\proshop\\frontend\\src\\screens\\HomeScreen.js":"6","D:\\fullstack-react\\proshop\\frontend\\src\\products.js":"7","D:\\fullstack-react\\proshop\\frontend\\src\\components\\Product.js":"8","D:\\fullstack-react\\proshop\\frontend\\src\\components\\Rating.js":"9","D:\\fullstack-react\\proshop\\frontend\\src\\screens\\ProductScreen.js":"10"},{"size":529,"mtime":1607255062853,"results":"11","hashOfConfig":"12"},{"size":362,"mtime":499162500000,"results":"13","hashOfConfig":"12"},{"size":644,"mtime":1609777555012,"results":"14","hashOfConfig":"12"},{"size":1072,"mtime":1609778091026,"results":"15","hashOfConfig":"12"},{"size":328,"mtime":1607255607209,"results":"16","hashOfConfig":"12"},{"size":483,"mtime":1609776864088,"results":"17","hashOfConfig":"12"},{"size":2486,"mtime":1607256618887,"results":"18","hashOfConfig":"12"},{"size":886,"mtime":1609777824480,"results":"19","hashOfConfig":"12"},{"size":1801,"mtime":1609776135148,"results":"20","hashOfConfig":"12"},{"size":2165,"mtime":1609779535448,"results":"21","hashOfConfig":"12"},{"filePath":"22","messages":"23","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},"146rpn5",{"filePath":"25","messages":"26","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"27","messages":"28","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"29","messages":"30","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"31","messages":"32","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"33","messages":"34","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"35","messages":"36","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"37","messages":"38","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"39","messages":"40","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"41","messages":"42","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"D:\\fullstack-react\\proshop\\frontend\\src\\index.js",[],["43","44"],"D:\\fullstack-react\\proshop\\frontend\\src\\reportWebVitals.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\App.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\components\\Header.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\components\\Footer.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\screens\\HomeScreen.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\products.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\components\\Product.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\components\\Rating.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\screens\\ProductScreen.js",[],{"ruleId":"45","replacedBy":"46"},{"ruleId":"47","replacedBy":"48"},"no-native-reassign",["49"],"no-negated-in-lhs",["50"],"no-global-assign","no-unsafe-negation"]
1+
[{"D:\\fullstack-react\\proshop\\frontend\\src\\index.js":"1","D:\\fullstack-react\\proshop\\frontend\\src\\reportWebVitals.js":"2","D:\\fullstack-react\\proshop\\frontend\\src\\App.js":"3","D:\\fullstack-react\\proshop\\frontend\\src\\components\\Header.js":"4","D:\\fullstack-react\\proshop\\frontend\\src\\components\\Footer.js":"5","D:\\fullstack-react\\proshop\\frontend\\src\\screens\\HomeScreen.js":"6","D:\\fullstack-react\\proshop\\frontend\\src\\components\\Product.js":"7","D:\\fullstack-react\\proshop\\frontend\\src\\components\\Rating.js":"8","D:\\fullstack-react\\proshop\\frontend\\src\\screens\\ProductScreen.js":"9"},{"size":529,"mtime":1607255062853,"results":"10","hashOfConfig":"11"},{"size":362,"mtime":499162500000,"results":"12","hashOfConfig":"11"},{"size":644,"mtime":1609777555012,"results":"13","hashOfConfig":"11"},{"size":1072,"mtime":1609778091026,"results":"14","hashOfConfig":"11"},{"size":328,"mtime":1607255607209,"results":"15","hashOfConfig":"11"},{"size":737,"mtime":1610813399059,"results":"16","hashOfConfig":"11"},{"size":886,"mtime":1609777824480,"results":"17","hashOfConfig":"11"},{"size":1801,"mtime":1609776135148,"results":"18","hashOfConfig":"11"},{"size":2948,"mtime":1610814709204,"results":"19","hashOfConfig":"11"},{"filePath":"20","messages":"21","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},"146rpn5",{"filePath":"23","messages":"24","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},{"filePath":"25","messages":"26","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},{"filePath":"27","messages":"28","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},{"filePath":"29","messages":"30","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},{"filePath":"31","messages":"32","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},{"filePath":"33","messages":"34","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},{"filePath":"35","messages":"36","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"37"},{"filePath":"38","messages":"39","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},"D:\\fullstack-react\\proshop\\frontend\\src\\index.js",[],["40","41"],"D:\\fullstack-react\\proshop\\frontend\\src\\reportWebVitals.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\App.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\components\\Header.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\components\\Footer.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\screens\\HomeScreen.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\components\\Product.js",[],"D:\\fullstack-react\\proshop\\frontend\\src\\components\\Rating.js",[],["42","43"],"D:\\fullstack-react\\proshop\\frontend\\src\\screens\\ProductScreen.js",[],{"ruleId":"44","replacedBy":"45"},{"ruleId":"46","replacedBy":"47"},{"ruleId":"44","replacedBy":"48"},{"ruleId":"46","replacedBy":"49"},"no-native-reassign",["50"],"no-negated-in-lhs",["51"],["50"],["51"],"no-global-assign","no-unsafe-negation"]

frontend/package-lock.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
{
22
"name": "frontend",
3+
"proxy": "http://127.0.0.1:5000",
34
"version": "0.1.0",
45
"private": true,
56
"dependencies": {
67
"@testing-library/jest-dom": "^5.11.6",
78
"@testing-library/react": "^11.2.2",
89
"@testing-library/user-event": "^12.5.0",
10+
"axios": "^0.21.1",
911
"react": "^17.0.1",
1012
"react-bootstrap": "^1.4.0",
1113
"react-dom": "^17.0.1",

frontend/public/index.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
<meta name="viewport" content="width=device-width, initial-scale=1" />
77
<meta name="theme-color" content="#000000" />
88
<meta name="description" content="Find the best product" />
9-
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
109
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
1110
<link
1211
rel="stylesheet"

frontend/src/screens/HomeScreen.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1-
import React from 'react'
1+
import React, { useState, useEffect } from 'react'
22
import { Row, Col } from 'react-bootstrap'
3-
import products from '../products'
43
import Product from '../components/Product'
4+
import axios from 'axios'
55

66
const HomeScreen = () => {
7+
const [products, setProducts] = useState([])
8+
9+
useEffect(() => {
10+
const fetchProducts = async () => {
11+
const { data } = await axios.get('/api/products')
12+
setProducts(data)
13+
}
14+
15+
fetchProducts()
16+
}, [])
17+
718
return (
819
<>
920
<h1>Latest Products</h1>

frontend/src/screens/ProductScreen.js

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,33 @@
1-
import React from 'react'
1+
import React, { useState, useEffect } from 'react'
22
import { Link } from 'react-router-dom'
33
import { Row, Col, Image, ListGroup, Card, Button } from 'react-bootstrap'
44
import Rating from '../components/Rating'
5-
import products from '../products'
5+
import axios from 'axios'
66

77
const ProductScreen = ({ match }) => {
8-
const product = products.find((p) => p._id === match.params.id)
9-
console.log(product)
8+
// configure component state with the useState hook
9+
// state contains the product object
10+
// setProduct is setter for this object
11+
const [product, setProduct] = useState({})
12+
13+
useEffect(() => {
14+
// configure the fetchProduct method that calls the API
15+
// and fetches the products with a GET request
16+
const fetchProduct = async () => {
17+
// use axios to make the GET request
18+
// match.params is passed via the related react-router route
19+
// with { data } we destructure the axios response's 'data'
20+
const { data } = await axios.get(`/api/products/${match.params.id}`)
21+
22+
// call the setter to set the response data to the state
23+
setProduct(data)
24+
}
25+
26+
// call the method
27+
fetchProduct()
28+
29+
// match has to be added to the dependencies as suggested by the React linter
30+
}, [match])
1031

1132
return (
1233
<>

0 commit comments

Comments
 (0)