Skip to content

Commit fff9b6c

Browse files
committed
Working on a back4app alternative to the persistence lesson
1 parent 7b2053d commit fff9b6c

File tree

8 files changed

+5808
-55
lines changed

8 files changed

+5808
-55
lines changed

.editorconfig

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = tab
6+
insert_final_newline = true
7+
trim_trailing_whitespace = true
8+
9+
[package.json]
10+
indent_style = space
11+
tab_width = 2
12+
13+
[*.yaml]
14+
indent_style = space
15+
tab_width = 2
16+
17+
[*.md]
18+
indent_style = space
19+
tab_width = 2

lessons/03-persistence/03-persistence.md

+22-28
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ Sam Tarakajian for NYU
88

99
## Essential Questions
1010
- How can we persist data over a long period of time, even if the server restarts?
11-
- What is CRUD? How can we implement it?
11+
- What is BaaS?
12+
- What is CRUD?
1213

1314
## Introduction
1415
We've seen how to put a Node server on the Internet. The question is, how does that server store data? It could store data in memory, but then that goes away when the server closes. It could write files to disk, but file access is slow, especially if multiple people are trying to read/write a file at the same time.
1516

1617
### Target Audience / Prerequisite & Pre-Assessment
17-
The first three Node classes are prerequisite for this class.
18+
The first three classes are prerequisite for this class.
1819

1920
### Outcomes & Goals
2021
* In this workshop we will be looking at how to implement data persistance on a web server. We will store data on a server, and update that data using an API call.
@@ -34,23 +35,15 @@ This workshop is indended to last about three hours
3435
- nvm
3536
- git
3637
- Postman (https://www.postman.com/)
37-
- mongodb
38-
- See https://docs.mongodb.com/manual/administration/install-community/ for platform-specific installation instructions
39-
- sign up for heroku
40-
- (recommended) mongodb compass https://www.mongodb.com/download-center/compass which you can use to visualze your database
41-
4238

4339
### Exercises To Do Before Class
44-
- Introduce yourself to MongoDB concepts
45-
- https://docs.mongodb.com/manual/introduction/
46-
- https://docs.mongodb.com/manual/core/databases-and-collections/
47-
- https://docs.mongodb.com/manual/core/document/
48-
- https://docs.mongodb.com/manual/crud/
40+
- Create an account on [Back4App](https://www.back4app.com/)
41+
- Introduce yourself to Back4App
42+
- https://www.back4app.com/docs/get-started/welcome
4943

5044
### Vocabulary (example)
5145
* Database
5246
* Deploy
53-
* Virtual Machine
5447

5548
## Exercise Descriptions
5649

@@ -108,7 +101,7 @@ const access = promisify(fs.access);
108101

109102
const app = express();
110103

111-
app.get("/", async (req, res) => {
104+
app.get("/", async (req, res, next) => {
112105

113106
const datafile = path.join(__dirname, "data.json");
114107

@@ -128,14 +121,12 @@ app.get("/", async (req, res) => {
128121

129122
// Write the result back to disk
130123
fs.writeFileSync(datafile, JSON.stringify(data));
131-
124+
132125
// Finally, report back the number of pageviews
133126
res.send(`This page has been viewed ${data.pageviews} times`);
134-
135-
} catch (e) {
136-
res.send("Some kind of terrible error happened");
137127

138-
console.dir(e);
128+
} catch (e) {
129+
next(e);
139130
}
140131
});
141132

@@ -151,7 +142,7 @@ This is better (and also gives us a chance to talk about Promises and async/awai
151142

152143
Now we get to talk about something fun called a database.
153144

154-
### Mongodb
145+
### Databases
155146

156147
A database does a few important things for us:
157148

@@ -160,17 +151,20 @@ A database does a few important things for us:
160151
- It provides an API, which means the database can be hosted in a number of ways (important for working with a VM).
161152
- It takes care of a lot of messy details for us, like concurrency (two people touching the database at the same time) and consistency (not a problem for us, but a problem for some people).
162153

163-
Let's start a database! See the instructions on `https://docs.mongodb.com/manual/administration/install-community/`
164-
165154
Interacting with the database is a lot like interacting with a remote API. We don't actually deal with modifying any data files. Rather, we connect to the database server, and we handle requests by interacting with that server on the behalf of our client.
166155

167156
`Client -> Server (Our express server) -> Database Server (We don't write this) -> Actual database files`
168157

169-
See [this file](./src/mongo-basic/app.js) for the basics. As you can see, this app is able to stop and restart, while still keeping all of its data.
158+
### Starting with Back4App
159+
160+
Back4App has a silly name, but it gives you a really streamlined way to interact with a relational database. To understand what we're doing, it might help to picture how all the different parts of our web application fit together.
161+
162+
![image](img/webapp-diagram.png)
170163

164+
Our server is fulfilling two roles simultaneously. First, it's serving the entire website, aka the client application. This is the page that actually loads when a person visits your website. Second, it's providing an API—and Application Programming Interface—that the website can use to fetch data from your backend database. Dynamic websites like Twitter and Facebook work the same way. When you go to twitter.com, first the webpage itself loads, and then a separate request gets the content that should actually be displayed in the page. The page doesn't connect to the database directly, but uses an interface that interacts with the database on its behalf. It's a bit like going to the bank; when you ask to make a withdrawal, the bank doesn't open its vault and trust you to take the right amount. Instead, there's an interface that does all of that on your behalf
171165
### Mongodb plus Heroku
172166

173-
Let's throw this up on Heroku. So right now we're running Mongodb locally. We could maybe figure out a way to tell Heroku to install Mongo on our virtual machine, but a better way is with something called a Heroku add-on. Log into Heroku, click on the app you want to use (we could use the same app we used last week, or create a new free one, whichever you prefer). Next, add the mLab add-on. This adds a Mongodb server that will start in parallel to our Heroku VM.
167+
Let's throw this up on Heroku. So right now we're running Mongodb locally. We could maybe figure out a way to tell Heroku to install Mongo on our virtual machine, but a better way is with something called a Heroku add-on. Log into Heroku, click on the app you want to use (we could use the same app we used last week, or create a new free one, whichever you prefer). Next, add the mLab add-on. This adds a Mongodb server that will start in parallel to our Heroku VM.
174168

175169
If you want to push your new repo up to Heroku, follow the usual steps:
176170

@@ -474,11 +468,11 @@ const DumbTwitterForm = function(props) {
474468
return (
475469
<form onSubmit={handleSubmit}>
476470
<label>
477-
User:
471+
User:
478472
<input type="text"value={user} onChange={updateUser}/>
479473
</label>
480474
<label>
481-
Message:
475+
Message:
482476
<input type="text" value={message} onChange={updateMessage}/>
483477
</label>
484478
<input type="submit" value="Submit"/>
@@ -540,6 +534,6 @@ https://dumb-twitter.herokuapp.com/
540534

541535
### References
542536

543-
### Implementation Guidance & Teaching Reflection
537+
### Implementation Guidance & Teaching Reflection
544538

545-
***With thanks and acknowledgement, this is based on the template provided by [Eyebeam](https://github.com/eyebeam/curriculum/blob/master/TEMPLATE.md)***
539+
***With thanks and acknowledgement, this is based on the template provided by [Eyebeam](https://github.com/eyebeam/curriculum/blob/master/TEMPLATE.md)***

lessons/03-persistence/img/webapp-diagram.ai

+5,667
Large diffs are not rendered by default.
18.6 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
11
// DumbTwitter.jsx
2+
const { useState, useEffect } = require('react');
23
const React = require('react');
34
const DumbTwitterForm = require("./DumbTwitterForm");
45
const DumbTwitterList = require("./DumbTwitterList");
56

67
/* the main page for the index route of this app */
78
const DumbTwitter = function() {
9+
10+
const [tweets, setTweets] = useState([]);
11+
12+
async function fetchTweets() {
13+
const rawData = await fetch("api/tweets");
14+
const body = await rawData.json();
15+
setTweets(body);
16+
}
17+
18+
useEffect(() => {
19+
fetchTweets();
20+
}, []);
21+
822
return (
923
<div>
1024
<h1>Dumb Twitter</h1>
11-
<DumbTwitterForm />
12-
<DumbTwitterList />
25+
<DumbTwitterForm onTweeted={fetchTweets} />
26+
<DumbTwitterList tweets={tweets} />
1327
</div>
1428
);
1529
}
1630

17-
module.exports = DumbTwitter;
31+
module.exports = DumbTwitter;

lessons/14-back4app-experiment/app/components/DumbTwitterForm.jsx

+45-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,52 @@
11
// DumbTwitterForm.jsx
2+
const { useState } = require('react');
23
const React = require('react');
34

4-
const DumbTwitterForm = function() {
5+
const DumbTwitterForm = function(props) {
6+
7+
const [user, setUser] = useState(null);
8+
const [message, setMessage] = useState(null);
9+
10+
const updateUser = (event) =>{
11+
setUser(event.target.value);
12+
};
13+
14+
const updateMessage = (event) => {
15+
setMessage(event.target.value);
16+
};
17+
18+
const doAsyncSubmit = async () => {
19+
const response = await fetch('api/tweet', {
20+
method: 'POST',
21+
headers: {
22+
'Content-Type': 'application/json',
23+
},
24+
body: JSON.stringify(({user, message})),
25+
});
26+
if (response.status === 200) {
27+
setUser("");
28+
setMessage("");
29+
if (props.onTweeted) props.onTweeted();
30+
}
31+
};
32+
33+
const handleSubmit = (event) => {
34+
doAsyncSubmit();
35+
event.preventDefault();
36+
}
37+
538
return (
6-
<div>
7-
This is where the dumb Twitter form will go.
8-
</div>
39+
<form onSubmit={handleSubmit}>
40+
<label>
41+
User:
42+
<input type="text" value={user} onChange={updateUser}/>
43+
</label>
44+
<label>
45+
Message:
46+
<input type="text" value={message} onChange={updateMessage}/>
47+
</label>
48+
<input type="submit" value="Submit"/>
49+
</form>
950
);
1051
}
1152

Original file line numberDiff line numberDiff line change
@@ -1,29 +1,17 @@
11
const { useState, useEffect } = require('react');
22
const React = require('react');
33

4-
const DumbTwitterList = function() {
4+
const DumbTwitterList = function(props) {
55

6-
const [tweets, setTweets] = useState([]);
7-
8-
const listElements = tweets.map((tweet, idx) => {
6+
const listElements = props.tweets.map((tweet, idx) => {
97
return <p key={idx}> {`${tweet.user}: ${tweet.message}`} </p>;
108
});
119

12-
async function fetchTweets() {
13-
const rawData = await fetch("api/tweets");
14-
const body = await rawData.json();
15-
setTweets(body);
16-
}
17-
18-
useEffect(() => {
19-
fetchTweets();
20-
}, []);
21-
2210
return (
2311
<div>
2412
{listElements}
2513
</div>
2614
);
2715
}
2816

29-
module.exports = DumbTwitterList;
17+
module.exports = DumbTwitterList;

lessons/14-back4app-experiment/server.js

+35-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ const port = process.env.PORT || 3000;
99
const bodyParser = require('body-parser');
1010
app.use(bodyParser.json());
1111

12+
// Initialize your connection to Back4App
13+
const Parse = require('parse/node');
14+
const { json } = require('body-parser');
15+
16+
Parse.serverURL = 'https://parseapi.back4app.com'; // This is your Server URL
17+
Parse.initialize(
18+
'woTcOnHZSKrWRhQucRxAkrs4fPZWFmxBdnOH4yFS', // This is your Application ID
19+
'TPkEzQBaiTVWdpBXqAK6jHLeaUjvvwsPcOybmehO', // This is your Javascript key
20+
'cbdbjPOsdj7S8cNsmnFTOyYgyJrksQhVu3KjuRHm' // This is your Master key (never use it in the frontend)
21+
);
22+
1223
// Special piece for running with webpack dev server
1324
if (process.env.NODE_ENV === "development") {
1425
const webpack = require('webpack');
@@ -37,9 +48,19 @@ const dummyData = [
3748
{user: "Tom", message: "Hi Alex, nice to meet you"}
3849
];
3950

40-
// Fetch tweets from the database
41-
app.get("/api/tweets", (_, res) => {
42-
res.json(dummyData);
51+
// Fetch tweets from the database. For now, just fetch the first 100
52+
app.get("/api/tweets", (_, res, next) => {
53+
let tweetClass = Parse.Object.extend("tweet");
54+
let query = new Parse.Query(tweetClass);
55+
56+
// Sort by their creation date
57+
query.descending("createdAt");
58+
59+
query.find().then(results => {
60+
res.json(results);
61+
}).catch(err => {
62+
next(err);
63+
});
4364
});
4465

4566
// Post a new tweet
@@ -50,8 +71,17 @@ app.post("/api/tweet", (req, res) => {
5071
if (!user || !message) {
5172
res.status(400).send("Missing user or message");
5273
} else {
53-
dummyData.push({user, message});
54-
res.sendStatus(200);
74+
75+
let tweetClass = Parse.Object.extend("tweet");
76+
let tweet = new tweetClass();
77+
tweet.set("user", user);
78+
tweet.set("message", message);
79+
80+
tweet.save().then(result => {
81+
res.json(result);
82+
}).catch(err => {
83+
next(err);
84+
});
5585
}
5686
});
5787

0 commit comments

Comments
 (0)