
We really hope not!
Please feel free to interrupt and ask questions, make this more of a conversation and less of a lecture.
Please keep learning after this workshop! There are many people available to help you.

Bruno Rosendo
MEIC 1st Year
(Almost) Senior Backend Engineer
João Mesquita
MEIC 1st Year
(Almost) Senior Frontend Engineer

HTTP is a protocol used to communicate between two machines, currently used in web applications.
In a simple form:

HTTP has many methods, so we'll only show the most common:
GET Usually used to read or fetch resources. Should not have secondary effects on the server.POST Usually used to interact with a resource, often causing a change in state or side-effects.PUT Usually used to create/replace entities. Should be idempotent - No matter how many times you call it, the result is the same.PATCH Usually used to apply partial updates to a resource.DELETE Usually used to delete a resource.Each HTTP Response has an associated Status code.
1XX Information2XX Success3XX Redirects4XX Client error5XX Server errorCheck out https://http.cat !
Some examples:
201 Created After a successful creation of a resource301 Moved Permanently Useful for crawlers to know when a webpage has been moved to another location401 Unauthorized Requires authentication to access the resource404 Not Found The requested resource does not exist418 I'm a teapot An HTTP easter-egg503 Service Unavailable The server is not ready to handle the request. Maybe it's under heavy load, or undergoing maintenanceAPI (Application Programming Interface) is the specification of methods through which you can interact with a service. Often web applications use REST APIs.
Some common public APIs:
The server will receive the request and handle it
Web applications are simply programs that listen for requests and send responses, using the HTTP protocol.
Almost any language has its version of an http server module.
The most common are Java, Python, C# and Node.js.
Today, we'll look specifically into Node.js
Node.js is a server-side language that uses V8 JavaScript engine, which means you can use (almost) the same language you have to use on the browser, but now on the server as well!
const http = require('http');const server = http.createServer(function (req, res) { res.write('Hello World!'); // write a response to the client res.end(); // end the response});server.listen(80); //the server listens on port 80 (HTTP default)
npm is the package manager for Node.js. The basic commands you need to know are:
# Bootstraps the project, creating the package.jsonnpm init
# Adds a dependency to package.json and installs it locally npm install <package>
# Runs a command as defined in the `scripts` section on package.jsonnpm run <cmd>
React is a library for building user interfaces (aka Frontend)
Express is a minimal framework used to build web servers (usually Backend)

We purposefully left some (somewhat relevant) parts out because We're about to give a lot of information at once, which can be counter-productive.
It is normal if you feel lost in the beginning, don't give up and eventually all will start to make sense.
Never stop learning.
React is a JavaScript library that automatically renders and handles component updates on a <div> of your website.
ReactDOM.render( <App />, document.getElementById("root"));
This allows it to run wherever inside an existing website. You can even migrate progressively from old UIs to React-powered UI components.
React is just glorified JavaScript. Always keep this in mind! Most of the problems you'll face are just JavaScript problems.
To use React, you just need to load it in a script tag in your HTML.
<html lang="en"> <head> <meta charset="utf-8"> <title>NIJobs</title> <link href="https://ni.fe.up.pt/st4g1ng/nijobs/static/css/main.4f9a2d8f.chunk.css" rel="stylesheet"> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <!-- React source code --> <script src="https://ni.fe.up.pt/st4g1ng/nijobs/static/js/2.8ac0d13b.chunk.js"></script> <!-- Application source code, using React --> <script src="https://ni.fe.up.pt/st4g1ng/nijobs/static/js/main.df8d00d7.chunk.js"></script> </body></html>
In a typical web application, you have 3 layers:

In Imperative programming, you define exactly what will be done and how.
In Declarative programming, you define what happens depending on some state.
function markSelected(id) { const item = document.getElementById(id); item.classList.add("selected");}Array.from(document.getElementsByClassName("todo-item")) .forEach(elem => elem.addEventListener("click", markSelected(elem.id)))
const [items, setItems] = useState([{isSelected: false, text: "TODO1"}])const toggleItemSelection = (i) => { setItems((items) => { const updatedItems = cloneDeep(items); updatedItems[i].isSelected = !items[i].isSelected return updatedItems });}items.map((item, i) => ( <p className={item.isSelected && "selected"} onClick={toggleItemSelection(i)} > {item.text} </p>))
React uses an HTML-in-JS language (JSX) that lets you specify the components similarly to how you would do it in regular HTML.
<div className="meteorolgy-widget"><p>{"This is Javascript. " + "Today it's " + getMeteoPrediction()}</p>{ weeklyPredictions.map(prediction => ( <p>{prediction.day + " - " + prediction.state}</p> ))}</div>
There are some differences like using className instead of class, and allowing you to have JavaScript sections to generate some parts of it.
React is based on a tree of components, recursively rendered: a component can render none or multiple children, which will be other components, which will be rendered themselves, and so on.
const NewsWebpage = ({news, ads}) => ( <> // Special "dummy" component - React.Fragment <NewsArea news={news}/> <AdsColumn ads={ads}> </>)
Components can receive a props object to use when creating the rendering logic, in order to change dynamically.
Components always have a children prop representing their children components.
const WrapperThatAddsAnHelloV1 = (props) => ( <> <p>Hello,</p> <p>{props.name}</p> </>)const WrapperThatAddsAnHelloV2 = (props) => ( <> <p>Hello,</p> {props.children} </>)const MyPage = () => ( <> <WrapperThatAddsAnHelloV1 name="World"/> <WrapperThatAddsAnHelloV2> <p>World</p> </WrapperThatAddsAnHelloV2> </>)
DOM (Document Object Model) is the browser's representation of a web page.
<html> <head> <title>DOM</title> </head> <body> <p>Hello World</p> </body></html>
React has the concept of the Virtual DOM, which it stores internally to manage the components' state.
Virtual DOM as it only updates the relevant components instead of the whole page when rendering components in the browser.
When the VDOM changes, those are mapped to instructions to update the real DOM (append, delete and update operations). These instructions are generated by comparing the new version of the VDOM with the older one, and generating the minimum set of operations required to change it on the DOM*.
If we used this in React, displaying 1000 elements would require in the order of one billion comparisons. This is far too expensive. Instead, React implements a heuristic O(n) algorithm based on two assumptions:
By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there’s a difference.
For example, when adding an element at the end of the children, converting between these two trees works well:
<ul> <!-- before --> <li>first</li> <li>second</li></ul><ul> <!-- after --> <li>first</li> <li>second</li> <li>third</li></ul>
<li>first</li> trees, match the two <li>second</li> trees, and then insert the <li>third</li> tree.If you implement it naively, inserting an element at the beginning has worse performance. For example, converting between these two trees works poorly:
<ul> <!-- before --> <li>Duke</li> <li>Villanova</li></ul><ul><!-- after --> <li>Connecticut</li> <li>Duke</li> <li>Villanova</li></ul>
React will mutate every child instead of realizing it can keep the <li>Duke</li> and <li>Villanova</li> subtrees intact. This inefficiency can be a problem.
In order to solve this issue, React supports a key attribute. When children have keys, React uses the key to match children in the original tree with children in the subsequent tree. For example, adding a key to our inefficient example above can make the tree conversion efficient:
<ul> <li key="2015">Duke</li> <li key="2016">Villanova</li></ul><ul> <li key="2014">Connecticut</li> <li key="2015">Duke</li> <li key="2016">Villanova</li></ul>
Now React knows that the element with key '2014' is the new one, and the elements with the keys '2015' and '2016' have just moved.
Usually, React will let you know when you have some list of mutating children and you should be using keys.
But there are some things to consider before choosing your keys:
In order to interact with the Virtual DOM, React lets you use React Components, which can be classes or functions (we’ll use functions) that represent a part of the website and can contain more components inside them.
These React Components are bound by a Lifecycle that manages their existence and interactions, which reflect on the actual DOM after the Reconciliation Phase.
There are 4 steps:
React Hooks are JavaScript functions that can interact with the component, by executing specific actions during the component lifecycle.
React exposes some default hooks, but you can create custom hooks which call React's ones for more complex scenarios.
There are two rules when using React Hooks:
Let's you store some state in-between re-renders. If you pass a function as the initial value, it will only run it on the first render.
Returns an array where the first value is the state value and the second is a setter function for that value.
It's recommended you have a separate state for every variable you want to store, instead of a giant object with a field for each.
const [count, setCount] = useState(0);const incrementCounter = () => { setCount(count + 1)}const decrementCounter = () => { setCount(currentCount => currentCount - 1)}
setState(val) vs setState(fn)Using the function version is better due to async updates. If you call incrementCounter in rapid succession, React will batch the updates and race conditions may prevent the counter from updating multiple times, i.e. the count variable will not update in between calls.
Using an updater function, the "current state" variable is always correct.
Lets you execute code at different stages of the lifecycle. It is called at every render, but it might do nothing, depending on the dependencies.
useEffect(() => { // This will run on every render})
Notice the undefined dependency array. This is the same as not calling useEffect, and writing the code directly on the component.
useEffect(() => { // This will run on mount only}, [])
Notice the empty dependency array, indicating that the code will run at mount only.
useEffect(() => { // This will run every time the dependencies change console.log(foo, bar)}, [foo, bar])
foo and bar might be some component props or variables created inside the component that depend on props. If the props change, making foo or bar change, the useEffect function will be executed.
Does NOT execute if the references to the dependencies don’t change.
useRef is similar to useState, however it does NOT trigger anything on change. It's just a mutable JavaScript object with a current field which stores whatever.
It's also used to store references to DOM elements, so that you can program something imperatively, if needed.
function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { inputEl.current.focus(); // `current` points to the mounted text input }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> );}
We can create a function that calls any React Hook and call it as if it were a React Hook, for more complex scenarios.
function useForm(fieldOptions) { const initialState = Object.entries(fieldOptions).map(...) const [fields, setFields] = useState(initialState) const setField = (fieldName) = (val) => { setFields(fields => ({ ...fields, [fieldName]: val })) } return [fields, setField];}
Since React is programmed in JavaScript, props DON'T have types by default. This can lead to some errors if you're not careful.
PropTypes lets you define the types for you component props, and even if they are required or not.
const SomeComponent = ({prop1, prop2, prop3}) => ()SomeComponent.propTypes = { prop1: PropTypes.string.isRequired, prop2: PropTypes.func, prop3: PropTypes.oneOf(["first", "second", "third"]).isRequired,}
In order to make requests to an HTTP API, you can use the built-in JS library fetch, or some external package such as Axios.
try { const response = await fetch(`${API_HOSTNAME}/offers`, { method: "GET", }); if (!response.ok) { // Any HTTP status non 2xx will make ok = false } // If the response is JSON, call .json() which returns a Promise const json = await res.json(); } catch (error) { // Handle Network Error}
React Router allows you to simulate different pages in your application.
<BrowserRouter> <Switch> <Route exact path="/" > <HomePage/> </Route> <Route path="/apply/company" > <CompanyApplicationPage/> </Route> </Switch></BrowserRouter>
When you define different Routes, technically, it will NOT create different pages. The user will still access "/", which will then load the application code and then the rest of the path will be parsed and a different component will be rendered, depending on the route.
This is why when you have an "only React with React Router" web application, you need to re-route all pages to "/", so that they are resolved by React, instead of the web server itself.
Redux allows you to centralize your application's state and logic enables powerful capabilities like undo/redo and state persistence.
Redux is made for JavaScript in general, but it has specific bindings for React, which are really useful.
You can specify the application theme with some UI defaults such as colors palette, the font type, spacing settings, etc...
This way, every time you are creating a UI, you don't have to worry about making everything consistent.
Usually, it's placed at the top of the Component Tree.
const theme = responsiveFontSizes(createMuiTheme({ palette: { primary: { main: "#DC4F47", }, secondary: { main: "#4F1315", }, }, typography: { fontFamily: [ "Poppins", "Roboto", "sans-serif", ].join(","), },}));<ThemeProvider theme={AppTheme}> <App/></ThemeProvider>

REST (Representational State Transfer) uses HTTP Status and URI rules to give meaning to calls and represent resources and operations.
Instead of GET /getStock?beverageType=water
we have GET /beverages/water/stock
POST /buy{ beverageType: water, quantity: 2, paymentMethod: { type: "credit-card", id: "1111-1111-1111-1111" ... }}
POST /water/buy{ quantity: 2, paymentMethod: { type: "credit-card", id: "1111-1111-1111-1111" ... }}
REST focuses on Resources and Operations, instead of behaviors. You don't call functions. You don't even know which functions exist. Only need to know about resources, and what you can do with those.
Often, the same URL is used but, by changing the HTTP Method, it gives a completely different meaning:
POST /posts/new # Creates a new post
GET /posts/new # Fetches the latest posts
Express is a web framework that abstracts some of the work involved in creating a web server in Node.js. It offers us neat feature like routing and middleware, which we'll see later on.
const express = require('express');const app = express();const port = 80;app.get('/', (req, res) => { res.send('Hello World!');})app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`);})
Here's how a simple server would look like in Node.js:
const server = http.createServer(function (req, res) { const endpoint = req.url; if(endpoint == '/') { res.write('hello world'); } else if(endpoint == '/bruno'){ res.write('hello Bruno'); } else if(endpoint == '/joao'){ res.write('hello João'); } else { res.write('hello stranger'); } res.end();});
Let's now try to use "parameters"
const server = http.createServer(function (req, res) { const endpoint = req.url; const params = endpoint.split('/'); // Are these really parameters? // What if we have something like /bruno/goodbye? if (params.length > 1) { const name = params[1]; res.write(`hello ${name}`); } else { res.write('hello world'); } res.end();});
We're expecting /:name, we need to make sure we don't affect other endpoints!
const server = http.createServer(function (req, res) { const endpoint = req.url; const params = endpoint.split('/'); // Are these really parameters? if (params.length > 2) { // Can you actually scale this? res.writeHead(StatusCodes.NOT_FOUND); res.write("The opereration is not supported"); } else if (params.length == 1) { const name = params[1]; res.write(`hello ${name}`); } else { res.write('hello world'); } res.end();});
What about error handling? I think you're starting to see the problem...
const server = http.createServer(function (req, res) { const endpoint = req.url; const params = endpoint.split('/'); // Are these really parameters? if (params.length > 2) { // Can you actually scale this? res.writeHead(StatusCodes.NOT_FOUND); res.write("The opereration is not supported"); } else if (params.length == 1) { const name = params[1]; if (typeof name == 'string') { if (name == "andre") { res.writeHead(StatusCodes.FORBIDDEN); res.write('You were banned from our website!'); } res.write(`hello ${params.name}`); } else { res.writeHead(StatusCodes.BAD_REQUEST); res.write('Invalid name!'); } } else { res.write('hello world'); } res.end();});
function validName(req, res, next) { if (typeof req.params.name != 'string') { res.status(StatusCodes.BAD_REQUEST).send('Invalid name!'); return; } next();}function isNameForbidden(req, res, next) { if (req.params.name == 'andre') { res.status(StatusCodes.FORBIDDEN).send('You were banned from our website!'); return; } next();}app.get('/:name', validName, isNameForbidden, (req, res) => { res.send(`Hello ${req.params.name}!`);})app.get('/', (req, res) => res.send('Hello World!'))
Routing is how an application responds to a client request to a particular endpoint (URI) and request method (GET, POST, etc.).
app.get('/', (req, res) => { res.send('Hello World!')})app.post('/', (req, res) => { res.send('Got a POST request')})app.put('/user', (req, res) => { res.send('Got a PUT request at /user')})app.delete('/user', (req, res) => { res.send('Got a DELETE request at /user')})
You can think about Route Parameters as variables lying in the URL itself. The values are stored in the req.params object, with the name specified in the path as the key.
app.get('/:name', (req, res) => { res.send(`Hello ${req.params.name}!`);})
There are more ways of handling route paths, like regex and wildcards. You can read about them here.
Query parameters, such as /?name=bob, are also common and stored in the req.query object.
In order to have a modular application, we can use multiple routers. You can think of a router as a mini-app. You have two ways of doing this:
app.route('/book') .get((req, res) => { res.send('Get a random book'); }) .post((req, res) => { res.send('Add a book'); }) .put((req, res) => { res.send('Update the book'); })
const router = express.Router();app.use("/book", router);// Translates to /book/buyrouter.post("/buy", (req, res) => { res.send("Buy a book");});
Middleware functions run between the request arrival and the route handler, so it's useful for validation or or some logic you want to run every time you receive a request.
They have access to the request object (req), the response object (res), and the next function. next is a special function in the Express router which, when invoked, executes the middleware succeeding the current one.
function isNameForbidden(req, res, next) { if (req.params.name == 'andre') { res.status(StatusCodes.FORBIDDEN).send('You were banned!'); return; } next();}app.get('/:name', validName, isNameForbidden, (req, res) => { res.send(`Hello ${req.params.name}!`);})
You can define error-handling functions the same way as other middleware functions, except with four arguments instead of three: err, req, res, and next.
You can use app.use() to define a global middleware, including an error handler.
app.use((err, req, res, next) => { console.error(err.stack) res.status(StatusCodes.INTERNAL_SERVER_ERROR).send('Something broke!')})
The res object has a lot of methods for sending responses to the client. Here are some of the most common ones:
You can read more about them here.
Express has a package called express-validator that can be used to validate the request body, params, query, headers, and cookies.
const { body, validationResult } = require('express-validator');app.post('/user', body('email').isEmail(), // must be an email body('password').isLength({ min: 5 }), // must be at least 5 chars long async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(StatusCodes.BAD_REQUEST).json({ errors: errors.array() }); } const user = await User.create( {email: req.body.email, password: req.body.password}); res.json(user); },);
There are a lot of available validators, you can check them here.
{ "errors": [ { "location": "body", "msg": "Invalid value", "param": "email" } ]}
You'll often want to develop an API that accepts JSON data (or another format). In order to do that, you need to parse the request body.
Before Express 4.16.0, you needed to install a package called body-parser to parse the request body as JSON. Now, you can simply use the express.json() method.
app.use(express.json());
CORS (Cross-Origin Resource Sharing) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin.
Due to this, you cannot make requests to services in different locations by default. This is the most common error for beginner web developers.

git clone https://github.com/NIAEFEUP/react-express-ws-2022.git/
Let's build a simple to-do list app using React and Express. We already started the project but we need your help to finish it!
You'll find many TODOs in the code, and you'll need to complete them to make the app work. They are ordered by priority but you can do them in any order you want.
The frontend folder contains the React app and the backend folder contains the Express app. Read the READMEs in each folder for more information.
We really hope not!
Please feel free to interrupt and ask questions, make this more of a conversation and less of a lecture.
Please keep learning after this workshop! There are many people available to help you.
Keyboard shortcuts
| ↑, ←, Pg Up, k | Go to previous slide |
| ↓, →, Pg Dn, Space, j | Go to next slide |
| Home | Go to first slide |
| End | Go to last slide |
| Number + Return | Go to specific slide |
| b / m / f | Toggle blackout / mirrored / fullscreen mode |
| c | Clone slideshow |
| p | Toggle presenter mode |
| t | Restart the presentation timer |
| ?, h | Toggle this help |
| Esc | Back to slideshow |