# Serve OpenAPI spec document endpoint for download
@app.route("/openapi.yaml")
def openapi_yaml():
    spec = api.spec.to_dict()
    return app.response_class(
        yaml.dump(spec, default_flow_style=False),
        mimetype="application/x-yaml"
    )

if __name__ == "__main__":
    with app.app_context():
        db.create_all()  # Create database tables
    app.run(debug=True)
```

### Database

Here, you will see a method call to create a SQLite database and a function to run the Flask app:

```python mark=54,55
if __name__ == "__main__":
    with app.app_context():
        db.create_all()  # Create database tables
    app.run(debug=True)
```

### Models

From the root of the repository, open the `models.py` file to see a `Book` model containing a few fields with validation:

```python
from db import db

class Book(db.Model):
    __tablename__ = "books"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80), nullable=False)
    author = db.Column(db.String(80), nullable=False)
    description = db.Column(db.String(200))
```

### Schemas

In the `schemas.py` file, the `BookSchema` class can be used to serialize and deserialize book data with the `marshmallow` package:

```python
from marshmallow import Schema, fields

class BookSchema(Schema):
    id = fields.Int(dump_only=True)
    title = fields.Str(required=True)
    author = fields.Str(required=True)
    description = fields.Str()
```

### Resources

The `resources.py` file contains API endpoints set up to handle all the CRUD operations for the books:

```python
from flask.views import MethodView
from flask_smorest import Blueprint, abort
from sqlalchemy.exc import IntegrityError
from db import db
from models import Book
from schemas import BookSchema

blp = Blueprint("Books", "books", url_prefix="/books", description="Operations on books")

@blp.route("/")
class BookList(MethodView):
    @blp.response(200, BookSchema(many=True))
    @blp.paginate()
    def get(self, pagination_parameters):
        """List all books"""
        query = Book.query
        paginated_books = query.paginate(
            page=pagination_parameters.page,
            per_page=pagination_parameters.page_size,
            error_out=False
        )
        pagination_parameters.item_count = paginated_books.total
        return paginated_books.items

    @blp.arguments(BookSchema)
    @blp.response(201, BookSchema)
    def post(self, new_data):
        """Create a new book"""
        book = Book(**new_data)
        db.session.add(book)
        db.session.commit()
        return book

@blp.route("/<int:book_id>")
class BookDetail(MethodView):
    @blp.response(200, BookSchema)
    def get(self, book_id):
        """Return books based on ID.
        ---
        Internal comment not meant to be exposed.
        """
        book = Book.query.get_or_404(book_id)
        return book

    @blp.arguments(BookSchema)
    @blp.response(200, BookSchema)
    def put(self, updated_data, book_id):
        """Update an existing book"""
        book = Book.query.get_or_404(book_id)
        book.title = updated_data["title"]
        book.author = updated_data["author"]
        book.description = updated_data.get("description")
        db.session.commit()
        return book

    def delete(self, book_id):
        """Delete a book"""
        book = Book.query.get_or_404(book_id)
        db.session.delete(book)
        db.session.commit()
        return {"message": "Book deleted"}, 204
```


This code defines a simple Flask REST API with CRUD operations for a `Book` model. The `BookList` class provides a way to retrieve all book data and create new books. The `BookDetail` class handles the retrieval of specific books, updating book data, and deleting books.

## Generate the OpenAPI document using `flask-smorest`

Flask does not support OpenAPI document generation out-of-the-box, so we'll use the `flask-smorest` package to generate the OpenAPI document.

If you are following along with the example repository, you can create and activate a virtual environment to install the project dependencies:

```bash filename="Terminal"
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```

If you have not already, install `flask-smorest` with the following command:

```bash filename="Terminal"
pip install flask-smorest
```


### Configuration

The most basic configuration for generating an OpenAPI document with `flask-smorest` is added in the `app.py` file:

```python
app.config["API_TITLE"] = "Library API"
app.config["API_VERSION"] = "v0.0.1"
app.config["OPENAPI_VERSION"] = "3.1.0"
app.config["OPENAPI_DESCRIPTION"] = "A simple library API"
```

### SwaggerUI

The new Swagger UI endpoint is also added in the `app.py` file:

```python mark=14
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
```

### Server

The `app.py` file contains additional configuration settings for the OpenAPI document. These add a development server:

```python