Building a REST API with Flask-RESTx and Swagger Documentation

In this tutorial, we'll create a simple REST API to manage contacts. The API will include fields for name, email, and a subscription indicator to track whether a contact has subscribed to our newsletter. We'll use Flask-RESTx, which can automatically generate Swagger documentation for this API. The documentation will make it easier for developers to understand and interact with the API endpoints.

The API will cover the following operations:

  • GET requests to retrieve contact information

  • POST requests to add new contacts

  • PUT requests to update existing contact details

  • DELETE requests to remove contacts

Set Up the Flask Environment in Windows

You can use the same environment that you used for https://techdineshwrites.hashnode.dev/building-your-first-rest-api-using-flask

If the virtual environment isn’t activated, activate it and install Flask-RESTx by typing the command: pip install flask-restx

Create the Flask Application

Step 1: Create a file named contacts.py.

Step 2: Import necessary components and create an instance of the Flask class:

from flask import Flask, request
from flask_restx import Api, Resource, fields

app = Flask(__name__)

Step 3: Initialize the Flask-RESTx API:

api = Api(app, version='1.0', title="Dinesh's Contact Management API", description='Add, see, update, and remove your contacts.')

Step 4: Define a namespace for the API:

ns = api.namespace('contacts', description='Contact operations')
  • ns: This is a variable that stores the namespace instance. You can name this variable anything you like.

  • api.namespace('contacts', ...): This method creates a namespace with the path contacts. This means all endpoints defined under this namespace will be prefixed with /contacts.

A namespace helps organize your API endpoints under a common group, making it easier to manage and document them. Additionally, namespaces improve the auto-generated Swagger documentation by categorizing endpoints.

Step 5: Define the contact model:

contact_model = api.model('Contact', {
    'id': fields.Integer(readOnly=True, description='The contact unique identifier.'),
    'name': fields.String(required=True, description='The contact name.'),
    'email': fields.String(required=True, description='The contact email.'),
    'subscribed': fields.Boolean(description='Indicates whether the contact is subscribed to promotional messages. Valid values are true or false.')
})

When you define this model in Flask-RESTx, it automatically includes this model in the Swagger documentation, making it clear what kind of data your endpoints expect.

Step 6: Create an empty list to store contacts temporarily:

contacts = []

Step 7: Define the ContactList resource and its endpoints:

@ns.route('/')
class ContactList(Resource):
    @ns.doc('list_contacts', description='Retrieves a list of all contacts.')
    @ns.marshal_list_with(contact_model)
    def get(self):
        return contacts

    @ns.doc('create_contact', description='Creates a new contact.')
    @ns.expect(contact_model)
    @ns.marshal_with(contact_model, code=201)
    def post(self):
        new_contact = api.payload
        new_contact['id'] = len(contacts) + 1
        contacts.append(new_contact)
        return new_contact, 201
  • This resource has two main methods: get (retrieves the full list of contacts) and post (adds a new contact to the list).

  • The ns.doc decorator adds descriptions to the get and post operations, enhancing the auto-generated documentation.

  • The ns.marshal decorator specifies that the output will be in the format defined by the contact_model.

  • ns.expect specifies that the request body must follow the contact_model, ensuring that the incoming data matches the defined schema.

Step 8: Define the Contact resource and its endpoints:

@ns.route('/<int:id>')
@ns.response(404, 'Contact not found')
@ns.param('id', 'The contact identifier')
class Contact(Resource):
    @ns.doc('get_contact', description='Retrieves the contact information by contact ID.')
    @ns.marshal_with(contact_model)
    def get(self, id):
        for contact in contacts:
            if contact['id'] == id:
                return contact
        api.abort(404)

    @ns.doc('delete_contact', description='Deletes the contact by contact ID.')
    @ns.response(204, 'Contact deleted')
    def delete(self, id):
        global contacts
        contacts = [contact for contact in contacts if contact['id'] != id]
        return '', 204

    @ns.doc('update_contact', description='Updates the contact information by contact ID.')
    @ns.expect(contact_model)
    @ns.marshal_with(contact_model)
    def put(self, id):
        for contact in contacts:
            if contact['id'] == id:
                contact.update(api.payload)
                return contact
        api.abort(404)

This resource has three main methods: get (retrieves the contact information by contact ID), delete (deletes the contact by contact ID), and put (updates the contact information by contact ID).

Step 9: Add the namespace to the API to ensure that endpoints, such as GET /contacts, can be accessed through the API:

api.add_namespace(ns)

Step 10: Ensure that the Flask application will start running with debug mode enabled when you run the contacts.py file:

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

Run the Application

On Visual Studio Code, click Run for contacts.py. This will launch the server locally:

Access the Swagger Documentation

Once the server is running, you can access the automatically generated Swagger documentation by navigating to http://127.0.0.1:5000/ in your web browser.

Click Models, then Contact: The expanded view will show you the fields that make up the model, along with their data types and descriptions.

Expand Contacts to see all the API endpoints, such as GET /contacts:

Click on the desired endpoint to expand it. For example, click on POST /contacts to see the post operation’s description and example of the JSON object that you would send:

You can also see the example response:

Try it Out

You can use the Try it out feature for all operations in the Swagger documentation. This feature allows you to interact with the API directly from the documentation interface. Let’s add a contact:

Step 1: Click Try it out for the post operation. You'll see fields where you can enter data.

Step 2: Add the contact details in the Payload field:

Step 3: Click Execute.

If successful, you'll get a 201 status code along with the details of the newly created contact:

Step 4: We'll add another contact for this example:

Step 5: Expand the GET /contacts endpoint:

Step 6: Click Try it out for the get operation.

Step 7: Click Execute to send a request to the endpoint.

The response body will display the data retrieved by the GET /contacts operation.

The response body will show the retrieved information for both contacts we added, and indicate a 200 status code:

The 200 status indicates that the request was successful, and the server has returned the requested data.

Step 8: Let’s say you want to update email from Emma@example.com to Emma.Miller@example.com. Expand the PUT /contacts/{id} endpoint.

Step 9: Click Try it out.

Step 10: Enter the ID of the contact whose email you want to change:

Step 11: In the request body, enter the new email address along with any other details you want to keep unchanged:

Step 12: Click Execute.

The response body will show the updated contact information, and you'll receive a 200 status code indicating that the update is successful:

Nicely done! By using this tutorial, we successfully created a Contact Management API using Flask that handles GET, POST, PUT, and DELETE requests. We also auto-generated Swagger documentation that provides information about the API and allows users to interact with the API.