Create a RESTful API Using Python and Flask
Traducciones al EspañolEstamos traduciendo nuestros guías y tutoriales al Español. Es posible que usted esté viendo una traducción generada automáticamente. Estamos trabajando con traductores profesionales para verificar las traducciones de nuestro sitio web. Este proyecto es un trabajo en curso.
Flask is a Python micro-framework for building web applications and web APIs. The framework provides pared-down core functionality, however, it is highly extensible. This guide shows you how to use Flask to build a REST API that serves up information about different programming languages. The data information exposed by the API can also be referred to as a resource. The API’s data comes from Hillel Wayne’s research on influential programming languages. At the end of the guide, you have an API that allows clients to complete the following:
- GET all programming languages stored in the API
- GET a specific instance of a programming language
- Filter the programming language resources based on the publication year field
- POST, PUT, and DELETE a programming language instanceNote GET, POST, PUT, and DELETE are HTTP request methods used to perform an action on a resource.
How to Create REST API Endpoints with Flask
The REST protocol gives clients access to resources stored in a database and allows clients to perform operations on the stored data. The operations are known as CRUD operations (create, read, update, and delete). The following sections show you how to create the CRUD operations for your Flask web API.
Install Flask
- Create a directory to store your Flask web application and move into the directory. - mkdir example_app && cd example_app
- Inside the - example_appdirectory, create a new file named- prog_lang_app.py.- mkdir example_app && cd example_app touch prog_lang_app.py
- Create and activate a virtual environment using the following command: - python3 -m venv venv . venv/bin/activate
In order to run a Flask server, you install Flask first using the Python Package Index (pip). Use the following command to install Flask:
pip install flask
Create the List Endpoint in Flask
RESTful services typically have two endpoints used to retrieve (GET) resources. One endpoint lists all resources or filters them according to some criterion. The second endpoint retrieves the details of a specific resource based on a unique identifier. In this section, you create two endpoints to GET resources from your API. This section may refer to these endpoints as the list and details endpoints.
prog_lang_app.py.- In your preferred text editor, open the - prog_lang_app.pyfile and add the following lines:- File: prog_lang_app.py
- 1 2 3- from flask import Flask app = Flask(__name__)
 - These lines import Flask, and instantiate the app. You can instantiate the class - Flaskand assign it to a variable (traditionally, this variable is named- app)- Note Although RESTful APIs typically access data from a database, this tutorial does not cover the details of integrating with a database.
- Create a small in-memory data store (Python dictionary) to store the data related to programming languages. Place this code underneath the import and app instantiation lines. - 1 2 3 4 5 6 7- ... in_memory_datastore = { "COBOL" : {"name": "COBOL", "publication_year": 1960, "contribution": "record data"}, "ALGOL" : {"name": "ALGOL", "publication_year": 1958, "contribution": "scoping and nested functions"}, "APL" : {"name": "APL", "publication_year": 1962, "contribution": "array processing"}, }
 - The code creates the - in_memory_datastorenested dictionary with entries for three programming language. Each programming language dictionary has keys for its name, the approximate year it was published, and its contributions to modern programming languages.
- Create the - listendpoint with the code in the example below. Below the- in-memory datastoredictionary, a rudimentary list endpoint fetches all the programming language resources and displays them as JSON.- Note RESTful APIs are generally organized around a resource. A resource refers to the database records that an API gives clients access to. In the case of this tutorial, the resource is an instance of a programming language.- File: prog_lang_app.py
- 1 2 3 4 5- ... @app.get('/programming_languages') def list_programming_languages(): return {"programming_languages":list(in_memory_datastore.values())}
 - Requests can be sent to the - /programming_languagesURL using the GET HTTP verb. The request should be sent without any parameters. This endpoint fetches all the records in the datastore. It returns a JSON object with the key- programming_languages. This key points to all the records and is represented as an array.- Note - There are two reasons to put the list into an object with a label, rather than returning the raw array. - Maintainability: an object provides the freedom to add more attributes to the return body later. For example, suppose you wanted to return a count of the objects in the database. You cannot add a count attribute to a raw array, but you can add a count attribute to an enclosing JSON object with one key that points to an array. This is especially useful in APIs that allow clients to filter sections of data or to request aggregate metrics for the data or sections of data. 
- Security: ten years ago, browsers didn’t guard against malicious actors redefining the JSON array and obtaining access to raw JSON array payloads. It’s all patched now, but the programming community keeps on wrapping arrays in objects because of the maintainability benefit. 
 
- Start the app to view the data returned by the - listprogramming languages endpoint. Navigate to the directory where you stored the app. Then, run the following commands:- export FLASK_APP=prog_lang_app.py flask run
- Open a browser and visit - http://127.0.0.1:5000/to access the app running locally on your computer.
- Visit - http://127.0.0.1:5000/programming_languagesin the browser to view the JSON object containing the contents of the datastore you created.
Create the Detail Endpoint in Flask
The next step is to add an endpoint to retrieve a specific programming language resource from the datastore. The details endpoint has an interpolated variable in the endpoint string called programming_language_id. This variable allows you to query for a specific item in your datastore. The id refers to the index in the list related to a specific instance of a programming language resource. This presents a problem once clients can delete items from the datastore. This is fixed in a later section.
- Update the - prog_lang_app.pyfile to add the code that creates your app’s detail endpoint. This code goes underneath the code for listing the programming languages:- File: prog_lang_app.py
- 1 2 3 4 5- ... @app.route('/programming_languages/<programming_language_name>') def get_programming_language(programming_language_name): return in_memory_datastore[programming_language_name]
 
- Run the app and visit - http://127.0.0.1:5000/programming_languages/COBOLin your browser. You should see a similar output returned by your API.- {"contribution":"record data","name":"COBOL","publication_year":1960}
Add Filters to the List Endpoint
Update the prog_lang_app.py file’s in_memory_datastore dictionary with a few more programming language entries. Increasing the size of the datastore provides you with more data to filter. In this section, you add code to filter the list endpoint using a specific date range.
- Open the - prog_lang_app.pyfile and edit the- in_memory_datastoreto add the additional entries.- File: prog_lang_app.py
- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16- ... in_memory_datastore = { "COBOL": {"name": "COBOL", "publication_year": 1960, "contribution": "record data"}, "ALGOL": {"name": "ALGOL", "publication_year": 1958, "contribution": "scoping and nested functions"}, "APL": {"name": "APL", "publication_year": 1962, "contribution": "array processing"}, "BASIC": {"name": "BASIC", "publication_year": 1964, "contribution": "runtime interpretation, office tooling"}, "PL": {"name": "PL", "publication_year": 1966, "contribution": "constants, function overloading, pointers"}, "SIMULA67": {"name": "SIMULA67", "publication_year": 1967, "contribution": "class/object split, subclassing, protected attributes"}, "Pascal": {"name": "Pascal", "publication_year": 1970, "contribution": "modern unary, binary, and assignment operator syntax expectations"}, "CLU": {"name": "CLU", "publication_year": 1975, "contribution": "iterators, abstract data types, generics, checked exceptions"}, } ...
 
- Now, you can add the code to allow clients to filter on the - publication_yearparameter. First, add the- Flask.requestobject to your- prog_lang_app.pyfile’s import statement as shown below:- File: prog_lang_app.py
- 1 2 3 4- from flask import Flask, request app = Flask(__name__) ...
 
- Next, change the - list_programming_languages()function to act upon the query parameters- before_yearand- after_year.- File: prog_lang_app.py
- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15- ... @app.get('/programming_languages') def list_programming_languages(): before_year = request.args.get('before_year') or '30000' after_year = request.args.get('after_year') or '0' qualifying_data = list( filter( lambda pl: int(before_year) > pl['publication_year'] > int(after_year), in_memory_datastore.values() ) ) return {"programming_languages": qualifying_data}
 - Clients can now filter the programming languages with two query parameters: - before_yearand- after_year. Flask automatically treats all parameters passed to a routed function (besides interpolated path parameters) as query parameters. If a client does not pass any query parameters, the default start year of- 0and the default end year of- 30,000automatically capture all languages.- The resulting objects go through a filter that picks out only the ones with a - publication_yearbetween the- before_yearand the- after_year. A request without those query parameters continues to deliver all of the programming languages.
Build a Create Endpoint
So far, all the endpoints expect clients to use the GET HTTP verb to make their requests. In this section, you write the code to support the POST HTTP verb. The create endpoint expects a POST verb as well as a request body. The request body is a payload of data that specifies the attributes of the new resource that the client wants to add. In this case, those attributes are sent as a JSON object. These attributes include the name, publication_year, and contribution of the programming language being added.
- To use the same route in your API with different request verbs, write your code under the same annotation. Then, use conditional logic to route the request to the correct place. To do this, edit your - prog_lang_app.pyfile to remove the- @app.getannotation and modify it as shown below:- File: prog_lang_app.py
- 1 2 3 4 5 6 7 8- ... @app.route('/programming_languages', methods=['GET', 'POST']) def programming_languages_route(): if request.method == 'GET': return list_programming_languages() elif request.method == "POST": return create_programming_language(request.get_json(force=True))
 
- Now, add the new - create_programming_languagemethod below- list_programming_languages()method:- File: prog_lang_app.py
- 1 2 3 4 5 6 7- ... def create_programming_language(new_lang): language_name = new_lang['name'] in_memory_datastore[language_name] = new_lang return new_lang
 
- The two helper functions handle listing programming languages, in the case of a GET request. In the case of a POST request, the second helper function creates a new programming language resource. Use cURL to create a programming language on the command line: - curl -X POST http://127.0.0.1:5000/programming_languages -H 'Content-Type: application/json' -d '{"name": "Java", "publication_year": 1995, "contribution": "Object-oriented programming language."}'
- Once you have created the new resource, make a GET request to - http://127.0.0.1:5000/programming_languages.- curl http://127.0.0.1:5000/programming_languages- Notice that a resource for - Javais returned in the JSON object.
Create the Update Endpoint
To update a resource, you send a PUT request with a request body to the URL of the record you want to update. To achieve this you, use a similar tactic to the one you used in the previous section.
- Remove the - @app.routeannotation and the- get_programming_language()function. Replace them with the following code:- File: prog_lang_app.py
- 1 2 3 4 5 6 7 8- ... @app.route('/programming_languages/<programming_language_name>', methods=['GET', 'PUT']) def programming_language_route(programming_language_name): if request.method == 'GET': return get_programming_language(programming_language_name) elif request.method == "PUT": return update_programming_language(programming_language_name, request.get_json(force=True))
 
- Now, add the new - update_programming_language()function below the- get_programming_language()function:- File: prog_lang_app.py
- 1 2 3 4 5 6- ... def update_programming_language(lang_name, new_lang_attributes): lang_getting_update = in_memory_datastore[lang_name] lang_getting_update.update(new_lang_attributes) return lang_getting_update
 
- To test your new endpoint, send a request to it to update an existing resource. For example, send a request using Postman similar to the following: - curl -X PUT http://127.0.0.1:5000/programming_languages/Java -H 'Content-Type: application/json' -d '{"contribution": "The JVM"}'
- Send a GET request to the - listendpoint to view the update made to the Java contribution you issued in your PUT request.- curl http://127.0.0.1:5000/programming_languages
Create the Delete Record Endpoint
The endpoint to delete a record is similar to the update endpoint. The difference is the HTTP verb that you use. RESTful services conventionally use a DELETE verb for the delete endpoint.
- Update your - @app.routeannotation to include the- DELETEmethod, as shown below:- File: prog_lang_app.py
- 1 2 3 4 5 6 7 8 9 10- ... @app.route('/programming_languages/<programming_language_name>', methods=['GET', 'PUT', 'DELETE']) def programming_language_route(programming_language_name): if request.method == 'GET': return get_programming_language(programming_language_name) elif request.method == "PUT": return update_programming_language(programming_language_name, request.get_json(force=True)) elif request.method == "DELETE": return delete_programming_language(programming_language_name)
 - Notice the addition of - DELETEis passed to the method’s parameter in the annotation.
- Next, add the - delete_programming_language()function below the- update_programming_language()function:- File: prog_lang_app.py
- 1 2 3 4 5 6- ... def delete_programming_language(lang_name): deleting_lang = in_memory_datastore[lang_name] del in_memory_datastore[lang_name] return deleting_lang
 
- To delete a resource, use your preferred request client and issue the following request: - curl -X DELETE http://127.0.0.1:5000/programming_languages/COBOL- The return value is the COBOL JSON object. A visit to the - Listendpoint reveals that COBOL is no longer in the list of languages.
You can view the entirety of the app in
the example prog_lang_app.txt file. This file contains all endpoints created in this guide. Flask includes many specialized options in addition to the basics covered in this guide. Refer to Flask’s official documentation to learn how to enhance the API created in this tutorial.
This page was originally published on