Api Design Course
Api Design Course
The first part of API design is understanding what the API is for and
who will be using it. For our online marketplace, we will have buyers,
sellers, and administrators.
● Buyers need to search for items, view item details, add items to a
cart, and make a purchase.
● Sellers need to list new items, update existing item details, and
view their sales.
● Administrators need to manage users and items, and view sales
across the entire marketplace.
It's important to note that these are just examples and might not fit
your exact use case. The important part is to think about who will be
using the API and what they need to be able to do.
Now, let's start building the API with Flask. We'll focus on the buyers
endpoints for brevity, but you can apply the same principles to the
other endpoints.
Create a new Python file, app.py, and set up a basic Flask application:
app = Flask(__name__)
@app.route('/')
def home():
return "Welcome to our online marketplace!"
if __name__ == '__main__':
app.run(debug=True)
@app.route('/items', methods=['GET'])
def get_items():
return jsonify(items)
@app.route('/items/<int:id>', methods=['GET'])
def get_item(id):
item = next((item for item in items if item['id'] == id), None)
if item is None:
return jsonify({'message': 'Item not found'}), 404
return jsonify(item)
@app.route('/cart', methods=['POST'])
def add_to_cart():
new_item = request.get_json()
cart.append(new_item)
return jsonify(new_item), 201
@app.route('/cart/<int:id>', methods=['DELETE'])
def remove_from_cart(id):
item = next((item for item in cart if item['id'] == id), None)
if item is None:
return jsonify({'message': 'Item not found in cart'}), 404
cart.remove(item)
return jsonify({'message': 'Item removed from cart'}), 204
Make a purchase
@app.route('/purchases', methods=['POST'])
def make_purchase():
new_purchase = request.get_json()
purchases.append(new_purchase)
cart.clear() # Clears the cart after purchase
return jsonify(new_purchase), 201
Now, you can run your application with python app.py and use Postman to
test your API endpoints.
Always use HTTPS for your APIs to ensure the data transmitted between
the client and server is encrypted and cannot be easily intercepted.
This is especially important if you're dealing with sensitive data such
as passwords, credit card numbers, or personal user data.
● API keys: These are unique identifiers that are often sent as a
part of the header or query parameters in an API request. They
identify the client application but do not identify the individual
user.
● Basic Authentication: This involves sending a username and
password with each request. This method should always be combined
with HTTPS, as the credentials are sent in plain text.
● Token-based authentication: With this method, the user logs in
with their credentials and receives a token. The user then sends
this token with each request to authenticate.
● OAuth: This is a standard for token-based authentication that
allows users to authenticate with a third party service, like
Google or Facebook.
app = Flask(__name__)
auth = HTTPTokenAuth(scheme='Bearer')
@auth.verify_token
def verify_token(token):
user = s.loads(token)
if user in users:
return user
@app.route('/tokens', methods=['POST'])
def get_token():
username = request.json.get('username')
password = request.json.get('password')
@app.route('/protected')
@auth.login_required
def get_resource():
return jsonify({'data': 'Hello, %s!' % g.current_user})
Once a user is authenticated, your API needs to ensure that they are
authorized to access the resources they are requesting. This often
involves setting permissions on different resources. For example, in
our online marketplace, a seller might be authorized to update their
own items but not those belonging to other sellers.
Example:
@app.route('/admin')
@auth.login_required
def get_admin_resource():
if users[g.current_user]['role'] != 'admin':
abort(403)
return jsonify({'data': 'Hello, admin!'})
Always validate the data your API receives before processing it. This
can protect against attacks such as SQL injection and can help catch
mistakes made by legitimate users.
Here's an example of how you can validate incoming data using the
request.get_json() method:
Make sure your API handles errors gracefully and does not expose
sensitive information in error messages. For example, if a user tries
to access a resource they are not authorized to view, simply return a
generic "403 Forbidden" message rather than specifying that the
resource exists but they are not allowed to access it.
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': 'Resource not found.'}), 404
@app.errorhandler(500)
def internal_error(error):
return jsonify({'error': 'An internal error occurred.'}), 500
### Request
GET /items
No authentication required.
### Response
Status: 200 OK
```json
[ { "id": 1, "name": "Laptop", "price": 1000.00,
"seller_id": 1 }, { "id": 2, "name": "Keyboard",
"price": 50.00, "seller_id": 1 }]
For example, you can describe the /items endpoint in Swagger like this:
paths:
/items:
get:
summary: Get all items
responses:
'200':
description: A list of items
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Item'
components:
schemas:
Item:
type: object
properties:
id:
type: integer
name:
type: string
price:
type: number
seller_id:
type: integer
If you're using Flask, you can use the Sphinx tool to generate API
documentation automatically. There's even a flask-sphinx extension that
makes this process easy. You'll need to include docstrings in your code
that describe your endpoints, request, and response formats.
@app.route('/items', methods=['GET'])
def get_items():
"""
Get all items.
By running Sphinx, you'll get a nice HTML (or PDF) document that
includes your API documentation.