Вы находитесь на странице: 1из 24

5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Python REST APIs With Flask, Connexion, and


SQLAlchemy
by Doug Farrell  Jun 11, 2018  65 Comments  api flask intermediate web-dev

Table of Contents
What REST Is
What REST Is Not
The People REST API
Getting Started
Using Connexion to Add a REST API Endpoint
Adding Connexion to the Server
The Swagger Configuration File
Handler for People Endpoint
The Swagger UI
Building Out the Complete API
The Swagger UI Completed
Demonstration Single-Page Application
Static Files
JavaScript File
Demo Application
Example Code
Conclusion

If you’re writing a web application, then you’re probably thinking about making HTTP calls to your server to get data
to populate the dynamic parts of your application.

The goal of this article is to show you how to use Python 3, Flask, and Connexion to build useful REST APIs that can
include input and output validation, and provide Swagger documentation as a bonus. Also included is a simple but
useful single page web application that demonstrates using the API with JavaScript and updating the DOM with it.

The REST API you’ll be building will serve a simple people data structure where the people are keyed to the last name,
and any updates are marked with a new timestamp. Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 1/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

This data could be represented in a database, saved in a file, or be accessible through some network protocol, but for
us an in-memory data structure works fine. One of the purposes of an API is to decouple the data from the application
that uses it, hiding the data implementation details.

Free Bonus: Click here to download a copy of the "REST in a Nutshell" Guide with a hands-on introduction
to REST API principles and examples.

What REST Is
Before you get started creating an API server, I want to talk about REST a little bit. There’s lots of information about
REST available through some quick Google searches, and my intent is not to duplicate that here.Improve Your Python
...with
I just want to share how I view REST and use it to build APIs. I see REST as a set of a fresh 🐍 Python Trick 💌
conventions  
taking advantage of the
HTTP protocol to provide CRUD (Create, Read, Update, and Delete) behavior on code thingssnippet every couple
and collections of days:
of those things.
The CRUD behavior maps nicely to the HTTP protocol method verbs like this:
Email Address
Action HTTP Verb Description

Send Python Tricks »


Create POST Create a new, unique thing

Read GET Read the information about a thing or collection of things

Update PUT Update the information about an existing thing

Delete DELETE Delete a thing

You can perform these actions on a thing or resource. It’s useful to think about a resource as something a noun can be
applied to: a person, an order for something, a person’s address. This idea of a resource lines up nicely with a URL
(Unique Resource Locator).

A URL should identify a unique resource on the web, something that will work with the same thing over and over
again for the same URL. With these two ideas, we have a way to take common application actions on something
uniquely identified on the web. This is a very useful way of working.

This idea goes a long way towards creating clean APIs and performing the actions many applications want from the
API.

What REST Is Not


Because REST is useful and helps map out how we might want to interact with a web based API, it’s sometimes used
for things that don’t really fit well. There are lots of cases where what we want to do is perform some work or take an
action directly. An example might be performing a string substitution, which granted is a silly thing to make an API for,
but let’s go with it for now. Here’s a URL that might be constructed to provide this:

/api/substituteString/<string>/<search_string>/<sub_string>

Here, string is the string to make the substitution in, search_string is the string to replace, and sub_string is the
string to replace search_string with. This can certainly be tied to some code in the server that does the intended
work. But this has some problems in REST terms.

One problem that comes to mind is that this URL doesn’t point to a unique resource, so what it returns is entirely
dependent on the path variable sections. Also, there is no concept of CRUD against this URL. It really only needs one
HTTP method, and the method name conveys nothing about the action to take.

As an API, it’s not great either. The meaning of the path variables is dependent on their position in the URL. This could
be addressed by changing the URL to use a query string instead, like this:

/api/substituteString?string=<string>&search_string=<search_string>&sub_string=<sub_string>
Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 2/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

But the URL portion /api/substituteString isn’t a thing (noun) or collection of things at all: it’s an action (verb).

This doesn’t fit well in the REST conventions, and trying to force it to do so makes for a poor API. What the above
really represents is an RPC, or Remote Procedure Call. Thinking about this as an RPC makes much more sense.

The beauty is that both REST and RPC conventions can coexist in an API without any problems! By keeping in mind
the intention of each, you can use both to compliment each other in your API design. There are many situations where
it would be useful to perform CRUD operations on something. There are also many situations where it would be
useful to take an action with a thing (as a parameter) but not necessarily a ect the thing itself.

The People REST API Improve Your Python


For our example program, you’re going to create a REST API providing access to a collection of people with CRUD
...with
access to an individual person within that collection. Here’s the API design for the a fresh
people 🐍 Python Trick 💌  
collection:
code snippet every couple of days:

HTTP
Action Verb URL Path Description Email Address

Create POST /api/people Defines a unique URL to create a new person


Send Python Tricks »

Read GET /api/people Defines a unique URL to read a collection of people

Read GET /api/people/Farrell Defines a unique URL to read a particular person in the people
collection

Update PUT /api/people/Farrell Defines a unique URL to update an existing order

Delete DELETE /api/orders/Farrell Defines a unique URL to delete an existing person

Getting Started
First, you’ll create a simple web server using the Flask Micro Framework. To get started, create a directory where you
can create the code. You should also work in a virtualenv so you can install modules later on, which you’ll need to do.
In addition, create a templates directory.

The Python code below gets a very basic web server up and running, and responding with Hello World for a request
for the home page:

Python

from flask import (


Flask,
render_template
)

# Create the application instance


app = Flask(__name__, template_folder="templates")

# Create a URL route in our application for "/"


@app.route('/')
def home():
"""
This function just responds to the browser ULR
localhost:5000/

:return: the rendered template 'home.html'


"""
return render_template('home.html')

# If we're running in stand alone mode, run the application


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

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 3/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

You should also create a home.html in the templates folder, as this is what will be served to a browser when navigating
to the URL '/'. Here is the contents of the home.html file:

HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Application Home Page</title>
</head>
<body>
<h2>

</h2>
Hello World!
Improve Your Python
</body>
...with a fresh 🐍 Python Trick 💌  
</html>
code snippet every couple of days:

You’ll notice the HTML file is named home.html rather than index.html. This is intentional because having an
Email Address
index.html file in the templates directory causes problems once you import the Connexion module in your program.

You can run your application with this command line in the directory containing theSend
server.py file with the Python
Python Tricks »
VirtualEnv active:

Shell

python server.py

When you run this application, a web server will start on port 5000, which is the default port used by Flask. If you open
a browser and navigate to localhost:5000, you should see Hello World! displayed. Right now, this is useful to see the
web server is running. You’ll extend the home.html file later to become a full single page web application using the
REST API you’re developing.

In your Python program, you’ve imported the Flask module, giving the application access to the Flask functionality.
You then created a Flask application instance, the app variable. Next, you connected the URL route '/' to the home()
function by decorating it with @app.route('/'). This function calls the Flask render_template() function to get the
home.html file from the templates directory and return it to the browser.

All of the example code is available from a link provided at the end of this article.

Using Connexion to Add a REST API Endpoint


Now that you’ve got a working web server, let’s add a REST API endpoint. To do this, you’ll use the Connexion module,
which is installed using pip:

Shell

$ pip install connexion

This makes the Connexion module available to your program. The Connexion module allows a Python program to use
the Swagger specification. This provides a lot of functionality: validation of input and output data to and from your
API, an easy way to configure the API URL endpoints and the parameters expected, and a really nice UI interface to
work with the created API and explore it.

All of this can happen when you create a configuration file your application can access. The Swagger site even
provides an online configuration editor tool to help create and/or syntax check the configuration file you will create.

Adding Connexion to the Server


There are two parts to adding a REST API URL endpoint to your application with Connexion. You’ll add Connexion to
the server and create a configuration file it will use. Modify your Python program like this to add Connexion to the
server:

Python
Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 4/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

from flask import render_template


import connexion

# Create the application instance


app = connexion.App(__name__, specification_dir='./')

# Read the swagger.yml file to configure the endpoints


app.add_api('swagger.yml')

# Create a URL route in our application for "/"


@app.route('/')
def home():
"""
This function just responds to the browser ULR Improve Your Python
localhost:5000/
:return: the rendered template 'home.html' ...with a fresh 🐍 Python Trick 💌  
""" code snippet every couple of days:
return render_template('home.html')

# If we're running in stand alone mode, run the application Email Address
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)

Send Python Tricks »


You’ve added a couple of things to incorporate Connexion into the server. The import connexion statement adds the
module to the program. The next step is creating the application instance using Connexion rather than Flask.
Internally, the Flask app is still created, but it now has additional functionality added to it.

Part of the app instance creation includes the parameter specification_dir. This informs Connexion what directory to
look in for its configuration file, in this case our current directory. Right a er this, you’ve added the line:

app.add_api('swagger.yml')

This tells the app instance to read the file swagger.yml from the specification directory and configure the system to
provide the Connexion functionality.

The Swagger Configuration File


The file swagger.yml is a YAML or JSON file containing all of the information necessary to configure your server to
provide input parameter validation, output response data validation, URL endpoint definition, and the Swagger UI.
Here is the swagger.yml file defining the GET /api/people endpoint your REST API will provide:

YAML

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 5/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

swagger: "2.0"
info:
description: This is the swagger file that goes with our server code
version: "1.0.0"
title: Swagger REST Article
consumes:
- "application/json"
produces:
- "application/json"

basePath: "/api"

# Paths supported by the server application


paths: Improve Your Python
/people:
get: ...with a fresh 🐍 Python Trick 💌  
operationId: "people.read" code snippet every couple of days:
tags:
- "People"
Email Address
summary: "The people data structure supported by the server application"
description: "Read the list of people"
responses:
200:
Send Python Tricks »
description: "Successful read people list operation"
schema:
type: "array"
items:
properties:
fname:
type: "string"
lname:
type: "string"
timestamp:
type: "string"

This file is organized in a hierarchical manner: the indentation levels represent a level of ownership, or scope.

For example, paths defines the beginning of where all the API URL endpoints are defined. The /people value indented
under that defines the start of where all the /api/people URL endpoints will be defined. The get: indented under that
defines the section of definitions associated with an HTTP GET request to the /api/people URL endpoint. This goes on
for the entire configuration.

Here are the meanings of the fields in this section of the swagger.yml file:

This section is part of the global configuration information:

1. swagger: tells Connexion what version of the Swagger API is being used
2. info: begins a new ‘scope’ of information about the API being built
3. description: a user defined description of what the API provides or is about. This is in the Connexion generated
UI system
4. version: a user defined version value for the API
5. title: a user defined title included in the Connexion generated UI system
6. consumes: tells Connexion what MIME type is expected by the API.
7. produces: tells Connexion what content type is expected by the caller of the API.
8. basePath: "/api" defines the root of the API, kind of like a namespace the REST API will come from.

This section begins the configuration of the API URL endpoint paths:

1. paths: defines the section of the configuration containing all of the API REST endpoints.
2. /people: defines one path of your URL endpoint.
3. get: defines the HTTP method this URL endpoint will respond to. Together with the previous definitions, this
creates the GET /api/people URL endpoint.

This section begins the configuration of the single /api/people URL endpoint:

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 6/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

1. operationId: "people.read" defines the Python import path/function that will respond to an HTTP GET
/api/people request. The "people.read" portion can go as deep as you need to in order to connect a function to
the HTTP request. Something like "<package_name>.<package_name>.<package_name>.<function_name>" would
work just as well. You’ll create this shortly.
2. tags: defines a grouping for the UI interface. All the CRUD methods you’ll define for the people endpoint will
share this tag definition.
3. summary defines the UI interface display text for this endpoint.
4. description: defines what the UI interface will display for implementation notes.

This section defines the section of the configuration of a successful response from the URL endpoint:

1. response: defines the beginning of the expected response section.


Improve Your Python
2. 200: defines the section for a successful response, HTTP status code 200. ...with a fresh 🐍 Python Trick 💌  
3. description: defines the UI interface display text for a response of 200. code snippet every couple of days:
4. schema: defines the response as a schema, or structure.
Email Address
5. type: defines the structure of the schema as an array.
6. items: starts the definition of the items in the array.
7. properties: defines the items in the array as objects having key/value pairs. Send Python Tricks »
8. fname: defines the first key of the object.
9. type: defines the value associated with fname as a string.
10. lname: defines the second key of the object.
11. type: defines the value associated with lname as a string.
12. timestamp: defines the third key of the object.
13. type: defines the value associated with timestamp as a string.

Handler for People Endpoint


In the swagger.yml file, you configured Connexion with the operationId value to call the people module and the read
function within the module when the API gets an HTTP request for GET /api/people. This means a people.py module
must exist and contain a read() function. Here is the people.py module you will create:

Python

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 7/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

from datetime import datetime

def get_timestamp():
return datetime.now().strftime(("%Y-%m-%d %H:%M:%S"))

# Data to serve with our API


PEOPLE = {
"Farrell": {
"fname": "Doug",
"lname": "Farrell",
"timestamp": get_timestamp()
},
"Brockman": {
"fname": "Kent", Improve Your Python
"lname": "Brockman",
"timestamp": get_timestamp() ...with a fresh 🐍 Python Trick 💌  
}, code snippet every couple of days:
"Easter": {
"fname": "Bunny",
"lname": "Easter", Email Address
"timestamp": get_timestamp()
}
}
Send Python Tricks »
# Create a handler for our read (GET) people
def read():
"""
This function responds to a request for /api/people
with the complete lists of people

:return: sorted list of people


"""
# Create the list of people from our data
return [PEOPLE[key] for key in sorted(PEOPLE.keys())]

In this code, you’ve created a helper function called get_timestamp() that generates a string representation of the
current timestamp. This is used to create your in-memory structure and modify the data when you start modifying it
with the API.

You then created the PEOPLE dictionary data structure, which is a simple names database, keyed on the last name. This
is a module variable, so its state persists between REST API calls. In a real application, the PEOPLE data would exist in a
database, file, or network resource, something that persists the data beyond running/stopping the web application.

Then you created the read() function. This is called when an HTTP request to GET /api/people is received by the
server. The return value of this function is converted to a JSON string (recall the produces: definition in the
swagger.yml file). The read() function you created builds and returns a list of people sorted by last name.

Running your server code and navigating in a browser to localhost:5000/api/people will display the list of people on
screen:

JavaScript

[
{
"fname": "Kent",
"lname": "Brockman",
"timestamp": "2018-05-10 18:12:42"
},
{
"fname": "Bunny",
"lname": "Easter",
"timestamp": "2018-05-10 18:12:42"
},
{
"fname": "Doug",
"lname": "Farrell",
"timestamp": "2018-05-10 18:12:42"
}
]

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 8/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Congratulations, you’ve created a nice API and are on your way to building out a complete one!

The Swagger UI
Now you have a simple web API running with a single URL endpoint. At this point, it would be reasonable to think,
“configuring this with the swagger.yml file was cool and all, but what did it get me?”

You’d be right to think that. We haven’t taken advantage of the input or output validation. All that swagger.yml gave us
was a definition for the code path connected to the URL endpoint. However, what you also get for the extra work is the
creation of the Swagger UI for your API.

Improve Your Python


If you navigate to localhost:5000/api/ui, the system will bring up a page that looks something like this:

...with a fresh 🐍 Python Trick 💌  


code snippet every couple of days:

Email Address

Send Python Tricks »

This is the initial Swagger interface and shows the list of URL endpoints supported at our localhost:5000/api
endpoint. This is built automatically by Connexion when it parses the swagger.yml file.

If you click on the /people endpoint in the interface, the interface will expand to show a great deal more information
about your API and should look something like this:

This displays the structure of the expected response, the content-type of that response, and the description text you
entered about the endpoint in the swagger.yml file.

You can even try the endpoint out by clicking the Try It Out! button at the bottom of the screen. That will further
expand the interface to look something like this: Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 9/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Improve Your Python


...with a fresh 🐍 Python Trick 💌  
code snippet every couple of days:

Email Address

Send Python Tricks »

This can be extremely useful when the API is complete as it gives you and your API users a way to explore and
experiment with the API without having to write any code to do so.

Building an API this way is very useful to me at work. Not only is the Swagger UI useful as a way to experiment with
the API and read the provided documentation, but it’s also dynamic. Any time the configuration file changes, the
Swagger UI changes as well.

In addition, the configuration o ers a nice, clean way to think about and create the API URL endpoints. I know from
experience that APIs can develop in a sometimes random manner over time, making finding the code that supports
the endpoints, and coordinating them, di icult at best.

By separating the code from the API URL endpoint configuration, we decouple one from the other. This alone has
been very useful to me in my work building API systems supporting single page web applications.

Building Out the Complete API


Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 10/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Our original goal was to build out an API providing full CRUD access to our people structure. As you recall, the
definition of our API looks like this:

HTTP
Action Verb URL Path Description

Create POST /api/people Defines a unique URL to create a new person

Read GET /api/people Defines a unique URL to read a collection of people

Read GET /api/people/Farrell Defines a unique URL to read a particular person in the people
collection
Improve Your Python
...with a fresh 🐍 Python Trick 💌  
Update PUT /api/people/Farrell Defines a unique URL to update an snippet
code existing every
order couple of days:

Delete DELETE /api/orders/Farrell Defines a unique URL to delete an existing person


Email Address

To achieve this, you’ll extend both the swagger.yml and people.py files to fully support the API defined above. For the
sake of brevity, only a link will be provided for both files: Send Python Tricks »

swagger.yml

people.py

The Swagger UI Completed


Once you’ve updated the swagger.yml and people.py files to complete the people API functionality, the Swagger UI
system will update accordingly and look something like this:

This UI allows you to see all of the documentation you’ve included in the swagger.yml file and interact with all of the
URL endpoints making up the CRUD functionality of the people interface.

Demonstration Single-Page Application


You’ve got a working REST API with a great Swagger UI documentation/interaction system. But what do you do with it
now? The next step is to create a web application demonstrating the use of the API in a semi-practical manner.

You’ll create a web application that displays the people on screen as well as allows the user to create new people,
update existing people, and delete people. This will all be handled by AJAX calls from JavaScript to the people API
URL endpoints.

To begin, you need to extend the home.html file to look like this:

HTML
Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 11/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Application Home Page</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css">
<link rel="stylesheet" href="static/css/home.css">
<script
src="http://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous">
</script>
</head>
<body> Improve Your Python
<div class="container">
<h1 class="banner">People Demo Application</h1> ...with a fresh 🐍 Python Trick 💌  
<div class="section editor"> code snippet every couple of days:
<label for="fname">First Name
<input id="fname" type="text" />
</label> Email Address
<br />
<label for="lname">Last Name
<input id="lname" type="text" />
Send Python Tricks »
</label>
<br />
<button id="create">Create</button>
<button id="update">Update</button>
<button id="delete">Delete</button>
<button id="reset">Reset</button>
</div>
<div class="people">
<table>
<caption>People</caption>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Update Time</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="error">
</div>
</div>
</body>
<script src="static/js/home.js"></script>
</html>

The above HTML code extends the home.html file to pull in the external normalize.min.css file, which is a CSS reset file
to normalize the formatting of elements across browsers.

It also pulls in the external jquery-3.3.1.min.js file to provide the jQuery functionality you’ll use to create the single-
page application interactivity.

The HTML code above creates the static framework of the application. The dynamic parts appearing in the table
structure will be added by JavaScript at load time and as the user interacts with the application.

Static Files
In the home.html file you’ve created, there are references to two static files: static/css/home.css and
static/js/home.js. To add these, you’ll need to add the following directory structure to the application:

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 12/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

static/

├── css/
│ └── home.css

└── js/
└── home.js

Because a directory named static will automatically be served by the Flask application, any files you place in the css
and js folders will be available to the home.html file. For the sake of brevity, here are links to the home.css and home.js
files:
Improve Your Python
home.css

home.js ...with a fresh 🐍 Python Trick 💌  


code snippet every couple of days:

JavaScript File Email Address


As was mentioned, the JavaScript file provides all the interaction with and updates to the web application. It does
this by breaking up the necessary functionality into three parts by using the MVC (Model / View / Controller) design
pattern. Send Python Tricks »

Each object is created by a self-invoking function returning its own API for use by the other pieces. For instance, the
Controller is passed the instances of the Model and View as parameters in its instantiation. It interacts with those
objects through their exposed API methods.

The only other connection is between the Model and Controller by means of custom events on the AJAX method calls:

1. The Model provides the connection to the people API. Its own API is what the Controller calls to interact with the
server when a user interaction event requires it.
2. The View provides the mechanism to update the web application DOM. Its own API is what the Controller calls
to update the DOM when a user interaction event requires it.
3. The Controller provides all the event handlers for user interaction with the web application. This allows it to
make calls to the Model to make requests to the people API, and to the View to update the DOM with new
information received from the people API.

It also handles the custom events generated by the asynchronous AJAX requests made by the Model to the people
API.

Here is a diagram of the MVC structure used in the home.js file:

The idea is that the Controller has a strong link to both the Model and the View. The Model has a weak link (the
custom events) to the Controller and no connection to the View at all. The weak link from the Model to the Controller
reduces coupling and dependence, which is useful in this case.

Demo Application
When created, the web application will look like this in the browser:
Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 13/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Improve Your Python


...with a fresh 🐍 Python Trick 💌  
code snippet every couple of days:

The Create button allows the user to create a new person in the people structure on the Address
Email server. When you enter a First
and Last Name and hit Create, the Controller calls the Model to make a request to the POST /api/people URL
endpoint. This will verify that the last name doesn’t already exist. If it doesn’t, it will create a new person in the people
structure. Send Python Tricks »

This generates a custom event in the Model that causes the Controller to call the Model again to request a GET
/api/people, which will return the complete list of people sorted. The Controller then passes that onto the View to
redraw the table of people.

Double clicking on any row in the table will populate the First and Last Name fields in the editor section of the
application. At this point, the user can either update or delete the person.

To update successfully, the user must change something about the First Name. The Last Name must remain the same
as it’s the lookup key for the person to update. When Update is clicked, the Controller calls the Model to make a
request to the PUT /api/people/{lname} URL endpoint. This will verify that the Last Name does currently exist. If so, it
will update that person in the people structure.

This generates a custom event in the Model that causes the Controller to call the Model again to request a GET
/api/people, which will return the complete list of people sorted. The Controller then passes that onto the View to
redraw the table of people.

To delete successfully, the user need only click Delete. When Delete is clicked, the Controller calls the Model to make
a request to the DELETE /api/people/{lname} URL endpoint. This will verify that the last name does currently exist. If
so, it will delete that person from the people structure.

This generates a custom event in the Model that causes the Controller to call the Model again to request a GET
/api/people, which will return the complete list of people sorted. The Controller then passes that onto the View to
redraw the table of people.

Try making intentional errors in the editor, like misspelling a Last Name, and see the errors generated by the API
represented on the web application.

Example Code
All of the example code for this article is available here. There are four versions of the code, each in a version_#
directory, where # ranges from 1 to 4. The four versions correspond to the article sections in this manner:

1. version_1: This version contains the initial web server that serves up the home.html file.
2. version_2: This version contains the web server with Connexion added and the first people API URL endpoint.
3. version_3: This version contains the completed people API with all supported URL endpoints.
4. version_4: This version contains the completed API and a single page web application to demonstrate it.

Free Bonus: Click here to download a copy of the "REST in a Nutshell" Guide with a hands-on introduction
to REST API principles and examples.
Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 14/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Conclusion
In this tutorial, you saw how relatively easy it is to create a comprehensive REST API with Python. With the Connexion
module and some additional configuration work, a useful documentation and interactive system can be put in place,
making your API a much more enjoyable experience for your users to interface with and understand.

In Part 2 of this series, you’ll learn how to use a proper database to store your data permanently instead of relying on
in-memory storage as we did here:

Part 1: REST APIs With Flask Part 2: Database


+ Connexion Persistence »
Improve Your Python
...with a fresh 🐍 Python Trick 💌  
🐍 Python Tricks 💌 code snippet every couple of days:

Get a short & sweet Python Trick delivered to your inbox every couple of Email Address
days. No spam ever. Unsubscribe any time. Curated by the Real Python
team.
Send Python Tricks »

Email Address

Send Me Python Tricks »

About Doug Farrell

Doug is a Python developer with more than 25 years of experience. He writes about Python on
his personal website and works as a Senior Web Engineer with Shutterfly.

» More about Doug

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who
worked on this tutorial are:

Aldren Dan Joanna

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 15/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

What Do You Think?

Real Python Comment Policy: The most useful comments are those written with the goal of learning
from or helping out other readers—a er reading the whole article and all the earlier comments.
Complaints and insults generally won’t make the cut here.
Improve Your Python
65 Comments Real Python ...with a fresh 🐍 Python Trick 💌
1 Login
 
code snippet every couple of days:
 Recommend 8 t Tweet f Share Sort by Best

Email Address
Join the discussion…

LOG IN WITH
OR SIGN UP WITH DISQUS ?
Send Python Tricks »
Name

Nazim • 5 months ago


Swagger UI was not showing up. Instead it said the URL (api/ui) was not set up. After some browsing I ran into the
link below. Since I am working with docker, I had to include a pip install for swagger-ui-bundle in my requirements.txt
and it fixed the issue.

https://github.com/zalando/...
4△ ▽ • Reply • Share ›

Paul Caballero > Nazim • a month ago


Hi Nazim, I was able to show the swagger UI locally, but when I deploy it on IBM Cloud, it can't recognize the
url.
△ ▽ • Reply • Share ›

Doug Farrell > Nazim • 4 months ago


Nazim,
Thanks for digging that out!
Doug
△ ▽ • Reply • Share ›

Dan Walker • 5 months ago


Great post. Can I ask what the best practice would be for a shared object between the different endpoints. For
example, if my API calls another API, ideally I only want to instantiate/authenticate once and then have a shared
object that both people.py and another endpoint's code can access.
3△ ▽ • Reply • Share ›

Doug Farrell > Dan Walker • 4 months ago


Hi Dan,
I'm not entirely sure what you mean by having your API call another API and share an object.
But, in my own work what often do is have a module that contains a class/classes, and at the bottom I
instantiate an object of the class/classes. Then from other modules I import the class/classes from the
module. This creates an effective "singleton" because Python will only import the module once for the entire
application, even if multiple modules import the same module.
Does that makes sense?
Doug
△ ▽ • Reply • Share ›

youyi qin • 4 months ago


good jobs!Thanks!I install Connexion packet with this command: pip install "connexion[swagger-ui]"
2△ ▽ • Reply • Share ›

Andy Gardner > youyi qin • 2 months ago


i found this made no difference when installing on Ubuntu Took me a while but I finally got the swagger-ui
extras to install by running pip install connexion[tests] which seemed to install quite a few extras packages
including swagger-ui-bundle, and after that entering localhost:/api/ui in the URL bar produced the expected
documentation.
△ ▽ • Reply • Share ›
Improve Your Python
Jon Wesneski • a year ago
https://realpython.com/flask-connexion-rest-api/ 16/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python
Jon Wesneski • a year ago
Awesome job! I noticed the swagger.yml file shown here is missing some required properties:

swagger: "2.0"
info:
description: This is the swagger file that goes with our server code
version: "1.0.0"
title: Swagger ReST Article
1△ ▽ • Reply • Share ›

Dan Bader Mod > Jon Wesneski • a year ago


Thanks Jon—we only included an excerpt of the full "swagger.yml" file in the article to focus on the important
bits. You can find the complete swagger.yml example here.

Improve Your Python


But it seems like this decision caused some confusion :-) So we're going to update the article to include a
complete example. Thanks again for the heads up, we love hearing feedback like that.
△ ▽ • Reply • Share ›
...with a fresh 🐍 Python Trick 💌  
Doug Farrell > Dan Bader • a year ago
code snippet every couple of days:
Hi Jon - as Dan said, I'm going to update the article to include the missing pieces. My initial thought
was to exclude the "global" stuff as it wasn't directly related to theEmail
API being developed. But, if it
Address
caused confusion it's worth changing.
Doug
△ ▽ • Reply • Share ›
Send Python Tricks »
Alexander Berndt • 16 days ago
Hello Doug, first of all, thank you very much for your great article. I have a question, maybe you can help me out. I
want the people.py to be located in a separate folder, lets say ./modules. If I put the file there, it cannot be located.
How can I configure where the module files are located?
△ ▽ • Reply • Share ›

Doug Farrell > Alexander Berndt • 10 days ago


Hi Alexander,
Do you have a __init__.py file in your ./modules folder, and are you then importing it using from modules import
people?
I'd also suggest you look at using Flask Blueprints to separate out functionality like this. I use that in my own
work as I often have distinct functionality I want to keep separate.
Doug
△ ▽ • Reply • Share ›

Paul Caballero • a month ago


Hi, You're tutorial is Amazing, I just have one concern how can you implement a multiple query parameters in
Swagger then past it to your flask app? Appreciate your help on this. Thank You!
△ ▽ • Reply • Share ›

Doug Farrell > Paul Caballero • 10 days ago


Hi Paul,
You can have as many query parameters as you want using Swagger, just keep adding new ones to the
parameters section. You'll also need to tell the system where the parameters come from (path, query_string,
body) in order for Swagger to figure out how to get them and pass them on to the handler function.
Hope that's helpful!
Doug
△ ▽ • Reply • Share ›

Gavin McClary • 2 months ago


Thanks for this Doug! One question - when amending the swagger.yml file to include the other routes I can't view
them from http://localhost:5000/api/ui/. I can only view the people route. However, when I hit
http://localhost:5000/api/swagger.json it includes all the new routes. I even validated the swagger.yml file online in a
swagger editor. Is this some kind of caching issue?

Thanks
Gav
△ ▽ • Reply • Share ›

Paul Caballero > Gavin McClary • a month ago


Hi Gavin, did you install connexion[swagger-ui]?
△ ▽ • Reply • Share ›

Doug Farrell > Paul Caballero • 10 days ago


Thanks for jumping in there Paul, that's what I would have asked too!
△ ▽ • Reply • Share ›

ferstratus • 4 months ago


Thank you so much Doug Farrell for this tutorial, your javascript
Improvecode is simply
Your Pythonbeautiful, where can I learn to code it
in the way you do?
https://realpython.com/flask-connexion-rest-api/ 17/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python
in the way you do?
△ ▽ • Reply • Share ›

Doug Farrell > ferstratus • 4 months ago


Hi,
Actually the way I code JavaScript is just based on reading a bunch of stuff about modular JavaScript and
using JavaScript patterns. The MVC "thing" I use I made up to help me break up the JavaScript into more
logical groupings, and to match what I used to do with Windows GUI coding I did in the way back machine.
Feel free to use what I've done any way you like. :)
Doug
1△ ▽ • Reply • Share ›

Nicholas Jones • 4 months ago


Thanks you, Doug, A very useful post
cheers Improve Your Python
Nick
△ ▽ • Reply • Share › ...with a fresh 🐍 Python Trick 💌  
code snippet every couple of days:
Indranil Bhaumik • 4 months ago
I guess there's a typo with the "swagger.yml" file in version3. I'm getting the errors starting from line 54 in the same
file as: Email Address

connexion.exceptions.InvalidSpecification: 'description' does not match any of the regexes: '^x-'

Since I'm a newbie, I'm unable to figure out the fix. Please help. Send Python Tricks »
△ ▽ • Reply • Share ›

Ondra Nejedlý • 5 months ago


Very nice article!

Shameless plug: I have made a lib which lets you organize your Connexion schema into multiple files in a nested
directory structure:https://pypi.org/project/co...
△ ▽ • Reply • Share ›

Doug Farrell > Ondra Nejedlý • 4 months ago


Ondra,
Really nice project! I'm going to look into that and perhaps include it in my work projects!
Thanks Doug!
△ ▽ • Reply • Share ›

Ondra Nejedlý > Doug Farrell • 4 months ago


Thank you Doug! This is my first open source project that people may actually make some use of:) I'd
be glad if they do.
△ ▽ • Reply • Share ›

TrickiDicki • 6 months ago


Simply substituting app=Flask() for app=connexion.FlaskApp() doesn't work. Instead I suggest:

connex = connexion.FlaskApp(__name__, specification_dir='swagger')


app = connex.app
connex.add_api('api.yaml', resolver=RestyResolver('api'), base_path='/api/v1.0')
△ ▽ • Reply • Share ›

abofidu • 7 months ago


This is awesome. I have done the people.read part, and it works fine.
However, when I try ../api/ui the browser returns with status 404.
What could I be missing out?

I fixed this. Flask detected that swagger UI could not be accessed and suggested to install connexion with 'pip install
connexion[swagger-ui]'
△ ▽ • Reply • Share ›

Dinesh Shankar > abofidu • 6 months ago


I'm facing the same error. what was the fix?
△ ▽ • Reply • Share ›

Dinesh Shankar > Dinesh Shankar • 6 months ago


Got it fixed. Had issue in pip install
△ ▽ • Reply • Share ›

Eric • 7 months ago


Hi there,

Firs of all, thanks for this amazing tutorial. It helped me understand what an API is and how to code it.
Improve Your Python
But still I have a problem: I'm just coding it myself and, when I connect to the browser and put the url /api/ui, the
https://realpython.com/flask-connexion-rest-api/ 18/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

swagger ui does not appear. Also, the localhost:5000/ does not show the home.html, it actually raises the exception:

jinja2.exceptions.TemplateNotFound
TemplateNotFound: home.html

Do you know why this can happen?


△ ▽ • Reply • Share ›

Daniel > Eric • 6 months ago


create a 'templates' directory (folder) and place your 'home.html' file inside.
△ ▽ • Reply • Share ›

Rajesh Thevar • 7 months ago


Okay, new on Flask development; How to generate my swagger.yml file? Or the swagger configuration file was
written from scratch on a swagger tool? Improve Your Python
△ ▽ • Reply • Share ›
...with a fresh 🐍 Python Trick 💌  
Doug Farrell > Rajesh Thevar • 2 months ago code snippet every couple of days:
Rajesh,

The swagger.yml file is unfortunately written from scratch. However, there Email
is anAddress
online tool here that I've used
to help me find syntax errors in the file. It's a useful editor, but it doesn't auto-generate the configuration file for
you.

Doug Send Python Tricks »


△ ▽ • Reply • Share ›

Igor K • 8 months ago


Hi. It's beautiful. I've just only started to understand what is the REST. Thank you.
△ ▽ • Reply • Share ›

Jeremy Szyba • 8 months ago


Just wanna say I like how you describe REST, or at least how you view what it is and isn't. There are so many
definitions out there thrown around and it really does come down to the way you explained it, as simple as it might
be. There are so many gray areas regarding what to include in the API or how to format an endpoint, and I know I've
been a victim of making it overly complicated when it doesn't need to be. All that to say is it is a good reminder to
keep it simple and not over engineer things, and a reminder that when you start doing that, to remind yourself of
those basics.
△ ▽ • Reply • Share ›

Doug Farrell > Jeremy Szyba • 8 months ago


Thanks Jeremy,
I agree with you, there are so many definitions about what REST is and isn't, its why I think of it as a
convention more than a specification. What I wrote is how I think of REST and use it in my own work, and so
far it's covered most of the cases I've needed.

One of the things see happening all the time is a URL endpoint being proposed as being REST, but in reality it
has nothing to do with CRUD operations. Instead it is a RPC (Remote Procedure Call) that doesn't apply to a
resource, but takes some action based on the parameters passed to it. I write lots of these as well, but I never
think of them as REST and I always code them the same way: as a PUT method, passing the parameters as
a JSON string in the body of the request. To me this has much more flexibility than putting the parameters in
the path (which I consider misleading) or encoding them into a query_string.
Doug
△ ▽ • Reply • Share ›

Krzysztof Bober • 8 months ago


Great article. Thx for this.
Doug, when do you expect to have part 2 (with db persistence) done?
△ ▽ • Reply • Share ›

Doug Farrell > Krzysztof Bober • 8 months ago


Hi Krzysztof,
The Part 2 article has been published and is available here: https://realpython.com/flas...
Doug
1△ ▽ • Reply • Share ›

Anthlis • 9 months ago


Hi there! I'm loving the RealPython tutorial series. I've been following this one tonight and am now confused. I wonder
if the connexions module has been updated since?

I couldn't get this to work: (Note my app.py = server.py in the tutorial)

# Create the application instance


app = connexion.App(__name__, specification_dir='./')
# read the swagger.yml file to configure the endpoints Improve Your Python
app add api('swagger yml')
https://realpython.com/flask-connexion-rest-api/ 19/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python
app.add_api( swagger.yml )

as it threw up a "Error: Failed to find Flask application or factory in module..."

so I looked on the example on the connexions github page here: https://github.com/hjacobs/...

which instead uses:

app = connexion.App(__name__)
app.add_api('swagger.yaml')
application = app.app

This works for me now. Does the tutorial work for others as originally written and I've missed something?

Hope this helps someone else.


Keep up the great work RealPython team!
Looking forward to Part 2... Improve Your Python
△ ▽ • Reply • Share ›
...with a fresh 🐍 Python Trick 💌  
Tom Stranger • 9 months ago code snippet every couple of days:
Perfect tutorial, thanks. More of these :-)
△ ▽ • Reply • Share ›
Email Address
Diptangshu Banik • 10 months ago
How would I be hosting this service on a tomcat server?
SendiisPython
And during localhost, what is the server that is being used? (for example asp.net uses Tricks
to host .net »
web apps
during debuging)
△ ▽ • Reply • Share ›

Doug Farrell > Diptangshu Banik • 8 months ago


Hi Diptangshu,
I don't know to much about Tomcat servers, so I can't help you there. On localhost the server is built into Flask
and is started by the app.run() statement. This is useful for development, but in production you should use
something like uwsgi or gunicorn to actually run the application.
Doug
△ ▽ • Reply • Share ›

Chris Culberson • 10 months ago


The post is fantastic ! I have a question about the version 4 code. When I add a new user "create" - the table doesn't
update in Chrome. "update" does update the date field, "delete" removes a row from the table - are others seeing this
behaviour
△ ▽ • Reply • Share ›

Doug Farrell > Chris Culberson • 9 months ago


Hi Chris,
I haven't seen the behavior you're describing. Are you seeing this while developing the code, or just running it
from the repository? If the former, have you cleared your browser cache to make sure you have the latest
JavaScript files loaded?
Doug
△ ▽ • Reply • Share ›

okarito > Doug Farrell • 8 months ago


I'm also seeing this same problem, using the javascript code copied directly from the repository. It's as
if the 'model_create_success' event isn't being sent out by the create function in the model. The other
methods do redraw the table as expected. My javascript isn't good enough (yet) to debug this much
further - need to work out how to set breakpoints in AJAX js...

I'm also using Chrome, if that matters.

EDIT: Chrome JS console shows this error after POST:

home.js:234 Uncaught TypeError: Cannot read property 'detail' of undefined


at HTMLBodyElement.<anonymous> (home.js:234)
at HTMLBodyElement.dispatch (jquery-3.3.1.min.js:2)
at HTMLBodyElement.y.handle (jquery-3.3.1.min.js:2)
at Object.trigger (jquery-3.3.1.min.js:2)
at HTMLBodyElement.<anonymous> (jquery-3.3.1.min.js:2)
at Function.each (jquery-3.3.1.min.js:2)
at w.fn.init.each (jquery-3.3.1.min.js:2)
at w.fn.init.trigger (jquery-3.3.1.min.js:2)
at Object <anonymous> (home js:49)
see more

2△ ▽ • Reply • Share ›

Ghudrin • 10 months ago


Thanks for a great article! Improve Your Python
I have been looking at Flask and REST for some time, (even did the Flask Mega Tutorial) but the inclusion of
https://realpython.com/flask-connexion-rest-api/ 20/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python
g ,( g )
Swagger made it click for me. Now I'm jumping on flask_socketio as well as I need some asynchronous data to be
served. It's a pity that swagger seems to not be of use there.
Looking forward to a followup with sqlite for persistance (even though I'm not doing any CRUD myself).
△ ▽ • Reply • Share ›

Doug Farrell > Ghudrin • 8 months ago


Hi,
Very glad you enjoyed the article and got something out of it. The Part 2 article showing persistence has been
published and is available here: https://realpython.com/flas...
Doug
△ ▽ • Reply • Share ›

Reezal AQ • a year ago

Improve Your Python


I noticed that crud operation didn't update data in people.py, upon restarting the server everything back to default.

How do you do this ?


...with a fresh 🐍 Python Trick 💌  
Thanks! code snippet every couple of days:
△ ▽ • Reply • Share ›

Doug Farrell > Reezal AQ • a year ago


Email Address
Reezal,
In this version of the application the data exists only in memory in a dictionary. If the server is restarted the
people data goes back to its default. To persist the data even if the server Send Python
is restarted Tricks
it would have»to be
saved to an external representation, like a database.
Doug
△ ▽ • Reply • Share ›

Doug Farrell > Doug Farrell • 8 months ago


Hi Reezal,
The Part 2 article has been published, which is all about persisting the data to a database. You can
find it here: https://realpython.com/flas...
Doug
△ ▽ • Reply • Share ›

ed Leonard • a year ago


Agree that the article should demo with a DB section to make the overall value greater. Sometimes it's the final mile
that really shows the worth. Otherwise nice tutorial.
△ ▽ • Reply • Share ›

Load more comments

ALSO ON REAL PYTHON

13 Project Ideas for Intermediate Python Developers Using PyInstaller to Easily Distribute Python
6 comments • 3 months ago Applications
3RI Technologies Pvt. Ltd. — Informative post on ideas for 5 comments • 3 months ago
AvatarIntermediate Python Developers ! Alfa_Q — Interesting post. I'm definitely going to have to
Avatargive this a try 😁👍

How to Stand Out in a Python Coding Interview Get Started With Django Part 1: Build a Portfolio App
12 comments • 3 months ago 49 comments • 2 months ago
Geir Arne Hjelle — Hi Nitin. That's a cool story :) I think datalearner88 — yes, that is correct it is located in the
Avataryour solution is a very good one. It's readable and shows Avatarpersonal_portfolio folder
that you …

✉ Subscribe d Add Disqus to your siteAdd DisqusAdd 🔒 Disqus' Privacy PolicyPrivacy PolicyPrivacy

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 21/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Improve Your Python


...with a fresh 🐍 Python Trick 💌  
code snippet every couple of days:

Email Address
Keep Learning
Send Python Tricks »
Related Tutorial Categories: api flask intermediate web-dev

— FREE Email Series —

🐍 Python Tricks 💌

Email…

Get Python Tricks »

🔒 No spam. Unsubscribe any time.

All Tutorial Topics


advanced api basics best-practices community databases data-science

devops django docker flask front-end intermediate machine-learning

python testing tools web-dev web-scraping

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 22/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Improve Your Python


...with a fresh 🐍 Python Trick 💌  
code snippet every couple of days:
Table of Contents
What REST Is Email Address
What REST Is Not
The People REST API
Send Python Tricks »
Getting Started
Using Connexion to Add a REST API Endpoint
Adding Connexion to the Server
Handler for People Endpoint
Building Out the Complete API
Demonstration Single-Page Application
Example Code
Conclusion

© 2012–2019 Real Python ⋅ Newsletter ⋅ YouTube ⋅ Twitter ⋅ Facebook ⋅ Instagram


Python Tutorials ⋅ Search ⋅ Privacy Policy ⋅ Advertise ⋅ Contact
❤ Happy Pythoning!

Improve Your Python

https://realpython.com/flask-connexion-rest-api/ 23/24
5/29/2019 Python REST APIs With Flask, Connexion, and SQLAlchemy – Real Python

Improve Your Python


...with a fresh 🐍 Python Trick 💌  
code snippet every couple of days:

Email Address

Send Python Tricks »

https://realpython.com/flask-connexion-rest-api/ 24/24

Вам также может понравиться