Share
Explore

Lab: JSON and API client and server

Make our own small scale Toy Version of Mongo DB Server:

An API Server which can read/write JSON files.


Learning Outcomes:

Make a NODE.js program to provide an Express.js server with end point ROUTES to serve jokes which students encode into JSON text files.
In HTML : Forms: Actions → /resource
Application architectures: Web Services: API, which is an implementation of Microservices.
JSON: JavaScript Object Notation : key:value pairs contained in { }

Lab Activities:

Make an Express server which browser connects to.
HTML page provides a button and a Selector.
Button via onClick Event Handler will invoke API call to Server. This API activates a route on the Express.js server, which retrieves a random joke to display on the web page.
Server gets the joke from a JSON file in the file system.
Ryan Dahl says:
Creating a simple Node.js application to serve jokes through an Express server involves several steps which will be outlined in this lab.
We'll start by initializing a new Node.js project, then create the Express server, JSON joke files, and finally the web client that requests jokes using an API endpoint.
This lab exercise assumes that you have Node.js and Visual Studio Code already installed on your machine.

Step 1: Initialize a Node.js Project

Open Visual Studio Code.
Select File > Open Folder... and choose a directory where you want to create your project.
Open a new terminal in Visual Studio Code by selecting Terminal > New Terminal from the menu.
In the terminal, initialize a new Node.js project by entering:
npm init -y
Install the necessary NPM packages for our project:
npm install express

Step 2: Create Joke JSON Files

Create three JSON files in your project directory to store jokes. Each file will contain a JSON array of joke objects.
For example: jokes1.json

[
{"id": 1, "joke": "Why did the programmer quit his job? Because he didn't get arrays."},
{"id": 2, "joke": "Why was the JavaScript developer sad? Because he didn't Node how to Express himself."},
{"id": 3, "joke": "Why did the developer go broke? Because he used up all his cache."}
]
Duplicate this process to create jokes2.json and jokes3.json, each with different jokes.

Step 3: Create the Express Server

Create a file called server.js at the root of your project folder and add the following code:
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const port = 3000;

// Serve static files from the "public" folder
app.use(express.static('public'));

app.get('/joke', (req, res) => {
const jokeFileNumber = Math.floor(Math.random() * 3) + 1; // Selects a random joke file: jokes1.json, jokes2.json, or jokes3.json.
const filePath = path.join(__dirname, `jokes${jokeFileNumber}.json`);

fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
res.status(500).send('Error reading joke file');
return;
}

const jokes = JSON.parse(data);
const randomJoke = jokes[Math.floor(Math.random() * jokes.length)];
res.json(randomJoke);
});
});

app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
image.png

Step 4: Create the Web Client

Within your project directory, create a new folder named public. Inside the public folder, create a file named index.html with the following content:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Joke Service</title>
</head>
<body>
<h1>Random Joke Generator</h1>
<button id="getJokeBtn">Get Random Joke</button>
<p id="jokeDisplay"></p>

<script>
document.getElementById('getJokeBtn').addEventListener('click', function() {
fetch('/joke')
.then(response => response.json())
.then(data => {
document.getElementById('jokeDisplay').textContent = data.joke;
})
.catch(error => {
console.error('Error fetching joke:', error);
document.getElementById('jokeDisplay').textContent = 'Sorry, a joke could not be fetched at this time.';
});
});
</script>
</body>
</html>

Step 5: Running the Server

Back in the Visual Studio Code terminal, run your server with:
node server.js
Now go to http://localhost:3000 in your web browser. You should see the interface with a button to 'Get Random Joke.' When you click the button, it will fetch a random joke from one of the JSON files via the server and display it.

Version Control (Optional)

It is a good practice to version control your code. Initialize a Git repository if desired:
git init
git add .
git commit -m "Initial commit - Joke server setup"
You can then push this repository to a remote repository hosted on a service like GitHub, GitLab, or Bitbucket.

Conclusion

This lab will give students hands-on experience with:
Initializing a Node.js project
Using the Express framework to create a simple server
Serving static files
Handling API endpoints
Reading from the server's file system
Implementing client-side JavaScript to fetch data from the server
Make sure to explain each step in detail during the instructional lecture to help students understand the workflow and the tools they are using. Students are encouraged to experiment and learn by modifying code, adding new features, and understanding how client-server communication works in a web setting using Node.js and Express.


Lab Part 2: Let user add new jokes:


To add the functionality for a user to submit a new joke to jokes1.json, we need to do the following:

Update the index.html file to include a form for the user to submit a new joke.
Update the server.js file to handle POST requests to add a new joke to jokes1.json.
Let's start with the HTML form:

Updated index.html:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Joke Service</title>
</head>
<body>
<h1>Random Joke Generator</h1>

<button id="getJokeBtn">Get Random Joke</button>

<p id="jokeDisplay"></p>

<!-- New joke submission form -->
<h2>Submit a New Joke</h2>
<form id="jokeForm">
<input type="text" id="newJoke" placeholder="Enter your joke" required>
<button type="submit">Submit Joke</button>
</form>

<script>
// Existing joke fetching functionality
document.getElementById('getJokeBtn').addEventListener('click', function() {
fetch('/joke')
.then(response => response.json())
.then(data => {
document.getElementById('jokeDisplay').textContent = data.joke;
})
.catch(error => {
console.error('Error fetching joke:', error);
document.getElementById('jokeDisplay').textContent = 'Sorry, a joke could not be fetched at this time.';
});
});

// New joke submission functionality
document.getElementById('jokeForm').addEventListener('submit', function(event) {
event.preventDefault();
const jokeText = document.getElementById('newJoke').value;

fetch('/jokes', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ joke: jokeText }),
})
.then(response => response.json())
.then(data => {
alert(data.message);
document.getElementById('newJoke').value = ''; // Clear input field
})
.catch(error => {
console.error('Error submitting new joke:', error);
alert('Failed to submit new joke');
});
});
</script>
</body>
</html>
Next, let's update the server.js file to handle the POST requests to add a new joke:

Updated server.js:


const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const port = 3000;

app.use(express.json()); // To parse JSON bodies
app.use(express.static('public')); // Serve static files from the "public" folder

// Existing GET joke endpoint
// ...

// New POST joke endpoint
app.post('/jokes', (req, res) => {
const newJoke = req.body;
const filePath = path.join(__dirname, 'jokes1.json');

fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
res.status(500).send('Error reading joke file');
return;
}

const jokes = JSON.parse(data);
const newId = jokes.length > 0 ? Math.max(...jokes.map(joke => joke.id)) + 1 : 1;
const jokeToAdd = { id: newId, joke: newJoke.joke };
jokes.push(jokeToAdd);

fs.writeFile(filePath, JSON.stringify(jokes, null, 2), (err) => {
if (err) {
res.status(500).send('Error writing to joke file');
return;
}
res.json({ message: 'Joke added successfully' });
});
});
});

app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
Make sure you have body-parser middleware (express.json()) to correctly parse the JSON body of the POST requests.
Now when you launch your server using node server.js, you should be able to access your index.html by pointing your browser to http://localhost:3000/. You'll see a form to submit new jokes, and this will write the new joke to the jokes1.json file when submitted.

Lab Exercise 3:

server.js file using Express that allows users to enter jokes, persists them in a "joke1.json" file, and retrieves jokes from the same file:

To display an HTML page at the root URL () that includes a button to fetch all jokes and a form to add a new joke, you can modify your Express server code as follows:
Create an HTML file (e.g., index.html) with the desired structure for the page. Here's an example:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Joke Service</title> <style> body { font-family: Arial, sans-serif; padding: 20px; transition: background-color 1s ease, color 1s ease; } #jokeDisplay { margin: 20px 0; padding: 10px; border: 1px solid #ddd; transition: border-color 1s ease; } #getJokeBtn { padding: 10px 15px; background-color: #007bff; border: none; border-radius: 5px; color: white; transition: background-color 1s ease; cursor: pointer; } #getJokeBtn:hover { background-color: #0056b3; } </style> </head> <body> <h1>Random Joke Generator</h1> <button id="getJokeBtn">Get Random Joke</button> <p id="jokeDisplay"></p>
<!-- New joke submission form --> <!-- ... (same as before) -->
<script> const colorSchemes = [ { bgColor: '#fefbd8', textColor: '#5d478b', borderColor: '#5d478b' }, { bgColor: '#d1f2a5', textColor: '#f56991', borderColor: '#f56991' }, { bgColor: '#ffcccb', textColor: '#6b5b95', borderColor: '#6b5b95' }, { bgColor: '#d2b4de', textColor: '#ffaf7b', borderColor: '#ffaf7b' } ];
function changeColorScheme() { const index = Math.floor(Math.random() * colorSchemes.length); const scheme = colorSchemes[index]; document.body.style.backgroundColor = scheme.bgColor; document.body.style.color = scheme.textColor; document.getElementById('jokeDisplay').style.borderColor = scheme.borderColor; }
document.getElementById('getJokeBtn').addEventListener('click', function() { fetch('/joke') .then(response => response.json()) .then(data => { document.getElementById('jokeDisplay').textContent = data.joke; changeColorScheme(); // Change color scheme with each new joke }) .catch(error => { console.error('Error fetching joke:', error); document.getElementById('jokeDisplay').textContent = 'Sorry, a joke could not be fetched at this time.'; }); });
// New joke submission functionality // ... (same as before) </script> </body> </html>

Update your Express server code to serve this HTML file when the root URL is accessed:
const express = require('express'); const fs = require('fs'); const bodyParser = require('body-parser');
const app = express(); const port = 3000;
app.use(bodyParser.json());
// Serve static files from a directory (e.g., public) app.use(express.static('public'));
// Read the existing jokes from "joke1.json" file let jokeData = require('./joke1.json');
// Endpoint to get all jokes app.get('/jokes', (req, res) => { res.json(jokeData); });
// Endpoint to add a new joke app.post('/jokes', (req, res) => { const newJoke = req.body;
// Add the new joke to the array jokeData.push(newJoke);
// Save the updated jokes to "joke1.json" file fs.writeFile('./joke1.json', JSON.stringify(jokeData, null, 2), (err) => { if (err) { console.error('Error saving joke:', err); res.status(500).json({ error: 'Failed to save joke' }); } else { console.log('Joke added successfully!'); res.json({ message: 'Joke added successfully!' }); } }); });
app.listen(port, () => { console.log(`Server is running on port ${port}`); });

Place the index.html file in a directory named "public" in the same directory as your server file.
With these changes, when you access , it will serve the index.html file from the "public" directory, and the HTML page with the button to fetch jokes and the form to add new jokes will be displayed. You can implement the JavaScript functions (fetchJokes and addJoke) to interact with your API to fetch and add jokes as needed.
In this updated code:
We use the Express framework to create a simple API server.
We use the body-parser middleware to parse JSON data from incoming requests.
We have two endpoints: /jokes (GET) for retrieving jokes and /jokes (POST) for adding new jokes.
We read the existing jokes from "joke1.json" when the server starts.
The /jokes endpoint returns the list of jokes in JSON format.
The /jokes (POST) endpoint allows users to add new jokes to the array and persists them to the "joke1.json" file.
The server listens on port 3000.
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.