{ "info": { "author": "Bill Rao", "author_email": "billrao@me.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# flask-boiler\n\nFlask-boiler helps you build fast-prototype of your backend. \n\n## Architecture Diagram\n\nYou may structure your project in this way:\n\n![architecture diagrama](https://www.lucidchart.com/publicSegments/view/76e8c8d4-a356-46ed-af95-e079d38a7bd7/image.png)\n\n## Features\n\n### Context Management\n\nIn ```__init__``` of your project source root: \n```python\nimport os\n\nfrom flask_boiler import context\nfrom flask_boiler import config\n\nConfig = config.Config\n\ntesting_config = Config(app_name=\"your_app_name\",\n debug=True,\n testing=True,\n certificate_path=os.path.curdir + \"/../your_project/config_jsons/your_certificate.json\")\n\nCTX = context.Context\nCTX.read(testing_config)\n```\n\nNote that initializing ```Config``` with ```certificate_path``` is unstable and \nmay be changed later. \n\nIn your project code, \n\n```python\nfrom flask_boiler import context\n\nCTX = context.Context\n\n# Retrieves firestore database instance \nCTX.db\n\n# Retrieves firebase app instance \nCTX.firebase_app\n\n```\n\n### ORM\n\n```python\n\nfrom flask_boiler.factory import ClsFactory\nfrom flask_boiler import schema, fields \n\n\n# Creates a schema for serializing and deserializing to firestore database\nclass TestObjectSchema(schema.Schema):\n \n # Describes how obj.int_a is read from and stored to a document in firestore \n int_a = fields.Raw(\n load_from=\"intA\", # reads obj.int_a from firestore document field \"intA\" \n dump_to=\"intA\" # stores the value of obj.int_a to firestore document field \"intA\" \n )\n int_b = fields.Raw(load_from=\"intB\", dump_to=\"intB\")\n\n\n# Declares the object\nTestObject = ClsFactory.create(\n name=\"TestObject\",\n schema=TestObjectSchema,\n # Either MyDomainModelBase (specify cls._collection_id)\n # or SubclassOfViewModel \n # TODO: ADD MORE DOCS \n base=PrimaryObject \n)\n\n# Creates an object with default values with reference: \"TestObject/testObjId1\" \n# (but not saved to database)\nobj = TestObject.create(doc_id=\"testObjId1\")\n\n# Assigns value to the newly created object \nobj.int_a = 1\nobj.int_b = 2\n\n# Saves to firestore \"TestObject/testObjId1\" \nobj.save()\n\n# Gets the object from firestore \"TestObject/testObjId1\" \nretrieved_obj = TestObject.get(doc_id=\"testObjId1\")\n\n# Access values of the object retrieved \nassert retrieved_obj.int_a == 1\nassert retrieved_obj.int_b == 2\n\n# Deletes the object from firestore \"TestObject/testObjId1\" \nretrieved_obj.delete()\n```\n\n## Architecture Discussion\n\n### Disambiguation \n\nThere are 2+ ways to run the view layer. \n1. Document-As-View: Persist all view models to firestore, and client reads/writes to firestore. \n\n * Document is refreshed every time the bounding domain models change \n * Firestore serves Document at near 0 latency (cached) if the client attaches a listener \n to the view model\n * Performance depends on **how often the domain model is changed**\n \n2. Flask-As-View: only the binding structure is persisted, and client reads/writes to flask REST API resources. \n\n * Bounding domain models are read every time the client requests the resource \n * May experience latency, but overall lower in server cost since the ViewModel is not persisted\n * Performance depends on **how often the view model is read** \n \n3. A combination of 1 and 2: build read-intensive microservices with Document-As-View \n and change-intensive microservices with Flask-As-View. \n\nFlask-boiler is mostly for building a fast prototype of your backend. As you keep \ndeveloping your product, we recommend that you switch to a relational database for \nyour domain model layer if your data has many references, and WebSocket/REST API \nfor view layer. This does not mean that flask-boiler is not runtime efficient, \nbut that simplicity is always a compromise and firestore can be expensive. \n\n### Performance \n\nDocument-As-View has better performance if data is read more than it's changed, and \nthe view models served are limited or specific to a user. \n\nFlask-As-View has better performance when the domain model is \nchanged often, and the client rarely reads all data available \nto a specific user. \n\nFlask-boiler is not a well-tested concept, but criticisms are welcomed. \nAt least, we can strive to build a backend framework that is simple and \nfriendly to beginners who want to prototype their backend easily \nso that they can focus on transforming ideas. \n\n\n## Advantages\n\n### Decoupled Domain Model and View Model\n\nUsing Firebase Firestore sometimes require duplicated fields \nacross several documents in order to both query the data and \ndisplay them properly in front end. Flask-boiler solves this \nproblem by decoupling domain model and view model. View model \nare generated and refreshed automatically as domain model \nchanges. This means that you will only have to write business \nlogics on the domain model without worrying about how the data \nwill be displayed. This also means that the View Models can \nbe displayed directly in front end, while supporting \nreal-time features of Firebase Firestore. \n\n### One-step Configuration\n\nRather than configuring the network and different certificate \nsettings for your database and other cloud services. All you \nhave to do is to enable related services on Google Cloud \nConsole, and add your certificate. Flask-boiler configures \nall the services you need, and expose them as a singleton \nContext object across the project. \n\n### Redundancy\n\nSince all View Models are persisted in Firebase Firestore. \nEven if your App Instance is offline, the users can still \naccess a view of the data from Firebase Firestore. Every \nView is also a Flask View, so you can also access the data \nwith auto-generated REST API, in case Firebase Firestore is \nnot viable. \n\n### Added Safety\n\nBy separating business data from documents that are accessible\nto the front end, you have more control over which data is \ndisplayed depending on the user's role. \n\n### One-step Documentation\n\nAll ViewModels have automatically generated documentations \n(provided by Flasgger). This helps AGILE teams keep their \ndocumentations and actual code in sync. \n\n### Fully-extendable\n\nWhen you need better performance or relational database \nsupport, you can always refactor a specific layer by \nadding modules such as ```flask-sqlalchemy```.", "description_content_type": "text/markdown", "docs_url": null, "download_url": "https://github.com/billyrrr/flask-boiler/archive/v0.0.1a4.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/billyrrr/flask-boiler", "keywords": "firebase,firestore,ORM,flasgger,flask,backend,nosql", "license": "", "maintainer": "", "maintainer_email": "", "name": "flask-boiler", "package_url": "https://pypi.org/project/flask-boiler/", "platform": "", "project_url": "https://pypi.org/project/flask-boiler/", "project_urls": { "Download": "https://github.com/billyrrr/flask-boiler/archive/v0.0.1a4.tar.gz", "Homepage": "https://github.com/billyrrr/flask-boiler" }, "release_url": "https://pypi.org/project/flask-boiler/0.0.1a4/", "requires_dist": null, "requires_python": "", "summary": "Build flask project with Firebase", "version": "0.0.1a4" }, "last_serial": 5768265, "releases": { "0.0.1a2": [ { "comment_text": "", "digests": { "md5": "b3988a82f11209870696dd78037538fe", "sha256": "9129ae8690c723047dd9f48d0082fdf1d7567d7e995dec2a2ea8759650489b9f" }, "downloads": -1, "filename": "flask_boiler-0.0.1a2.tar.gz", "has_sig": false, "md5_digest": "b3988a82f11209870696dd78037538fe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22494, "upload_time": "2019-09-01T20:14:55", "url": "https://files.pythonhosted.org/packages/fc/ba/ffda972c17ff141fdcec70b0cb5da6a148cfee629873b3cf1b932f5c7f5c/flask_boiler-0.0.1a2.tar.gz" } ], "0.0.1a3": [ { "comment_text": "", "digests": { "md5": "0a92f2d5d2dd2d7d7ec799e174451d83", "sha256": "c434bc3d165924556428fd530dfa0ead3af825b91312f13dd1255cb06d38fe83" }, "downloads": -1, "filename": "flask_boiler-0.0.1a3.tar.gz", "has_sig": false, "md5_digest": "0a92f2d5d2dd2d7d7ec799e174451d83", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22813, "upload_time": "2019-09-01T22:17:15", "url": "https://files.pythonhosted.org/packages/fc/41/eb93dbfa2ce76c7137a17147b1b2e8ccc08ee35fa4f080ccfb4ac87ec843/flask_boiler-0.0.1a3.tar.gz" } ], "0.0.1a4": [ { "comment_text": "", "digests": { "md5": "0ea572012f30ca5607d06338210e84ef", "sha256": "bdfe7825cb4a202cf7b1947c6f13fdcc871caa060d5ec9e183bdfec261d962a7" }, "downloads": -1, "filename": "flask_boiler-0.0.1a4.tar.gz", "has_sig": false, "md5_digest": "0ea572012f30ca5607d06338210e84ef", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22816, "upload_time": "2019-09-01T22:28:50", "url": "https://files.pythonhosted.org/packages/25/82/c82795f050a56561fd49be64de2c94e62c9079ff9aaf242d6b8eb1a13445/flask_boiler-0.0.1a4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "0ea572012f30ca5607d06338210e84ef", "sha256": "bdfe7825cb4a202cf7b1947c6f13fdcc871caa060d5ec9e183bdfec261d962a7" }, "downloads": -1, "filename": "flask_boiler-0.0.1a4.tar.gz", "has_sig": false, "md5_digest": "0ea572012f30ca5607d06338210e84ef", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22816, "upload_time": "2019-09-01T22:28:50", "url": "https://files.pythonhosted.org/packages/25/82/c82795f050a56561fd49be64de2c94e62c9079ff9aaf242d6b8eb1a13445/flask_boiler-0.0.1a4.tar.gz" } ] }