Skip to content

Commit 45e74a4

Browse files
Add files via upload
1 parent 56251db commit 45e74a4

File tree

4 files changed

+410
-1
lines changed

4 files changed

+410
-1
lines changed

README.md

Lines changed: 259 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,259 @@
1-
# webapp-python-oracledb-flask-api
1+
# EMS Demo App - RESTful APIs on Oracle Database with Python Flask
2+
A Demo App build with Python3, Flask Package and Oracle Autonomous Database
3+
4+
The python-flask-demo-oracle repository contains a simple Flask application that demonstrates how to connect to an Oracle Autonomous database (or any other Oracle Database) and perform basic CRUD (Create, Read, Update, Delete) operations on a database table.
5+
6+
The application consists of a single Flask app defined in the main.py file, which serves as the entry point for the application. The main.py file defines several Flask routes (i.e. URL endpoints) that handle HTTP requests from clients and return HTTP responses.
7+
8+
The main features of the application are:
9+
10+
1. Database connection: The app connects to an Oracle database using the python-oracldb library and a DSN (Data Source Name) string that specifies the hostname, port, service name, username, and password for the database connection.
11+
12+
2. CRUD operations: The app allows users to perform basic CRUD operations on a database table called employees. Users can add new employees, view all employees, update employee information, and delete employees.
13+
14+
3. SSL/TLS encryption: The app uses SSL/TLS encryption to secure HTTP traffic between the client and server. You can use self-signed SSL certificates, and the Flask app is configured to use this certificate to encrypt HTTP traffic.
15+
16+
The repository also contains several HTML templates that define the app's user interface. The base.html template defines the basic layout of the app, while the other templates extend this base template and define the content for specific pages (e.g. the add employee form, the view employees page, etc.).
17+
18+
19+
## Quick Build & Deploy with Docker or Podman
20+
#### 1. Clone the Repo
21+
22+
```
23+
git clone https://github.com/shadabshaukat/python-flask-demo-oracle.git && cd python-flask-demo-oracle/
24+
25+
```
26+
27+
#### 2. Generate the self-signed certificates
28+
29+
```
30+
openssl genrsa -out key.pem 2048
31+
32+
openssl req -new -x509 -newkey rsa:2048 -key key.pem -out cert.pem
33+
34+
chmod +r cert.pem key.pem
35+
```
36+
37+
#### 3. Check for certificate and key file
38+
39+
```
40+
ls -ltr
41+
```
42+
43+
#### 4. Replace username,password & connection string in main.py with your Autonomous DB details
44+
```
45+
vim main.py
46+
```
47+
48+
#### 5. Create table in Autonomous DB
49+
50+
```
51+
CREATE TABLE employees (
52+
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
53+
name VARCHAR2(255) NOT NULL,
54+
email VARCHAR2(255) NOT NULL,
55+
department VARCHAR2(255) NOT NULL
56+
);
57+
```
58+
59+
#### 6. Enable port 4443 on local machine where you are running Docker (Linux only)
60+
```
61+
sudo firewall-cmd --permanent --add-port=4443/tcp
62+
sudo firewall-cmd --reload
63+
sudo firewall-cmd --zone=public --permanent --list-ports
64+
```
65+
66+
#### 7. Build the Docker Image
67+
68+
```
69+
docker build -t oracleflaskdemo .
70+
```
71+
72+
#### 8. Run the Docker Container
73+
74+
```
75+
docker run -p 4443:4443 \
76+
-e ORACLE_USER=admin \
77+
-e ORACLE_PASSWORD=YourP@ssword1234#_ \
78+
-e ORACLE_DSN="(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=adb.ap-melbourne-1.oraclecloud.com))(connect_data=(service_name=******_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))" oracleflaskdemo
79+
```
80+
81+
#### Note : If you are using Podman instead of Docker, just replaced 'docker' with 'podman' in the commands
82+
```
83+
# Install Podman on MacOS M1 Pro
84+
brew install podman
85+
podman machine init
86+
podman machine set -m 3072
87+
podman machine start
88+
89+
# Build Flask App
90+
podman build -t oracleflaskdemo .
91+
92+
podman run -p 4443:4443 \
93+
-e ORACLE_USER=admin \
94+
-e ORACLE_PASSWORD=YourP@ssword1234#_ \
95+
-e ORACLE_DSN="(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=adb.ap-melbourne-1.oraclecloud.com))(connect_data=(service_name=******_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))" oracleflaskdemo
96+
```
97+
98+
# App Testing
99+
100+
## Main Page
101+
#### Open in browser
102+
103+
```
104+
https://127.0.0.1:4443/api/main
105+
```
106+
107+
#### Enter API Username & Password
108+
```
109+
Username : user1
110+
Password : password1
111+
```
112+
113+
<img width="428" alt="Screen Shot 2023-03-11 at 11 22 25 pm" src="https://user-images.githubusercontent.com/39692236/224484216-72b14f5c-6607-4d23-8d85-8992984956bd.png">
114+
115+
<img width="1439" alt="Screen Shot 2023-03-11 at 11 20 40 pm" src="https://user-images.githubusercontent.com/39692236/224484111-2986bfd0-a731-4d51-8649-fabf96fa5bd1.png">
116+
117+
## Create Employee
118+
#### Open in browser
119+
120+
```
121+
https://127.0.0.1:4443/api/add_employee
122+
```
123+
124+
<img width="1623" alt="Screen Shot 2023-03-12 at 10 54 57 am" src="https://user-images.githubusercontent.com/39692236/224516956-bbbfdfbb-9361-434d-9646-8064c1acc14a.png">
125+
126+
## READ Employees
127+
128+
#### Open in browser
129+
130+
```
131+
https://127.0.0.1:4443/api/getall
132+
```
133+
134+
135+
<img width="1756" alt="Screen Shot 2023-03-12 at 10 55 11 am" src="https://user-images.githubusercontent.com/39692236/224516971-bac05ac8-7e85-4be5-b7e2-d76cdfcdacd1.png">
136+
137+
138+
## UPDATE Employee
139+
140+
#### Open in browser
141+
142+
```
143+
https://127.0.0.1:4443/api/update_employee/101
144+
```
145+
146+
<img width="1545" alt="Screen Shot 2023-03-12 at 11 07 25 am" src="https://user-images.githubusercontent.com/39692236/224517115-08a16e38-4a16-4856-8d08-b2725b5d202f.png">
147+
148+
149+
<img width="1709" alt="Screen Shot 2023-03-12 at 11 10 52 am" src="https://user-images.githubusercontent.com/39692236/224517167-9d1a16a8-f040-4a12-9e93-ae96ef5e482b.png">
150+
151+
152+
## DELETE Employee
153+
154+
#### Open in browser
155+
156+
```
157+
https://127.0.0.1:4443/api/delete_employee/101
158+
```
159+
160+
<img width="886" alt="Screen Shot 2023-03-12 at 11 11 33 am" src="https://user-images.githubusercontent.com/39692236/224517187-ca26fed8-de20-4f75-9507-83a7ae453806.png">
161+
162+
163+
164+
165+
## Oracle Linux VM Deploy
166+
167+
### 1. Install Python 3.6, flask , cx_Oracle, Jinga2 & six packages on Oracle Linux 7
168+
169+
First pre-requisite is to ensure your instance has Python3 installed along with the Python packages. We will also install the command-line browser links to test the API using a html form.
170+
171+
```
172+
sudo yum install python36
173+
sudo yum install links
174+
sudo yum install openssl
175+
176+
sudo pip3 install flask
177+
sudo pip3 install flask_cors
178+
sudo pip3 install six
179+
sudo pip3 install Jinja2
180+
sudo pip3 install oracledb
181+
```
182+
183+
```
184+
python3 --version
185+
```
186+
187+
### 2. Generate Self-signed certificates and firewall rules
188+
189+
As we are creating a secure web server ensure you need SSL certificates. In this example for demo purposes we are creating self-signed certificates but in a production scenario you should have SSL certificates issued from a third party authority.
190+
191+
```
192+
openssl genrsa -out key.pem 2048
193+
194+
openssl req -new -x509 -newkey rsa:2048 -key key.pem -out cert.pem
195+
196+
chmod +r cert.pem key.pem
197+
198+
sudo firewall-cmd --permanent --add-port=4443/tcp
199+
sudo firewall-cmd --reload
200+
sudo firewall-cmd --zone=public --permanent --list-ports
201+
```
202+
203+
### 3. Deploy the Oracle Table
204+
205+
The example uses a simple table called employees in the hr schema. An identity column is used to auto-increment the id of the employee
206+
207+
```
208+
CREATE TABLE employees (
209+
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
210+
name VARCHAR2(255) NOT NULL,
211+
email VARCHAR2(255) NOT NULL,
212+
department VARCHAR2(255) NOT NULL
213+
);
214+
```
215+
216+
### 4. Clone the Repo & Install Python Packages
217+
218+
```
219+
git clone https://github.com/shadabshaukat/python-flask-demo-oracle.git
220+
221+
cd python-flask-demo-oracle/
222+
223+
pip3 install -r requirements.txt
224+
225+
```
226+
227+
228+
229+
### 5. Change path for template_folder in main.py to reflect the local directory where .html files and code is stored :
230+
231+
232+
```
233+
app = Flask(__name__, template_folder='<your local directory>')
234+
```
235+
236+
This will allow two web pages one for the POST request to the “/api/add_employee” endpoint and another for getting a list of all employees in the databases via "/api/getall"
237+
238+
### 6. Change path for SSL certificates in main.py file to location of SSL certificates created in Step 2.
239+
240+
```
241+
app.run(host='0.0.0.0', port=4443, ssl_context=('cert.pem', 'key.pem'))
242+
```
243+
244+
### 7. Run the Python script
245+
246+
Set Oracle Database Environment Variables
247+
248+
```
249+
export ORACLE_USER=admin
250+
export ORACLE_PASSWORD=YourPass@word1234#_
251+
export ORACLE_DSN="(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=adb.ap-melbourne-1.oraclecloud.com))(connect_data=(service_name=*****_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))"
252+
```
253+
254+
```
255+
$ python3 main.py
256+
* Running on https://10.180.1.21:4443/ (Press CTRL+C to quit)
257+
```
258+
259+

requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
flask
2+
flask_cors
3+
six
4+
Jinja2
5+
oracledb

schema.sql

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
-- Employees Table
2+
CREATE TABLE employees (
3+
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
4+
name VARCHAR2(255) NOT NULL,
5+
email VARCHAR2(255) NOT NULL,
6+
department VARCHAR2(255) NOT NULL
7+
);
8+
9+
-- Insert 50 records in 'employees' table
10+
INSERT INTO employees (name, email, department) VALUES ('John Doe', 'john.doe@example.com', 'Sales');
11+
INSERT INTO employees (name, email, department) VALUES ('Jane Smith', 'jane.smith@example.com', 'Marketing');
12+
INSERT INTO employees (name, email, department) VALUES ('Bob Johnson', 'bob.johnson@example.com', 'Finance');
13+
INSERT INTO employees (name, email, department) VALUES ('Mary Brown', 'mary.brown@example.com', 'Human Resources');
14+
INSERT INTO employees (name, email, department) VALUES ('David Lee', 'david.lee@example.com', 'Engineering');
15+
INSERT INTO employees (name, email, department) VALUES ('Sarah Green', 'sarah.green@example.com', 'Sales');
16+
INSERT INTO employees (name, email, department) VALUES ('Mike Davis', 'mike.davis@example.com', 'Marketing');
17+
INSERT INTO employees (name, email, department) VALUES ('Karen Wilson', 'karen.wilson@example.com', 'Finance');
18+
INSERT INTO employees (name, email, department) VALUES ('Tom Johnson', 'tom.johnson@example.com', 'Human Resources');
19+
INSERT INTO employees (name, email, department) VALUES ('Lisa Chen', 'lisa.chen@example.com', 'Engineering');
20+
INSERT INTO employees (name, email, department) VALUES ('David Davis', 'david.davis@example.com', 'Sales');
21+
INSERT INTO employees (name, email, department) VALUES ('Michelle Rodriguez', 'michelle.rodriguez@example.com', 'Marketing');
22+
INSERT INTO employees (name, email, department) VALUES ('Christopher Smith', 'christopher.smith@example.com', 'Finance');
23+
INSERT INTO employees (name, email, department) VALUES ('Samantha Brown', 'samantha.brown@example.com', 'Human Resources');
24+
INSERT INTO employees (name, email, department) VALUES ('Charles Kim', 'charles.kim@example.com', 'Engineering');
25+
INSERT INTO employees (name, email, department) VALUES ('Alexandra Taylor', 'alexandra.taylor@example.com', 'Sales');
26+
INSERT INTO employees (name, email, department) VALUES ('Richard Wilson', 'richard.wilson@example.com', 'Marketing');
27+
INSERT INTO employees (name, email, department) VALUES ('Jennifer Lee', 'jennifer.lee@example.com', 'Finance');
28+
INSERT INTO employees (name, email, department) VALUES ('Matthew Jones', 'matthew.jones@example.com', 'Human Resources');
29+
INSERT INTO employees (name, email, department) VALUES ('Ava Chen', 'ava.chen@example.com', 'Engineering');
30+
INSERT INTO employees (name, email, department) VALUES ('William Davis', 'william.davis@example.com', 'Sales');
31+
INSERT INTO employees (name, email, department) VALUES ('Natalie Nguyen', 'natalie.nguyen@example.com', 'Marketing');
32+
INSERT INTO employees (name, email, department) VALUES ('Joseph Garcia', 'joseph.garcia@example.com', 'Finance');
33+
INSERT INTO employees (name, email, department) VALUES ('Rachel Martin', 'rachel.martin@example.com', 'Human Resources');
34+
INSERT INTO employees (name, email, department) VALUES ('Christian Kim', 'christian.kim@example.com', 'Engineering');
35+
INSERT INTO employees (name, email, department) VALUES ('Hannah Rodriguez', 'hannah.rodriguez@example.com', 'Sales');
36+
INSERT INTO employees (name, email, department) VALUES ('Anthony Johnson', 'anthony.johnson@example.com', 'Marketing');
37+
INSERT INTO employees (name, email, department) VALUES ('Sophia Wilson', 'sophia.wilson@example.com', 'Finance');
38+
INSERT INTO employees (name, email, department) VALUES ('Ethan Chen', 'ethan.chen@example.com', 'Human Resources');
39+
INSERT INTO employees (name, email, department) VALUES ('Madison Smith', 'madison.smith@example.com', 'Engineering');
40+
INSERT INTO employees (name, email, department) VALUES ('Oliver Davis', 'oliver.davis@example.com', 'Sales');
41+
INSERT INTO employees (name, email, department) VALUES ('Grace Nguyen', 'grace.nguyen@example.com', 'Marketing');
42+
INSERT INTO employees (name, email, department) VALUES ('Daniel Garcia', 'daniel.garcia@example.com', 'Finance');
43+
INSERT INTO employees (name, email, department) VALUES ('Isabella Martin', 'isabella.martin@example.com', 'Human Resources');
44+
INSERT INTO employees (name, email, department) VALUES ('Mia Kim', 'mia.kim@example.com', 'Engineering');
45+
INSERT INTO employees (name, email, department) VALUES ('Lucas Rodriguez', 'lucas.rodriguez@example.com', 'Sales');
46+
INSERT INTO employees (name, email, department) VALUES ('Victoria Johnson', 'victoria.johnson@example.com', 'Marketing');
47+
INSERT INTO employees (name, email, department) VALUES ('David Wilson', 'david.wilson@example.com','Engineering');
48+
INSERT INTO employees (name, email, department) VALUES ('Steven Nguyen', 'steven.nguyen@example.com', 'Marketing');
49+
INSERT INTO employees (name, email, department) VALUES ('Amy Kim', 'amy.kim@example.com', 'Engineering');
50+
INSERT INTO employees (name, email, department) VALUES ('Anna Martinez', 'anna.martinez@example.com', 'Sales');
51+
INSERT INTO employees (name, email, department) VALUES ('Kevin Kim', 'kevin.kim@example.com', 'Marketing');
52+
INSERT INTO employees (name, email, department) VALUES ('Catherine Davis', 'catherine.davis@example.com', 'Finance');
53+
INSERT INTO employees (name, email, department) VALUES ('Robert Nguyen', 'robert.nguyen@example.com', 'Human Resources');
54+
INSERT INTO employees (name, email, department) VALUES ('Karen Clark', 'karen.clark@example.com', 'Engineering');
55+
INSERT INTO employees (name, email, department) VALUES ('Mike Wilson', 'mike.wilson@example.com', 'Sales');
56+
INSERT INTO employees (name, email, department) VALUES ('Rachel Lee', 'rachel.lee@example.com', 'Marketing');
57+
INSERT INTO employees (name, email, department) VALUES ('Thomas Johnson', 'thomas.johnson@example.com', 'Finance');
58+
INSERT INTO employees (name, email, department) VALUES ('Emily White', 'emily.white@example.com', 'Human Resources');
59+
INSERT INTO employees (name, email, department) VALUES ('Brian Brown', 'brian.brown@example.com', 'Engineering');
60+
commit;
61+
62+
-- Procedure to Generate Sample Data
63+
CREATE OR REPLACE PROCEDURE add_employees (
64+
n IN NUMBER
65+
)
66+
AS
67+
departments employees.department%TYPE := 'Sales,Marketing,Finance,Human Resources,Engineering';
68+
BEGIN
69+
FOR i IN 1..n LOOP
70+
INSERT INTO employees (name, email, department)
71+
VALUES ('Employee ' || i, 'employee' || i || '@example.com', REGEXP_SUBSTR(departments,'[^,]+',1,ROUND(DBMS_RANDOM.VALUE(1,5))));
72+
END LOOP;
73+
COMMIT;
74+
END;
75+
/
76+
77+
-- Generate Sample Employee Data
78+
BEGIN
79+
add_employees(50);
80+
END;
81+
/
82+
83+
-- Employees Salary Table
84+
CREATE TABLE employees_salary (
85+
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
86+
employee_id NUMBER NOT NULL,
87+
salary NUMERIC(10, 2) NOT NULL,
88+
start_date DATE NOT NULL,
89+
end_date DATE NOT NULL,
90+
bonus FLOAT NOT NULL
91+
);
92+
93+
-- Procedure to Generate Sample Data
94+
CREATE OR REPLACE PROCEDURE generate_employees_salary(n IN NUMBER) AS
95+
BEGIN
96+
FOR i IN 1..n LOOP
97+
INSERT INTO employees_salary (employee_id, salary, start_date, end_date, bonus)
98+
VALUES (FLOOR(DBMS_RANDOM.VALUE(1, 10)), -- generate random employee_id between 1 and 10
99+
ROUND(DBMS_RANDOM.VALUE(50000, 100000), 2), -- generate random salary between 50000 and 100000 with 2 decimal places
100+
TRUNC(SYSDATE - DBMS_RANDOM.VALUE(1, 365)), -- generate random start_date between 1 and 365 days ago
101+
TRUNC(SYSDATE + DBMS_RANDOM.VALUE(1, 365)), -- generate random end_date between today and 365 days from now
102+
ROUND(DBMS_RANDOM.VALUE(5000, 15000), 2)); -- generate random bonus between 5000 and 15000 with 2 decimal places
103+
END LOOP;
104+
COMMIT;
105+
END;
106+
/
107+
108+
-- Generate Sample Employee Salary Data
109+
BEGIN
110+
generate_employees_salary(50); -- generate 50 random records
111+
END;
112+
/
113+
114+
-- Cleanup
115+
-- drop table employees;
116+
-- drop table employees_salary;
117+
-- drop procedure generate_employees_salary;
118+
-- drop procedure add_employees;

0 commit comments

Comments
 (0)