diff --git a/projects/eventonica-react/README.md b/project-example/week-9/eventonica/README.md similarity index 100% rename from projects/eventonica-react/README.md rename to project-example/week-9/eventonica/README.md diff --git a/projects/eventonica-react/eventonica-express-backend.md b/project-example/week-9/eventonica/eventonica-express-backend.md similarity index 52% rename from projects/eventonica-react/eventonica-express-backend.md rename to project-example/week-9/eventonica/eventonica-express-backend.md index 172e985ef..791f23b96 100644 --- a/projects/eventonica-react/eventonica-express-backend.md +++ b/project-example/week-9/eventonica/eventonica-express-backend.md @@ -6,7 +6,7 @@ Up until now in your Eventonica project, all the data is deleted every time you #### Example API Endpoint -For example, in your code before, to get all the events, you might've had a function like `app.getAllEvents()`. Instead, we will create an API endpoint like `http://127.0.0.1:3000/events` that returns all the current events as a JSON response. +For example, in your code before, to get all the events, you might've had a function like `app.getAllEvents()`. Instead, we will create an API endpoint like `http://127.0.0.1:4000/events` that returns all the current events as a JSON response. #### Why is this better? @@ -24,147 +24,184 @@ The following directions are an adaptation of [this freeCodeCamp tutorial](https #### Create a new Express App -1. In your terminal, navigate to your `eventonica-react` project. Start it with `npm start`. +1. In your terminal, navigate to your `eventonica-react` project i.e `client` directory . Start it with `npm start`. -1. You will need to create a second app for your Express backend. In a second terminal window, navigate to your general Techtonica project folder. Follow these commands to create a new project called `eventonica-api` and start it. If it asks you if you want to download `express-generator`, choose `yes`. - ``` - npx express-generator eventonica-api - cd eventonica-api - npm install - npm start - ``` +1. You will need to create a second app for your Express backend. In a second terminal window, navigate to your general `Eventonica` project folder. Follow these commands to create a new project called `server` and start it. If it asks you if you want to download `express-generator`, choose `yes`. -1. Did you get a message that says?: - ``` - ? Something is already running on port 3000. Probably: - node ./bin/www (pid 13314) - in /Users/al/projects/eventonica-api + ``` + npx express-generator server + cd server + npm install + ``` - Would you like to run the app on another port instead? › (Y/n) - ``` - Each app needs its own port if we want to run them on the same machine! +> If you see warning on your terminal like +> `npm WARN deprecated transformers@2.1.0: Deprecated, use jstransformer
npm WARN deprecated constantinople@3.0.2: Please update to at least constantinople 3.1.1
npm WARN deprecated jade@1.11.0: Jade has been renamed to pug, please install the latest version of pug instead of jade` -1. To solve this problem, let's change the port for your frontend app. In `eventonica-react/package.json`, find the start script that says ` "start": "react-scripts start",`. Change it to now say: - `"start": "PORT=8888 react-scripts start",` - Now start your eventonica-react project again. Go to `http://localhost:8888/` and you should see your app running on its new port. +> You need to follow this instructions +> +> > - In package.json remove Jade +> > - Install Pug (Jade has been renamed to pug) `npm install pug` +> > - Run `npm install` again +> > - In **server/app.js** changes `app.set('view engine', 'jade');` to `app.set('view engine', 'pug');` +> > - In **views** folder rename all jade file to pug. Ex: index.jade -> index.pug +> > - Run `npm audit` to check for any vulnerabilities again -1. To be thorough, you should also search your `eventonica-react` project and make sure you've replaced references to port 3000. I had to change `http://localhost:3000` in the README.md to `http://localhost:8888` in a few spots. +1. Inside the **server** directory, go to **bin/www** and change the port number on line 15 from 3000 to 4000. You will be running both apps at the same time later on, so doing this will avoid issues. -1. In your second window, you should now be able to start `eventonica-api` on port 3000 without any problems. Open a browser window and go to `http://localhost:3000/`. If it's working, you should see a welcome message! +```js +// server/bin/www -1. Open `eventonica-api/routes/index.js` and find line 6 that says: - ``` - res.render('index', { title: 'Express' }); - ``` - Change the title so it says this instead: - ``` - res.render('index', { title: 'Our express app is working properly' }); - ``` +var port = normalizePort(process.env.PORT || '4000'); +app.set('port', port); +``` -1. Stop your `eventonica-api` app and restart. `http://localhost:3000` should now show your new message. +1. In your second window, you should now be able to start `server` on port 4000 without any problems using the command `npm start`. Open a browser window and go to [http://localhost:4000/](http://localhost:4000/). If it's working, you should see a welcome message! -1. `.gitignore` your `node_modules`. Push your project up to GitHub by creating a new repo there also called `eventonica-api`. Follow the directions on the page that include the first commit, etc. +1. Open `server/routes/index.js` and find line 6 that says: + + ```js + res.render('index', { title: 'Express' }); + ``` + + Change the title so it says this instead: + + ```js + res.render('index', { title: 'Our express app is working properly' }); + ``` + +1. Stop your `server` app and restart. `http://localhost:4000` should now show your new message. + +1. `.gitignore` your `node_modules`. Push your project up to GitHub. #### Create a new Events route -1. Duplicate your `eventonica-api/routes/index.js` file and name it `eventonica-api/routes/events.js`. In this new file, change line 6 to say: - ``` - res.render('index', { title: 'This is my events route.' }); - ``` +1. Duplicate your `server/routes/index.js` file and name it `server/routes/events.js`. In this new file, change line 6 to say: -1. In `eventonica-api/app.js`, add this to line 25: `app.use("/events", eventsRouter);` You'll need to define `eventsRouter`, so add this to line 9: `var eventsRouter = require("./routes/events");` + ```js + res.render('index', { title: 'This is my events route.' }); + ``` -1. Stop your `eventonica-api` app and restart. `http://localhost:3000/events` should now show your new message: 'This is my events route.' You just made a new route! +1. In `server/app.js`, add this to line 25: `app.use("/events", eventsRouter);` You'll need to define `eventsRouter`, so add this to line 9: `var eventsRouter = require("./routes/events");` -> Note: Obviously, any other app calling `http://localhost:3000/events` would be doing it to get data, not to get a visual web page, but it's nice to have proof that things are working so far. Thanks [express-generator](http://expressjs.com/en/starter/generator.html)! +1. Stop your `server` app and restart. `http://localhost:4000/events` should now show your new message: **This is my events route.** You just made a new route! + +> Note: Obviously, any other app calling `http://localhost:4000/events` would be doing it to get data, not to get a visual web page, but it's nice to have proof that things are working so far. Thanks [express-generator](http://expressjs.com/en/starter/generator.html)! #### Returning data in the Users endpoint -1. Copy your list of mock users to the to of `users.js` into an array called `users`. + +1. Copy your list of mock users from your client/src/components/Users.js file to the `server/routes/users.js` into an array called `users`. + +```js +let mockUsers = [ + { id: 1, name: 'Marlin', email: 'marlin@gmail.com' }, + { id: 2, name: 'Nemo', email: 'nemo@gmail.com' }, + { id: 3, name: 'Dory', email: 'dory@gmail.com' } +]; +``` 2. Update the endpoint so it returns `res.json({users:[your mock users here]});` -**Check** Review the difference between `res.json` and `res.send`. Typically front-end apps to expect to receive responses as a JSON. -Restart your server. Do you see the events list at `http://localhost:3000/users`? +```js +// server/routes/users.js` +router.get('/', function (req, res, next) { + console.log(req.body, 'the body'); + res.json({ users: mockUsers }); +}); +``` + +**Check** Review the difference between `res.json` and `res.send`. Typically front-end apps to expect to receive responses as a JSON. + +Restart your server. Do you see the users list at `http://localhost:4000/users`? **What shape should the response object be?** The example response returns `{ users: [array of users] }` instead of just `res.json(users)`. This is because naming the user object `users` is a more clear way of presenting this information. Also, this endpoint could send other information in addition to the user array. For example, it is common to have pagination in GET endpoints. So the response could eventually be something like `res.json( { users:[user array], pagination: {pageSize: 10, page: 1 } });` + #### Testing in Postman -Testing in Postman (or a similar app) is a great way to test and understand your backend services. While you can test the URLs in Chrome, or test your endpoints by calling them in React, they offer less flexibility, and/or might have less context into the endpoint's behavior and errors. + +Testing in Postman (or a similar app) is a great way to test and understand your backend services. While you can test the URLs in Chrome, or test your endpoints by calling them in React, they offer less flexibility, and/or might have less context into the endpoint's behavior and errors. 1. Testing the endpoint -Open Postman, and open a new tab called "Eventonica". "GET" should be automatically selected in the dropdown. Enter `http://localhost:3000/users` into the request URL and press send. You should see the same list of users in the response below. + Open Postman, and open a new tab called "Eventonica". "GET" should be automatically selected in the dropdown. Enter `http://localhost:4000/users` into the request URL and press send. You should see the same list of users in the response below. 2. Testing sending information -Now the get users endpoint always returns all users. However, in the future we might want filtering. + Now the get users endpoint always returns all users. However, in the future we might want filtering. To test this, you can console log `console.log(req.body, 'the body')` before the `res.json` line. In Postman, now try adding a body. Click the "body" tab and select "raw". Then select "JSON" from the dropdown. Try sending a JSON of something that the API might send. For example, it could send `{"name": "nemo"}` for when you implement filtering. If you added the console log, do you see this information printed in your express server terminal? (Note that console logs will not show up in Postman). #### Access your API from your React app -1. Back in your frontend, open `eventonica-react/src/Users.js`. Add this code to be the next line right after `const Users = () => {` so that it is inside your React code block: - ``` +1. Back in your frontend, open `client/src/Users.js`. Add this code to be the next line right after `const Users = () => {` so that it is inside your React code block: + + ```jsx const [users, setUsers] = useState([]); - console.log("users", users) + console.log('users', users); const getUsers = () => { - fetch("http://localhost:3000/users") - .then(res => res.json()) - .then(res => setUsers(res.users)) + fetch('http://localhost:4000/users') + .then((res) => res.json()) + .then((res) => setUsers(res.users)); }; useEffect(() => { - getUsers(); // useEffect will run getUsers() every time this component loads, as opposed to just the first time it is rendered. + // useEffect will run getUsers() every time this component loads, as opposed to just the first time it is rendered. + getUsers(); }, []); ``` -**Check** -Why do we set `setUsers(res.users)` instead of `setUsers(res)`? Remember that `res` is an object with a key `users`, but it could also have other information. Try to keep states as specific as possible. ie if the `res` response did have other information such as pagination, we want to keep the `users` state as "specific" as possible, so that it only stores the users array part of the API response. -1. If you look at http://localhost:8888/ or your terminal, it will probably say that `useState` and `useEffect` are not defined. You should import these React hooks from React like this on line 1: - ``` - import React, {useEffect, useState} from 'react'; + **Check** + Why do we set `setUsers(res.users)` instead of `setUsers(res)`? Remember that `res` is an object with a key `users`, but it could also have other information. Try to keep states as specific as possible. ie if the `res` response did have other information such as pagination, we want to keep the `users` state as "specific" as possible, so that it only stores the users array part of the API response. + +1. If you look at http://localhost:3000/ or your terminal, it will probably say that `useState` and `useEffect` are not defined. You should import these React hooks from React like this on line 1: + + ```js + import React, { useEffect, useState } from 'react'; ``` 1. On the line after `