Skip to content

Commit 0912e67

Browse files
committed
Days 1-12 APIs and FLASk
1 parent c07c5a0 commit 0912e67

33 files changed

+2661
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"python.pythonPath": "c:\\Users\\kevin\\Desktop\\Programming\\Practice Projects\\100daysofweb-with-python-course\\APIs\\bitcoin_app\\venv\\Scripts\\python.exe"
3+
}

APIs/bitcoin_app/app.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import json
2+
from typing import List
3+
4+
from apistar import App, Route, types, validators
5+
from apistar.http import JSONResponse
6+
7+
#helpers
8+
9+
def _load_bitcoin_data():
10+
with open('bitcoin_data.json') as f:
11+
data = json.loads(f.read())
12+
return {user["id"]: user for user in data}
13+
14+
users = _load_bitcoin_data()
15+
VALID_IDS = set([user["id"]
16+
for user in users.values()])
17+
ID_NOT_FOUND = 'User ID not found.'
18+
19+
#VALID_SOCIAL_SECURITY = set([user["social_security_number"]
20+
# for user in users.values()])
21+
#SOCIAL_NOT_FOUND = "Social security number not found."
22+
23+
#load in data
24+
25+
#definition
26+
27+
class Users(types.Type):
28+
id = validators.Integer(allow_null=True)
29+
first_name = validators.String(default='')
30+
last_name = validators.String(default = '')
31+
bitcoin_address = validators.String(max_length=34)
32+
social_security_number = validators.String(min_length=11, max_length=11)
33+
34+
def list_bitcoin() -> List[Users]:
35+
return [Users(user) for user in users.values()]
36+
37+
def create_user(user: Users) -> JSONResponse:
38+
user_id = len(users) + 1
39+
user.id = user_id
40+
users[user_id] = user
41+
return JSONResponse(Users(user), 201)
42+
43+
def get_user(user_id: int) -> JSONResponse:
44+
user = users.get(user_id)
45+
if not user:
46+
error = {'error': ID_NOT_FOUND}
47+
return JSONResponse(error, 404)
48+
return JSONResponse(Users(user), 200)
49+
50+
def update_user(user_id: int, user: Users) -> JSONResponse:
51+
if not users.get(user_id):
52+
error = {'error': ID_NOT_FOUND}
53+
return JSONResponse(error, 404)
54+
55+
user["id"] = user_id
56+
users[user_id] = user
57+
return JSONResponse(Users(user), 200)
58+
59+
def delete_user(user_id:int) -> JSONResponse:
60+
if not users.get(user_id):
61+
error = {'error': ID_NOT_FOUND}
62+
return JSONResponse(error, 404)
63+
64+
del users[user_id]
65+
return JSONResponse({}, 204)
66+
67+
routes = [
68+
Route('/', method='GET', handler=list_bitcoin),
69+
Route('/', method='POST', handler=create_user),
70+
Route('/{user_id}/', method='GET', handler=get_user),
71+
Route('/{user_id}/', method='PUT', handler=update_user),
72+
Route('/{user_id}/', method='DELETE', handler=delete_user),
73+
74+
]
75+
76+
app = App(routes=routes)
77+
78+
79+
if __name__ == '__main__':
80+
app.serve('127.0.0.1', 5000, debug=True)

APIs/bitcoin_app/bitcoin_data.json

Lines changed: 1000 additions & 0 deletions
Large diffs are not rendered by default.

APIs/bitcoin_app/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
apistar>=0.5.41,<0.5.1000
2+
pytest

APIs/bitcoin_app/test_app.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
from apistar import test
2+
from app import app, users, ID_NOT_FOUND
3+
4+
client = test.TestClient(app)
5+
6+
def test_list_users():
7+
response = client.get('/')
8+
assert response.status_code == 200
9+
users = response.json()
10+
assert len(users) == 1000
11+
assert type(users) == list
12+
user = users[0]
13+
expected = {"id":1,"first_name":"Sterne","last_name":"Gell",\
14+
"bitcoin_address":"15czwRiYGZ6PGM8EjkMS38XBNmkiohSExs",\
15+
"social_security_number":"283-62-6536"}
16+
assert user == expected
17+
last_id = users[-1]["id"]
18+
assert last_id == 1000
19+
20+
def test_create_user():
21+
data = dict(first_name="Kevin",
22+
last_name="Bisner",
23+
bitcoin_address="15czwRiYG78SGM8EjkMS38XBNmkiohSExs",
24+
social_security_number="110-51-1732")
25+
response = client.post('/', data=data)
26+
assert response.status_code == 201
27+
assert len(users) == 1001
28+
29+
response = client.get('/1001/')
30+
assert response.status_code == 200
31+
expected = {"id":1001, "first_name":"Kevin", "last_name":"Bisner",\
32+
"bitcoin_address":"15czwRiYG78SGM8EjkMS38XBNmkiohSExs",\
33+
"social_security_number":"110-51-1732"}
34+
assert response.json() == expected
35+
36+
def test_create_user_missing_field():
37+
data = {'key': 1}
38+
response = client.post('/', data=data)
39+
assert response.status_code == 400
40+
41+
errors = response.json()
42+
assert errors['social_security_number'] ==\
43+
'The "social_security_number" field is required.'
44+
45+
def test_create_user_field_validation():
46+
data = {'bitcoin_address': 'x'*35,
47+
'social_security_number': 123456789}
48+
response = client.post('/', data=data)
49+
assert response.status_code == 400
50+
51+
errors = response.json()
52+
assert errors['bitcoin_address'] == 'Must have no more than 34 characters.'
53+
assert errors['social_security_number'] == 'Must have at least 11 characters.'
54+
55+
def test_get_user():
56+
response = client.get('/813/')
57+
assert response.status_code == 200
58+
59+
expected = {"id":813,"first_name":"Keven","last_name":"Jirka",
60+
"bitcoin_address":"1HdhruUcmU1z3fDhz9b6FzajLuE3LrzoB8",
61+
"social_security_number":"898-62-9881"}
62+
assert response.json() == expected
63+
64+
def test_get_user_notfound():
65+
response = client.get('/11111/')
66+
assert response.status_code == 404
67+
assert response.json() == {'error': ID_NOT_FOUND}
68+
69+
def test_update_user():
70+
data = {'first_name': 'Kevin',
71+
'last_name': 'Bisner',
72+
'bitcoin_address': 'HG7thak2968HJkLllaiw82FGlQ32K103hZ',
73+
'social_security_number': '100-33-1129'}
74+
response = client.put('/777/', data=data)
75+
assert response.status_code == 200
76+
77+
#test put response
78+
expected = {'id': 777, 'first_name': 'Kevin',
79+
'last_name': 'Bisner',
80+
'bitcoin_address': 'HG7thak2968HJkLllaiw82FGlQ32K103hZ',
81+
'social_security_number': '100-33-1129'}
82+
assert response.json() == expected
83+
84+
#check if data persisted == wiped our previous data car 777
85+
response = client.get('/777/')
86+
assert response.json() == expected
87+
88+
def test_update_user_notfound():
89+
data = {'first_name': 'Kevin',
90+
'last_name': 'Bisner',
91+
'bitcoin_address': 'HG7thak2968HJkLllaiw82FGlQ32K103hZ',
92+
'social_security_number': '100-33-1129'}
93+
response = client.put('/11111/', data=data)
94+
95+
assert response.status_code == 404
96+
assert response.json() == {'error': ID_NOT_FOUND}
97+
98+
def test_update_user_validation():
99+
data = {'first_name': 'Kevin',
100+
'last_name': 'Bisner',
101+
'bitcoin_address': 's' * 35,
102+
'social_security_number': '123456789'}
103+
response = client.put('/777/', data=data)
104+
assert response.status_code == 400
105+
106+
errors = response.json()
107+
assert errors ['bitcoin_address'] == 'Must have no more than 34 characters.'
108+
assert errors ['social_security_number'] == 'Must have at least 11 characters.'
109+
110+
def test_delete_user():
111+
user_count = len(users)
112+
113+
for i in (11, 22, 33):
114+
response = client.delete(f'/{i}/')
115+
assert response.status_code == 204
116+
117+
response = client.get(f'/{i}/')
118+
assert response.status_code == 404 #user_gone
119+
120+
assert len(users) == user_count - 3
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"CurrentProjectSetting": null
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"ExpandedNodes": [
3+
""
4+
],
5+
"PreviewInSolutionExplorer": false
6+
}

APIs/demo-api/.vs/demo-api/v15/.suo

12.5 KB
Binary file not shown.

APIs/demo-api/.vs/slnx.sqlite

416 KB
Binary file not shown.

APIs/demo-api/.vscode/launch.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Python: Current File",
9+
"type": "python",
10+
"request": "launch",
11+
"program": "${file}",
12+
"console": "integratedTerminal"
13+
}
14+
]
15+
}

0 commit comments

Comments
 (0)