From f335feba101e5909b26c15dd62482f3dff22a964 Mon Sep 17 00:00:00 2001 From: Keith Galli Date: Sat, 21 Oct 2023 11:56:07 -0400 Subject: [PATCH 1/5] Template code for lunch and learn --- app.py | 98 +------------------------------------------------- book_review.py | 54 ---------------------------- 2 files changed, 1 insertion(+), 151 deletions(-) delete mode 100644 book_review.py diff --git a/app.py b/app.py index 997d548..4f1930b 100644 --- a/app.py +++ b/app.py @@ -2,8 +2,6 @@ from flask_restful import Api, Resource from flasgger import Swagger -import book_review - app = Flask(__name__) api = Api(app) swagger = Swagger(app) @@ -35,102 +33,8 @@ def get(self): """ text = request.args.get('text') - return jsonify({"text": text.upper()}) - -class Records(Resource): - def get(self): - """ - This method responds to the GET request for returning a number of books. - --- - tags: - - Records - parameters: - - name: count - in: query - type: integer - required: false - description: The number of books to return - - name: sort - in: query - type: string - enum: ['ASC', 'DESC'] - required: false - description: Sort order for the books - responses: - 200: - description: A successful GET request - schema: - type: object - properties: - books: - type: array - items: - type: object - properties: - title: - type: string - description: The title of the book - author: - type: string - description: The author of the book - """ - - count = request.args.get('count') # Default to returning 10 books if count is not provided - sort = request.args.get('sort') - - # Get all the books - books = book_review.get_all_records(count=count, sort=sort) - - return {"books": books}, 200 + return {"text": text.upper()}, 200 -class AddRecord(Resource): - def post(self): - """ - This method responds to the POST request for adding a new record to the DB table. - --- - tags: - - Records - parameters: - - in: body - name: body - required: true - schema: - id: BookReview - required: - - Book - - Rating - properties: - Book: - type: string - description: the name of the book - Rating: - type: integer - description: the rating of the book (1-10) - responses: - 200: - description: A successful POST request - 400: - description: Bad request, missing 'Book' or 'Rating' in the request body - """ - - data = request.json - print(data) - - # Check if 'Book' and 'Rating' are present in the request body - if 'Book' not in data or 'Rating' not in data: - return {"message": "Bad request, missing 'Book' or 'Rating' in the request body"}, 400 - # Call the add_record function to add the record to the DB table - success = book_review.add_record(data) - - if success: - return {"message": "Record added successfully"}, 200 - else: - return {"message": "Failed to add record"}, 500 - - - -api.add_resource(AddRecord, "/add-record") -api.add_resource(Records, "/records") api.add_resource(UppercaseText, "/uppercase") if __name__ == "__main__": diff --git a/book_review.py b/book_review.py deleted file mode 100644 index dd0725d..0000000 --- a/book_review.py +++ /dev/null @@ -1,54 +0,0 @@ -import os -from pyairtable import Api - -API_TOKEN = os.environ.get('AIRTABLE_TOKEN') - -BASE_ID = 'appi1uzlLKn1TEKSw' -TABLE_ID = 'tblvMMAVHo901m2Ra' - -api = Api(API_TOKEN) - -table = api.table(BASE_ID, TABLE_ID) - -def get_all_records(count=None, sort=None): - sort_param = [] - if sort and sort.upper()=='DESC': - sort_param = ['-Rating'] - elif sort and sort.upper()=='ASC': - sort_param = ['Rating'] - - return table.all(max_records=count, sort=sort_param) - -def get_record_id(name): - return table.first(formula=f"Book='{name}'")['id'] - -def update_record(record_id, data): - table.update(record_id, data) - - return True - -def add_record(data): - # require data contains a "Book" key and a "Rating" key (data is a dict) - if 'Book' not in data or 'Rating' not in data: - return False - - table.create(data) - return True - -if __name__ == '__main__': - ## Show getting certain records - print("Show getting certain records") - print(table.all(formula="Rating < 5", sort=['-Rating'])) - - ## Show getting a single record - print("Show getting a single record") - - # Replace a record - print("Replace a record") - name = "Test Message" - record_id = table.first(formula=f"Book='{name}'")['id'] - table.update(record_id, {"Rating": 5}) - - ## Show all records - print("All records!") - print(table.all()) \ No newline at end of file From 93a9feb25025efc1fcd3bcb8ca067a41a7215442 Mon Sep 17 00:00:00 2001 From: Keith Galli Date: Sat, 21 Oct 2023 14:03:27 -0400 Subject: [PATCH 2/5] Update README.md --- README.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bdcf71..9616225 100644 --- a/README.md +++ b/README.md @@ -1 +1,27 @@ -# Python API Example +# Building and deploying a Python API + +### About + +In this session we will build some API endpoints, documentation for those endpoints, and the ability to test on a live site deploying on render.com. This is a simple example to get started, but hopefully it will provide the foundation for you all to build more complex APIs in the future. If you have any questions, I recommend leaving them on the YouTube recording of the lunch & learn on Tina's channel. + +### Setup + +1. **Clone the repository**: + ```bash + git clone -b lunch-and-learn https://github.com/KeithGalli/python-api-example.git + ``` +2. **Navigate to directory** + ```bash + cd python-api-example + ``` +3. **Install Python libraries** + ```bash + pip install -r requirements.txt + +4. **Run Flask Endpoint** + ```bash + python3 app.py + ``` + +5. **Navigate to server**
+ Open up URL app is running on (should say when you run above command -- http://127.0.0.1:5000 for example). Navigate to http://127.0.0.1:5000/apidocs to see Swagger endpoint specs. From 8144d0316f2021e783285bcedd4f7d9ec8fb5591 Mon Sep 17 00:00:00 2001 From: Keith Galli Date: Sat, 21 Oct 2023 14:26:11 -0400 Subject: [PATCH 3/5] Update README.md --- README.md | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9616225..97dc57f 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,47 @@ # Building and deploying a Python API -### About +## About In this session we will build some API endpoints, documentation for those endpoints, and the ability to test on a live site deploying on render.com. This is a simple example to get started, but hopefully it will provide the foundation for you all to build more complex APIs in the future. If you have any questions, I recommend leaving them on the YouTube recording of the lunch & learn on Tina's channel. -### Setup +## Setup +1. **Fork the repository**: + Click on the 'Fork' button at the top right corner of the repository's GitHub page. This will create a copy of the repository in your own GitHub account. -1. **Clone the repository**: +2. **Clone your forked repository**: + Make sure to replace YOUR_GITHUB_USERNAME with your username in this command ```bash - git clone -b lunch-and-learn https://github.com/KeithGalli/python-api-example.git - ``` -2. **Navigate to directory** + git clone -b lunch-and-learn https://github.com/YOUR_GITHUB_USERNAME/python-api-example.git + +3. **Navigate to directory** ```bash cd python-api-example ``` -3. **Install Python libraries** +4. **Install Python libraries** ```bash pip install -r requirements.txt -4. **Run Flask Endpoint** +5. **Run Flask Endpoint** ```bash python3 app.py ``` -5. **Navigate to server**
+6. **Navigate to server**
Open up URL app is running on (should say when you run above command -- http://127.0.0.1:5000 for example). Navigate to http://127.0.0.1:5000/apidocs to see Swagger endpoint specs. + +7. **Making changes and pushing to your fork**
+ After making your changes, you can push them to your forked GitHub repository. + ```bash + git add -u + git commit -m "Your commit message" + git push origin lunch-and-learn + ``` + + +## Render.com + +We will be using [render.com](https://render.com) to deploy our app. Create an account there and connect your Github using the [following instructions](https://render.com/docs/github) + +## Airtable + +As a very simple and easy to set-up DB, we will be using airtable. I'll show in the live stream how to create an API token to use in Python API requests. From dd3981919465bc730e6c77b8951ec97e2c2f9462 Mon Sep 17 00:00:00 2001 From: Keith Galli Date: Sat, 21 Oct 2023 15:48:54 -0400 Subject: [PATCH 4/5] Final API endpoint code --- app.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++-- requirements.txt | 2 +- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index 4f1930b..cbacaff 100644 --- a/app.py +++ b/app.py @@ -14,7 +14,7 @@ def get(self): tags: - Text Processing parameters: - - name: text + - name: message in: query type: string required: true @@ -35,7 +35,58 @@ def get(self): return {"text": text.upper()}, 200 +class StringGenerator(Resource): + def get(self): + """ + This method responds to the GET request for this endpoint and generates a modified string. + --- + tags: + - Text Processing + parameters: + - name: message + in: query + type: string + required: true + description: The text to be processed + - name: duplication_factor + in: query + type: integer + required: false + description: Number of times to duplicate the text (default is 1) + - name: capitalization + in: query + type: string + required: false + enum: [UPPER, LOWER] + description: Capitalization of the text (default is no change) + responses: + 200: + description: A successful GET request + content: + application/json: + schema: + type: object + properties: + generated_text: + type: string + description: The generated text + """ + args = request.args + message = args['message'] + duplication_factor = int(args.get('duplication_factor', 1)) + capitalization = args.get('capitalization', None) + + if capitalization == 'UPPER': + message = message.upper() + elif capitalization == 'LOWER': + message = message.lower() + + generated_text = message * duplication_factor + + return {"generated_text": generated_text}, 200 + +api.add_resource(StringGenerator, "/generate") api.add_resource(UppercaseText, "/uppercase") if __name__ == "__main__": - app.run(debug=True) \ No newline at end of file + app.run(debug=True) diff --git a/requirements.txt b/requirements.txt index edd09fa..7afeaa2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ flask flasgger flask_restful pyairtable -gunicorn \ No newline at end of file + From 5844dd24f5ab798905a8344302e083682a4c26af Mon Sep 17 00:00:00 2001 From: Keith Galli Date: Sat, 21 Oct 2023 15:53:52 -0400 Subject: [PATCH 5/5] Adding gunicorn) --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 7afeaa2..61a6683 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ flask flasgger flask_restful pyairtable +gunicorn