-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdemo_pythonanywhere_com.py
More file actions
168 lines (145 loc) · 6.46 KB
/
Copy pathdemo_pythonanywhere_com.py
File metadata and controls
168 lines (145 loc) · 6.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# This script is deployed on thomaxxl.pythonanywhere.com
#
# This is a demo application to demonstrate the functionality of the safrs_rest REST API
#
# It can be ran standalone like this:
# python demo_relationship.py [Listener-IP]
#
# This will run the example on http://Listener-Ip:5000
#
# - A database is created and a person is added
# - A rest api is available
# - swagger2 documentation is generated
# - Flask-Admin frontend is created
# - jsonapi-admin pages are served
#
import sys
from flask import Flask, render_template, Flask, redirect, send_from_directory
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask_cors import CORS
from flask_admin import Admin, BaseView
from flask_admin.contrib import sqla
from safrs import SAFRSBase, jsonapi_rpc, SAFRSJSONEncoder, Api, SAFRS
from safrs import search, startswith
app = Flask('SAFRS Demo App', template_folder='/home/thomaxxl/mysite/templates')
app.secret_key ='not so secret'
CORS( app,
origins="*",
allow_headers=[ "Content-Type", "Authorization", "Access-Control-Allow-Credentials"],
supports_credentials = True)
app.config.update( SQLALCHEMY_DATABASE_URI = 'sqlite://',
DEBUG = True ) # DEBUG will also show safrs log messages + exception messages
db = SQLAlchemy(app)
prefix = '/api'
SAFRS(app, db, prefix = prefix)
# Add search and startswith methods so we can perform lookups from the frontend
SAFRSBase.search = search
SAFRSBase.startswith = startswith
# Needed because we don't want to implicitly commit when using flask-admin
SAFRSBase.db_commit = False
class Book(SAFRSBase, db.Model):
'''
description: Book description
'''
__tablename__ = 'Books'
id = db.Column(db.String, primary_key=True)
title = db.Column(db.String, default = '')
reader_id = db.Column(db.String, db.ForeignKey('People.id'))
author_id = db.Column(db.String, db.ForeignKey('People.id'))
publisher_id = db.Column(db.String, db.ForeignKey('Publishers.id'))
publisher = db.relationship('Publisher', back_populates='books')
reviews = db.relationship('Review', backref="book", cascade="save-update, merge, delete, delete-orphan")
class Person(SAFRSBase, db.Model):
'''
description: People description
'''
__tablename__ = 'People'
id = db.Column(db.String, primary_key=True)
name = db.Column(db.String, default = '')
email = db.Column(db.String, default = '')
comment = db.Column(db.Text, default = '')
books_read = db.relationship('Book', backref = "reader", foreign_keys = [Book.reader_id], cascade="save-update, merge, delete, delete-orphan")
books_written = db.relationship('Book', backref = "author", foreign_keys = [Book.author_id])
reviews = db.relationship('Review', backref = "reader")
# Following method is exposed through the REST API
# This means it can be invoked with a HTTP POST
@classmethod
@jsonapi_rpc(http_methods = ['POST'])
def send_mail(self, email):
'''
description : Send an email
args:
email:
type : string
example : test email
'''
content = 'Mail to {} : {}\n'.format(self.name, email)
with open('/tmp/mail.txt', 'a+') as mailfile :
mailfile.write(content)
return { 'result' : 'sent {}'.format(content)}
class Publisher(SAFRSBase, db.Model):
'''
description: Publisher description
'''
__tablename__ = 'Publishers'
id = db.Column(db.Integer, primary_key=True) # Integer pk instead of str
name = db.Column(db.String, default = '')
books = db.relationship('Book', back_populates = "publisher")
class Review(SAFRSBase, db.Model):
'''
description: Review description
'''
__tablename__ = 'Reviews'
reader_id = db.Column(db.String, db.ForeignKey('People.id',ondelete="CASCADE"), primary_key=True)
book_id = db.Column(db.String, db.ForeignKey('Books.id'), primary_key=True)
review = db.Column(db.String, default = '')
def start_api(HOST = '0.0.0.0' ,PORT = None):
db.create_all()
with app.app_context():
# populate the database
for i in range(300):
reader = Person(name='Reader '+str(i), email="reader_email"+str(i) )
author = Person(name='Author '+str(i), email="author_email"+str(i) )
book = Book(title='book_title' + str(i))
review = Review(reader_id=reader.id, book_id=book.id, review='review ' + str(i))
publisher = Publisher(name = 'name' + str(i))
publisher.books.append(book)
reader.books_read.append(book)
author.books_written.append(book)
db.session.add(reader)
db.session.add(author)
db.session.add(book)
db.session.add(publisher)
db.session.add(review)
db.session.commit()
swagger_host = HOST
if PORT and PORT != 80:
swagger_host += ':{}'.format(PORT)
api = Api(app, api_spec_url = '/api/swagger', host = swagger_host, schemes = [ "http", "https" ], description = description )
# Flask-Admin Config
admin = Admin(app, url='/admin')
for model in [ Person, Book, Review, Publisher] :
# add the flask-admin view
admin.add_view(sqla.ModelView(model, db.session))
# Create an API endpoint
api.expose_object(model)
@app.route('/ja')
@app.route('/ja/<path:path>', endpoint="jsonapi_admin")
def send_ja(path='index.html'):
return send_from_directory('/home/thomaxxl/mysite/jsonapi-admin/build', path)
@app.route('/')
def goto_api():
return redirect(prefix)
description = '''<a href=http://jsonapi.org>Json-API</a> compliant API built with https://github.com/thomaxxl/safrs <br/>
- <a href="https://github.com/thomaxxl/safrs/blob/master/examples/demo_pythonanywhere_com.py">Source code of this page</a> (only 150 lines!)<br/>
- <a href="http://thomaxxl.pythonanywhere.com/ja/index.html">reactjs+redux frontend</a>
- <a href="/admin/person">Flask-Admin frontend</a>
- Auto-generated swagger spec: <a href=/api/swagger.json>swagger.json</a><br/>
- Petstore <a href=http://petstore.swagger.io/?url=http://thomaxxl.pythonanywhere.com/api/swagger.json>Swagger2 UI</a><br/>
'''
if __name__ == '__main__':
HOST = sys.argv[1] if len(sys.argv) > 1 else 'thomaxxl.pythonanywhere.com'
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 5000
start_api(HOST,PORT)
app.run(host=HOST, port=PORT)