Server-Side: Flask API Development
We will build a simple API that will tell the current time. And then add more feature.
The explanation and the code
The code
from flask import Flask, request, jsonify
from datetime import datetime
app = Flask(__name__)
# Define a route to get the current time
@app.route('/get-current-time', methods=['POST'])
def get_current_time():
# Validate the API key
api_key = request.headers.get('Authorization')
if api_key != '12345':
return jsonify({"error": "Unauthorized"}), 401
# Get and format the current time
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Return the time in JSON format
return jsonify({"currentTime": current_time}), 200
if __name__ == '__main__':
app.run(port=5000, debug=True)
Route Definition: Use the @app.route() decorator to define the URL path (/get-current-time) for your API endpoint. This specific endpoint is configured to handle POST requests.
Endpoint Logic: Inside the get_current_time() function (which handles requests to your endpoint), retrieve the API key from the incoming request's headers
Authorization Check: Implement a security measure by verifying that the provided API key matches the correct value. If the key is invalid, return a JSON error response with a 401 (Unauthorized) HTTP status code.
Response Preparation: Construct a JSON dictionary (response_data) to hold the current time value.
Client-Side: Calling the API
import requests
url = 'http://localhost:5000/get-current-time'
api_key = '12345'
headers = {
'Authorization': api_key,
'Content-Type': 'application/json',
}
try:
response = requests.post(url, headers=headers)
if response.status_code == 200:
response_data = response.json()
current_time = response_data.get('currentTime')
print("Current time received from the API:", current_time)
else:
print("Error:", response.status_code, response.text) # Include response text
except requests.exceptions.RequestException as e:
print("Error On request:", e)
In the client side we will use requests module to retrieve the time with the API request.
requests module is not a built-in module in Python. So if you have not installed you need to install it first.
pip install requests
The code and the explanations
url = 'http://localhost:5000/get-current-time'
api_key = 'oCZ2DNROIRSyL058'
headers = {
'Authorization': api_key,
'Content-Type': 'application/json',
}
Set API URL and Key: Configure the address of your API endpoint and your valid API key.
Create Headers: Build a dictionary containing your API key for authorization and the content type (application/json).
Testing the code
- First we need to run the code we have add in the top for server side. It will run a server on local host http://localhost:5000/
- Then we need to run another python script that is written for the client side. That’s all! It will print the time which comes from the server.
This was just for essential approach. We can make it more practical. For example we need check if a number is prime or not but we do not want to write the core functionality in our client side code. So we can write the API for it .. And call when ever we need and wherever we are!
We will use Miller-Rabin Primality Test for more efficiency to check a number is prime or not.
The code that checks the number is prime or not
import random
def is_prime_miller_rabin(n, iterations=40):
"""Performs the Miller-Rabin Primality Test to determine if a number is likely prime.
This test is probabilistic, meaning it's highly accurate but not foolproof.
Increasing the 'iterations' value improves the accuracy of the result.
Args:
n: The integer to test for primality.
iterations: Number of test rounds to perform (default is 40).
Returns:
True if the number is likely prime, False if it's not.
"""
if n <= 1:
return False
if n <= 3:
return True
if n % 2 == 0:
return False
# Decompose n-1 into the form 2^r * d
d = n - 1
r = 0
while d % 2 == 0:
d //= 2
r += 1
# Witness loop
for _ in range(iterations):
a = random.randint(2, n - 2)
x = pow(a, d, n)
if x == 1 or x == n - 1:
continue
for _ in range(r - 1):
x = pow(x, 2, n)
if x == n - 1:
break
else:
return False
return True
# Test the code
number_to_test = int(input("Enter a number to check for primality: "))
if is_prime_miller_rabin(number_to_test):
print(f"{number_to_test} is likely a prime number.")
else:
print(f"{number_to_test} is not a prime number.")
If you are interested in prime numbers you also can read this article
Implemented In The server code( API)
from flask import Flask, request, jsonify
from datetime import datetime
import random
app = Flask(__name__)
def is_prime_miller_rabin(n, iterations=40):
"""Performs the Miller-Rabin Primality Test to determine if a number is likely prime."""
if n <= 1:
return False
if n <= 3:
return True
if n % 2 == 0:
return False
# Decompose n-1 into the form 2^r * d
d = n - 1
r = 0
while d % 2 == 0:
d //= 2
r += 1
# Witness loop
for _ in range(iterations):
a = random.randint(2, n - 2)
x = pow(a, d, n)
if x == 1 or x == n - 1:
continue
for _ in range(r - 1):
x = pow(x, 2, n)
if x == n - 1:
break
else:
return False
return True
# Define a route to check if a number is prime
@app.route('/check-prime', methods=['POST'])
def check_prime():
# Validate the API key
api_key = request.headers.get('Authorization')
if api_key != '12345':
return jsonify({"error": "Unauthorized"}), 401
# Get the number from the request
data = request.get_json()
number_to_test = data.get('number')
# Check if the number is prime
is_prime = is_prime_miller_rabin(number_to_test)
# Return the result
return jsonify({"number": number_to_test, "isPrime": is_prime}), 200
if __name__ == '__main__':
app.run(port=5000, debug=True)
Calling from the client side
import requests
url = 'http://127.0.0.1:5000/check-prime'
headers = {'Authorization': '12345'}
data = {'number': 172983479832623897492387592384682937659382477}
response = requests.post(url, json=data, headers=headers)
print(response.json())
Limit the API calling: Setting the Rate-Limiting
We can specifically set the daily limit or hourly limit for specific user to save the computation limits. For this we will use a wonderful library apscheduler . I first used this library on video calling project for user data management scheduler.
Install the library with
pip install apscheduler
Now our code will look like this
from flask import Flask, request, jsonify
from datetime import datetime, timedelta
import random
from apscheduler.schedulers.background import BackgroundScheduler
app = Flask(__name__)
def is_prime_miller_rabin(n, iterations=40):
"""Performs the Miller-Rabin Primality Test to determine if a number is likely prime."""
if n <= 1:
return False
if n <= 3:
return True
if n % 2 == 0:
return False
# Decompose n-1 into the form 2^r * d
d = n - 1
r = 0
while d % 2 == 0:
d //= 2
r += 1
# Witness loop
for _ in range(iterations):
a = random.randint(2, n - 2)
x = pow(a, d, n)
if x == 1 or x == n - 1:
continue
for _ in range(r - 1):
x = pow(x, 2, n)
if x == n - 1:
break
else:
return False
return True
# Initialize the scheduler
scheduler = BackgroundScheduler()
# Define the users and their limits
users = {"12345": {"limit": 5}, "45365": {"limit": 5}}
# Function to reset the limits
def reset_limits():
print("Resetting limits...")
for user_info in users.values():
user_info["limit"] = 5
# Schedule the job to run every 24 hours
scheduler.add_job(reset_limits, 'interval', hours=24)
# Start the scheduler
scheduler.start()
# Define a route to check if a number is prime
@app.route('/check-prime', methods=['POST'])
def check_prime():
# Validate the API key
api_key = request.headers.get('Authorization')
if api_key not in users:
return jsonify({"error": "Unauthorized"}), 401
# Get the number from the request
limit = users[api_key]['limit']
if not limit == 0:
data = request.get_json()
number_to_test = data.get('number')
# Check if the number is prime
is_prime = is_prime_miller_rabin(number_to_test)
# Update the request limit
users[api_key]['limit'] -= 1
# Return the result
return jsonify({"number": number_to_test, "isPrime": is_prime}), 200
else:
return jsonify({"error": "Request limit exceeded. Please try again later."}), 429
if __name__ == '__main__':
app.run(port=5000, debug=True)
Client Side will be unchanged!
import requests
url = 'http://127.0.0.1:5000/check-prime'
headers = {'Authorization': '12345'}
data = {'number': 172983479832623897492387592384682937659382477}
response = requests.post(url, json=data, headers=headers)
print(response.json())
Enhance Security Level
For demonstration purposes, this example stores the API key directly in the code. In production environments, always store API keys securely in a database with hashing to protect sensitive information.
With timestamp make the API key ultimately unique when generate new key for user
import secrets
import string
import time
def generate_unique_api_key(length=32):
"""Generate a unique API key using a combination of random characters and timestamp."""
timestamp = str(int(time.time())) # Get current timestamp as a string
alphabet = string.ascii_letters + string.digits
random_part = ''.join(secrets.choice(alphabet) for _ in range(length - len(timestamp)))
key = timestamp + random_part
return key
# Generate a unique API key of length 32
api_key = generate_unique_api_key()
print("unique API key:", api_key)
For You
For more easy to use, I added the code in the github repository