02-Claude Finished Notes ..


Learning Goals


Key Vocab

Term Definition
REST A convention for developing applications that use HTTP in a consistent, human-readable, machine-readable way.
API A software application that allows two or more software applications to communicate with one another.
GET The most common HTTP request method. Signifies the client is attempting to view a resource.
POST Signifies the client is attempting to create a new resource.
PATCH Signifies the client is attempting to partially update a resource.
PUT Signifies the client is attempting to fully update a resource.
DELETE Signifies the client is attempting to delete a resource.

Introduction

Flask is already great for building RESTful APIs, but Flask-RESTful makes it even easier. It's an extension that provides the Api and Resource classes, reducing boilerplate and enforcing RESTful structure.


Flask-RESTful: Core Concepts

Api and Resource

What's Different from Vanilla Flask?

Vanilla Flask Flask-RESTful
@app.route('/path', methods=['GET']) decorator class MyResource(Resource) + api.add_resource()
One function per route One class per URL, methods as instance methods
Manual JSON responses Still manual, but structure is cleaner

⚠️ If you add non-RESTful views, you still need @app.route() for those.


Getting Started

1. Environment Setup

# From project root
pipenv shell

# Move into server directory
cd server

# Set Flask env vars
export FLASK_APP=app.py
export FLASK_RUN_PORT=5555

2. Initial app.py — Bare Bones Setup + Home Resource

Open server/app.py and add:

#!/usr/bin/env python3

from flask import Flask, request, make_response
from flask_migrate import Migrate
from flask_restful import Api, Resource

from models import db, Newsletter

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///newsletters.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.json.compact = False

migrate = Migrate(app, db)
db.init_app(app)

api = Api(app)


class Home(Resource):

    def get(self):
        response_dict = {
            "message": "Welcome to the Newsletter RESTful API",
        }
        response = make_response(response_dict, 200)
        return response


api.add_resource(Home, '/')


if __name__ == '__main__':
    app.run(port=5555, debug=True)

Run the app:

flask run
# or
python app.py

Visit http://127.0.0.1:5555/ — you should see:

{
  "message": "Welcome to the Newsletter RESTful API"
}

3. Create the DB and Seed It

flask db upgrade
python seed.py

Retrieving Records — GET /newsletters

Add the Newsletters resource below Home in app.py:

class Newsletters(Resource):

    def get(self):
        response_dict_list = [n.to_dict() for n in Newsletter.query.all()]
        response = make_response(response_dict_list, 200)
        return response


api.add_resource(Newsletters, '/newsletters')

Visit http://127.0.0.1:5555/newsletters — you should see all newsletter records:

[
  {
    "body": "Create southern girl news...",
    "edited_at": null,
    "id": 1,
    "published_at": "2022-09-21 18:35:17",
    "title": "Establish they."
  },
  {
    "body": "Really attack we ground production game...",
    "edited_at": null,
    "id": 2,
    "published_at": "2022-09-21 18:35:17",
    "title": "Plan wonder manage."
  }
]

Creating Records — POST /newsletters

Add a post method inside the existing Newsletters class:

class Newsletters(Resource):

    def get(self):
        response_dict_list = [n.to_dict() for n in Newsletter.query.all()]
        response = make_response(response_dict_list, 200)
        return response

    def post(self):
        new_record = Newsletter(
            title=request.form['title'],
            body=request.form['body'],
        )

        db.session.add(new_record)
        db.session.commit()

        response_dict = new_record.to_dict()
        response = make_response(response_dict, 201)
        return response


api.add_resource(Newsletters, '/newsletters')  # only call add_resource ONCE

✅ You do NOT call api.add_resource() twice. Both GET and POST live in the same class under the same URL.

Test in Postman:

⚠️ form-data doesn't use quotes for strings — it'll throw an error if you include them.

Expected response (201):

{
  "body": "Some content here",
  "edited_at": null,
  "id": 21,
  "published_at": "2022-09-21 18:35:17",
  "title": "My Newsletter"
}

Retrieving a Single Record — GET /newsletters/<id>

You need a new Resource class for this because:

  1. A GET already exists at /newsletters
  2. This endpoint needs an id in the URL

Add below Newsletters:

class NewsletterByID(Resource):

    def get(self, id):
        response_dict = Newsletter.query.filter_by(id=id).first().to_dict()
        response = make_response(response_dict, 200)
        return response


api.add_resource(NewsletterByID, '/newsletters/<int:id>')

Test in Postman:

Expected response:

{
  "body": "College tax head change. Claim exactly because choose. Church edge center across test stock.",
  "edited_at": null,
  "id": 20,
  "published_at": "2022-09-21 18:35:17",
  "title": "Court probably not."
}

Full app.py — Complete Solution

#!/usr/bin/env python3

from flask import Flask, request, make_response
from flask_migrate import Migrate
from flask_restful import Api, Resource

from models import db, Newsletter

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///newsletters.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.json.compact = False

migrate = Migrate(app, db)
db.init_app(app)

api = Api(app)


class Home(Resource):

    def get(self):
        response_dict = {
            "message": "Welcome to the Newsletter RESTful API",
        }
        response = make_response(response_dict, 200)
        return response


api.add_resource(Home, '/')


class Newsletters(Resource):

    def get(self):
        response_dict_list = [n.to_dict() for n in Newsletter.query.all()]
        response = make_response(response_dict_list, 200)
        return response

    def post(self):
        new_record = Newsletter(
            title=request.form['title'],
            body=request.form['body'],
        )
        db.session.add(new_record)
        db.session.commit()

        response_dict = new_record.to_dict()
        response = make_response(response_dict, 201)
        return response


api.add_resource(Newsletters, '/newsletters')


class NewsletterByID(Resource):

    def get(self, id):
        response_dict = Newsletter.query.filter_by(id=id).first().to_dict()
        response = make_response(response_dict, 200)
        return response


api.add_resource(NewsletterByID, '/newsletters/<int:id>')


if __name__ == '__main__':
    app.run(port=5555, debug=True)

Route Summary

Resource Class URL Methods Description
Home / GET Welcome message
Newsletters /newsletters GET Return all newsletters
Newsletters /newsletters POST Create a new newsletter
NewsletterByID /newsletters/<int:id> GET Return one newsletter by ID

Key Patterns to Remember

# 1. Always import Api and Resource from flask_restful
from flask_restful import Api, Resource

# 2. Initialize the Api with the Flask app
api = Api(app)

# 3. Each URL group = one Resource class
class MyResource(Resource):
    def get(self):   # handles GET
        pass
    def post(self):  # handles POST
        pass

# 4. Register the class with a URL — only once per class
api.add_resource(MyResource, '/my-url')

# 5. Dynamic URLs use <type:param> syntax, matched in method args
class MyResourceByID(Resource):
    def get(self, id):  # id comes from the URL
        pass

api.add_resource(MyResourceByID, '/my-url/<int:id>')

Resources

Connected Pages
02-Claude Finished Notes ..
  • Learning Goals
  • Key Vocab
  • Introduction
  • Flask-RESTful: Core Concepts
    1. Api and Resource
    2. What's Different from Vanilla Flask?
  • Getting Started
    1. 1. Environment Setup
    2. 2. Initial app.py — Bare Bones Setup + Home Resource
    3. 3. Create the DB and Seed It
  • Retrieving Records — GET /newsletters
  • Creating Records — POST /newsletters
  • Retrieving a Single Record — GET /newsletters/
  • Full app.py — Complete Solution
  • Route Summary
  • Key Patterns to Remember
  • Resources
  • Powered by Forestry.md