Skip to content

Commit c0f5223

Browse files
committed
Add code to start the project
1 parent b7ac332 commit c0f5223

File tree

10 files changed

+462
-8
lines changed

10 files changed

+462
-8
lines changed

build-a-rest-api-frontend/README.md

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,42 @@
22

33
This repository contains code related to the tutorial on [building a frontend for a REST API](https://realpython.com/build-a-rest-api-frontend/).
44

5-
Create and activate a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/), then install the necessary dependencies:
5+
## Setup
66

7-
```sh
7+
You should first create a virtual environment:
8+
9+
```console
810
$ python -m venv venv
911
$ source venv/bin/activate
12+
```
13+
14+
Install the pinned dependencies from `requirements.txt`:
15+
16+
```console
1017
(venv) $ python -m pip install -r requirements.txt
1118
```
1219

13-
Then you can navigate into the folder `source_code_final/` and create a new database:
20+
Then you can navigate into the folder `source_code_start/` and create a new database:
1421

1522
```sh
16-
(venv) $ cd source_code_final
17-
(venv) $ python build_databas.py
23+
(venv) $ cd source_code_start
24+
(venv) $ python build_database.py
1825
```
1926

27+
This will delete any existing database and create a new database named `people.db` that you can use with your project.
28+
2029
After building the database, you can start the Flask server:
2130

2231
```sh
2332
(venv) $ python app.py
2433
```
2534

2635
When the Flask server is running, you can visit the frontend on `http://localhost:8000` and the API documentation on `http://localhost:8000/api/ui`.
36+
37+
## Author
38+
39+
- **Philipp Acsany**, E-mail: [[email protected]]([email protected])
40+
41+
## License
42+
43+
Distributed under the MIT license. See [`LICENSE`](../LICENSE) for more information.

build-a-rest-api-frontend/requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ clickclick==20.10.2
66
connexion==2.14.1
77
Flask==2.2.2
88
flask-marshmallow==0.14.0
9-
Flask-SQLAlchemy==3.0.0
9+
Flask-SQLAlchemy==3.0.2
1010
idna==3.4
1111
inflection==0.5.1
1212
itsdangerous==2.1.2
@@ -17,11 +17,11 @@ marshmallow==3.18.0
1717
marshmallow-sqlalchemy==0.28.1
1818
packaging==21.3
1919
pyparsing==3.0.9
20-
pyrsistent==0.18.1
20+
pyrsistent==0.19.1
2121
PyYAML==6.0
2222
requests==2.28.1
2323
six==1.16.0
24-
SQLAlchemy==1.4.41
24+
SQLAlchemy==1.4.42
2525
swagger-ui-bundle==0.0.9
2626
urllib3==1.26.12
2727
Werkzeug==2.2.2
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from flask import render_template
2+
3+
import config
4+
from models import Person
5+
6+
app = config.connex_app
7+
app.add_api(config.basedir / "swagger.yml")
8+
9+
10+
@app.route("/")
11+
def home():
12+
people = Person.query.all()
13+
return render_template("home.html", people=people)
14+
15+
16+
if __name__ == "__main__":
17+
app.run(host="0.0.0.0", port=8000, debug=True)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from datetime import datetime
2+
3+
from config import app, db
4+
from models import Note, Person
5+
6+
PEOPLE_NOTES = [
7+
{
8+
"lname": "Fairy",
9+
"fname": "Tooth",
10+
"notes": [
11+
("I brush my teeth after each meal.", "2022-01-06 17:10:24"),
12+
(
13+
"The other day a friend said, I have big teeth.",
14+
"2022-03-05 22:17:54",
15+
),
16+
("Do you pay per gram?", "2022-03-05 22:18:10"),
17+
],
18+
},
19+
{
20+
"lname": "Ruprecht",
21+
"fname": "Knecht",
22+
"notes": [
23+
(
24+
"I swear, I'll do better this year.",
25+
"2022-01-01 09:15:03",
26+
),
27+
(
28+
"Really! Only good deeds from now on!",
29+
"2022-02-06 13:09:21",
30+
),
31+
],
32+
},
33+
{
34+
"lname": "Bunny",
35+
"fname": "Easter",
36+
"notes": [
37+
(
38+
"Please keep the current inflation rate in mind!",
39+
"2022-01-07 22:47:54",
40+
),
41+
("No need to hide the eggs this time.", "2022-04-06 13:03:17"),
42+
],
43+
},
44+
]
45+
46+
with app.app_context():
47+
db.drop_all()
48+
db.create_all()
49+
for data in PEOPLE_NOTES:
50+
new_person = Person(lname=data.get("lname"), fname=data.get("fname"))
51+
for content, timestamp in data.get("notes", []):
52+
new_person.notes.append(
53+
Note(
54+
content=content,
55+
timestamp=datetime.strptime(
56+
timestamp, "%Y-%m-%d %H:%M:%S"
57+
),
58+
)
59+
)
60+
db.session.add(new_person)
61+
db.session.commit()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import pathlib
2+
3+
import connexion
4+
from flask_marshmallow import Marshmallow
5+
from flask_sqlalchemy import SQLAlchemy
6+
7+
basedir = pathlib.Path(__file__).parent.resolve()
8+
connex_app = connexion.App(__name__, specification_dir=basedir)
9+
10+
app = connex_app.app
11+
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{basedir / 'people.db'}"
12+
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
13+
14+
db = SQLAlchemy(app)
15+
ma = Marshmallow(app)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from datetime import datetime
2+
3+
from marshmallow_sqlalchemy import fields
4+
5+
from config import db, ma
6+
7+
8+
class Note(db.Model):
9+
__tablename__ = "note"
10+
id = db.Column(db.Integer, primary_key=True)
11+
person_id = db.Column(db.Integer, db.ForeignKey("person.id"))
12+
content = db.Column(db.String, nullable=False)
13+
timestamp = db.Column(
14+
db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
15+
)
16+
17+
18+
class NoteSchema(ma.SQLAlchemyAutoSchema):
19+
class Meta:
20+
model = Note
21+
load_instance = True
22+
sqla_session = db.session
23+
include_fk = True
24+
25+
26+
class Person(db.Model):
27+
__tablename__ = "person"
28+
id = db.Column(db.Integer, primary_key=True)
29+
lname = db.Column(db.String(32), unique=True)
30+
fname = db.Column(db.String(32))
31+
timestamp = db.Column(
32+
db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
33+
)
34+
35+
notes = db.relationship(
36+
Note,
37+
backref="person",
38+
cascade="all, delete, delete-orphan",
39+
single_parent=True,
40+
order_by="desc(Note.timestamp)",
41+
)
42+
43+
44+
class PersonSchema(ma.SQLAlchemyAutoSchema):
45+
class Meta:
46+
model = Person
47+
load_instance = True
48+
sqla_session = db.session
49+
include_relationships = True
50+
51+
notes = fields.Nested(NoteSchema, many=True)
52+
53+
54+
note_schema = NoteSchema()
55+
person_schema = PersonSchema()
56+
people_schema = PersonSchema(many=True)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from flask import abort, make_response
2+
3+
from config import db
4+
from models import Note, Person, note_schema
5+
6+
7+
def read_one(note_id):
8+
note = Note.query.get(note_id)
9+
10+
if note is not None:
11+
return note_schema.dump(note)
12+
else:
13+
abort(404, f"Note with ID {note_id} not found")
14+
15+
16+
def update(note_id, note):
17+
existing_note = Note.query.get(note_id)
18+
19+
if existing_note:
20+
update_note = note_schema.load(note, session=db.session)
21+
existing_note.content = update_note.content
22+
db.session.merge(existing_note)
23+
db.session.commit()
24+
return note_schema.dump(existing_note), 201
25+
else:
26+
abort(404, f"Note with ID {note_id} not found")
27+
28+
29+
def delete(note_id):
30+
existing_note = Note.query.get(note_id)
31+
32+
if existing_note:
33+
db.session.delete(existing_note)
34+
db.session.commit()
35+
return make_response(f"{note_id} successfully deleted", 204)
36+
else:
37+
abort(404, f"Note with ID {note_id} not found")
38+
39+
40+
def create(note):
41+
person_id = note.get("person_id")
42+
person = Person.query.get(person_id)
43+
44+
if person:
45+
new_note = note_schema.load(note, session=db.session)
46+
person.notes.append(new_note)
47+
db.session.commit()
48+
return note_schema.dump(new_note), 201
49+
else:
50+
abort(404, f"Person not found for ID: {person_id}")
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from flask import abort, make_response
2+
3+
from config import db
4+
from models import Person, people_schema, person_schema
5+
6+
7+
def read_all():
8+
people = Person.query.all()
9+
return people_schema.dump(people)
10+
11+
12+
def create(person):
13+
lname = person.get("lname")
14+
existing_person = Person.query.filter(Person.lname == lname).one_or_none()
15+
16+
if existing_person is None:
17+
new_person = person_schema.load(person, session=db.session)
18+
db.session.add(new_person)
19+
db.session.commit()
20+
return person_schema.dump(new_person), 201
21+
else:
22+
abort(406, f"Person with last name {lname} already exists")
23+
24+
25+
def read_one(lname):
26+
person = Person.query.filter(Person.lname == lname).one_or_none()
27+
28+
if person is not None:
29+
return person_schema.dump(person)
30+
else:
31+
abort(404, f"Person with last name {lname} not found")
32+
33+
34+
def update(lname, person):
35+
existing_person = Person.query.filter(Person.lname == lname).one_or_none()
36+
37+
if existing_person:
38+
update_person = person_schema.load(person, session=db.session)
39+
existing_person.fname = update_person.fname
40+
db.session.merge(existing_person)
41+
db.session.commit()
42+
return person_schema.dump(existing_person), 201
43+
else:
44+
abort(404, f"Person with last name {lname} not found")
45+
46+
47+
def delete(lname):
48+
existing_person = Person.query.filter(Person.lname == lname).one_or_none()
49+
50+
if existing_person:
51+
db.session.delete(existing_person)
52+
db.session.commit()
53+
return make_response(f"{lname} successfully deleted", 200)
54+
else:
55+
abort(404, f"Person with last name {lname} not found")

0 commit comments

Comments
 (0)