25
loading...
This website collects cookies to deliver better user experience
requirements.txt
Dockerfile
docker-compose.yml
mkdir flask-crud-api
cd flask-crud-api
code .
requirements.txt
file and list our dependencies there.flask
psycopg2-binary
Flask-SQLAlchemy
app.py
. We will write our crud API app in about 50 lines of code!from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
if __name__ == '__main__':
app.run(debug=True)
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL')
db = SQLAlchemy(app)
title
and content
as properties. We’ll also add an auto-incremental Integer named id
. This will act as the primary key for our table.class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), unique=True, nullable=False)
content = db.Column(db.String(120), unique=True, nullable=False)
def __init__(self, title, content):
self.title = title
self.content = content
db.create_all()
@app.route('/items/<id>', methods=['GET'])
def get_item(id):
item = Item.query.get(id)
del item.__dict__['_sa_instance_state']
return jsonify(item.__dict__)
@app.route('/items', methods=['GET'])
def get_items():
items = []
for item in db.session.query(Item).all():
del item.__dict__['_sa_instance_state']
items.append(item.__dict__)
return jsonify(items)
@app.route('/items', methods=['POST'])
def create_item():
body = request.get_json()
db.session.add(Item(body['title'], body['content']))
db.session.commit()
return "item created"
@app.route('/items/<id>', methods=['PUT'])
def update_item(id):
body = request.get_json()
db.session.query(Item).filter_by(id=id).update(
dict(title=body['title'], content=body['content']))
db.session.commit()
return "item updated"
@app.route('/items/<id>', methods=['DELETE'])
def delete_item(id):
db.session.query(Item).filter_by(id=id).delete()
db.session.commit()
return "item deleted"
Dockerfile
(capital D, no extension).FROM python:3.6-slim-buster
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 80
CMD ["flask", "run", "--host=0.0.0.0", "--port=80"]
FROM
: Set the baseImage to use for subsequent instructions. FROM must be the first instruction in a Dockerfile.COPY
: Copy files or folders from source to the dest path in the image's filesystem. The first COPY
copies the requirements.txt file inside the filesystem of the image; the second one copies everything else. : Execute any commands on top of the current image as a new layer and commit the results. In this case, we are running
pip` to install the Python libraries we need.EXPOSE
: Informs Docker of the port we will use at runtime. (PRO tip: this line is not really needed. It makes the intent of the Dockerfile clear and facilitates the translation to the docker-compose.yml file)CMD
: Provide defaults for an executing container. If an executable is not specified, then ENTRYPOINT
must be specified as well. There can only be one CMD
instruction in a Dockerfile.docker-compose.yml
file to make our life easier.
`yml
version
: '3.9' is the current version of the docker-compose.yml file.services
: The top-level entry of our docker-compose.yml
file. The services are basically the containers.pythonapp
: The Python application we just wrotecontainer_name
: Defines a custom name for our application. It’s the equivalent of using the --name
option at the command line when we run docker run
.image
: Rhe image for this service (container). Here, we are defining a custom name just to use it locally. If we want to push our containerto a public or private registry (a place to store Docker Images, e.g. Docker hub), we need to change the tag of the image (basically the name). We don’t need to do that now.build
: We need this option if we are using our custom image and not an existing one. The dot after the semicolon is the path of the Dockerfile, and it means "here is where I’mrunning the docker-compose.yml
file". Please note that the docker-compose.yml
file and the Dockerfile
are at the same level.ports
: A list of ports we want to expose to the outside. A good practice is to make the content a quoted string.environment
: Key-value pairs. Here, we use them to define our custom URL to connect to the Postgres database.depends_on
: Express dependency between services. Service dependencies cause the following behaviors:
docker-compose up
starts services in dependency order. In the following example, db and redis are started before web.docker-compose up
automatically includes a service’s dependencies. In the example below, docker-compose up web
also creates and starts db
and redis
.docker-compose stop
stops services in dependency order. In the following example, web
is stopped before db
and redis
.db
: Service for the Postgres database.container_name
: The default name for this service, also called db
image: postgres:12
: We will not use our custom image in this case but an existing one, the one the Postgres team has created and pushed for us on Docker Hub. ports
: A list of ports we want to expose to the outside. A good practice is to wrap this content in a quoted string. environment
: Here we define three environment variables for the Postgres service. The keys are not arbitrary, but are the ones defined in the official Postgres image. We can, of course, define the values of these environment variables (this is why the Postgres team has given them to us, to use them!). volumes
: Here we use a named volume called pgdata. the part before the ':' is the name of the volume, and the part on the right of the ':' is the destination pathpgdata
.
bash
docker compose up -d db
-d
option stands for detached
, to leave out terminal available after running this container.
docker ps
docker exec -it db psql -U postgres
\dt
did not find any relations
exit
\q
docker compose up --build pythonapp
--build
option is to build your application before running it. It's not useful the first time you run this command because Docker is going to build the image anyway. It becomes useful after you run docker compose up
multiple times and you’ve made some changes on your app. <none> <none>
as the repository and tag. To remove them, you can type docker image prune
and then y
to confirm.
docker ps -a
some minutes ago
.)
docker exec -it db psql -U postgres
\dt
python
db.create_all()
/item/<id>
, where <id>
is the unique ID of the item that you previously created. <id>
of the item in the body:<id>
at the end of the url:
docker exec -it db psql -U postgres
select * from item;