0% found this document useful (0 votes)
31 views

Api Design Course

The document provides a comprehensive guide to designing a RESTful API from scratch using Python and Flask. It covers understanding user needs, planning the design, building endpoints, and securing the API through authentication, authorization, validation and error handling.

Uploaded by

Jorge Quiñones
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views

Api Design Course

The document provides a comprehensive guide to designing a RESTful API from scratch using Python and Flask. It covers understanding user needs, planning the design, building endpoints, and securing the API through authentication, authorization, validation and error handling.

Uploaded by

Jorge Quiñones
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

SIMPLIFIED API DESIGN CRASH COURSE

Designing an API involves more than just coding. It requires


understanding the needs of the users, planning the design, and
following best practices. In this comprehensive guide, we'll be using
Python and the Flask library to build a RESTful API for a hypothetical
online marketplace.

PART I: Understanding and Planning Your API

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.

Step 1: Identifying the Stakeholders

● 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.

Step 2: Planning the API

Each stakeholder group needs specific API endpoints. An API endpoint is


one specific route of the API. They can be accessed via different HTTP
methods like GET, POST, PUT, and DELETE.

For the buyers, we could have the following endpoints:

● GET /items — view all items


● GET /items/:id — view a specific item
● POST /cart — add an item to their cart
● DELETE /cart/:id — remove an item from their cart
● POST /purchases — make a purchase

By: Waleed Mousa


For sellers, we might have these endpoints:

● POST /items — list a new item


● PUT /items/:id — update an existing item
● GET /sales — view their sales

For administrators, these endpoints would be useful:

● GET /users — view all users


● PUT /users/:id — update a user's information
● DELETE /users/:id — delete a user
● GET /items — view all items
● DELETE /items/:id — delete an item
● GET /sales — view all sales

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.

PART II: Building the API

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.

Step 1: Setting Up Your Environment

We'll use a virtual environment to isolate our project. In your


terminal, create a new virtual environment and activate it:

$ python3 -m venv env


$ source env/bin/activate

Install Flask with pip:

$ pip install flask

By: Waleed Mousa


Step 2: Creating the Flask Application

Create a new Python file, app.py, and set up a basic Flask application:

from flask import Flask, jsonify, request

app = Flask(__name__)

# This is our "database" for now


items = [
{'id': 1, 'name': 'Laptop', 'price': 1000.00, 'seller_id': 1},
{'id': 2, 'name': 'Keyboard', 'price': 50.00, 'seller_id': 1},
# more items...
]
cart = []
purchases = []

@app.route('/')
def home():
return "Welcome to our online marketplace!"

if __name__ == '__main__':
app.run(debug=True)

Step 3: Building the Endpoints

Next, we'll create the endpoints we planned earlier. Here's how to


implement them:

View all items

@app.route('/items', methods=['GET'])
def get_items():
return jsonify(items)

View a specific item

@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)

By: Waleed Mousa


Add an item to the cart

@app.route('/cart', methods=['POST'])
def add_to_cart():
new_item = request.get_json()
cart.append(new_item)
return jsonify(new_item), 201

Remove an item from the cart

@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.

PART III: Securing Your API

Step 1: Use HTTPS

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.

By: Waleed Mousa


Step 2: Authentication

Authentication is the process of identifying who is making a request to


your API. There are several ways to handle authentication in APIs:

● 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.

Here's an example of how to implement token-based authentication with


Flask-HTTPAuth.

First, install the extension with pip:

$ pip install flask-httpauth

By: Waleed Mousa


Then, in your app.py, you can set up a token-based authentication
scheme:

from flask import Flask, jsonify, abort, g


from flask_httpauth import HTTPTokenAuth
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

app = Flask(__name__)
auth = HTTPTokenAuth(scheme='Bearer')

# For simplicity, we'll store users in a dictionary


users = {"admin": {"username": "admin", "password": "secret", "token": ""}}

# Serializer for token generation


s = Serializer(app.secret_key)

@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')

if username in users and users[username]['password'] == password:


token = s.dumps(username)
users[username]['token'] = token
return jsonify({'token': token})
else:
abort(401)

@app.route('/protected')
@auth.login_required
def get_resource():
return jsonify({'data': 'Hello, %s!' % g.current_user})

In this example, a client can get a token by POSTing the correct


username and password to the /tokens endpoint. The token can then be
used to access the protected resource at the /protected endpoint.

By: Waleed Mousa


Step 3: Authorization

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:

# Adding a role to a user


users = {"admin": {"username": "admin", "password": "secret", "role":
"admin", "token": ""}}

@app.route('/admin')
@auth.login_required
def get_admin_resource():
if users[g.current_user]['role'] != 'admin':
abort(403)
return jsonify({'data': 'Hello, admin!'})

Step 4: Rate Limiting

Rate limiting restricts the number of requests a client can make to


your API in a certain amount of time. This can prevent abuse, protect
your server from being overwhelmed by too many requests, and ensure
fair usage of your API.

Step 5: Input Validation

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:

By: Waleed Mousa


@app.route('/items', methods=['POST'])
def create_item():
data = request.get_json()
if 'name' not in data or 'price' not in data:
abort(400, description='Invalid data. "name" and "price" are required
fields.')
# Process data...

Step 6: Error Handling

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.

Flask automatically returns a generic error message for common status


codes. If you want to customize these messages, you can use the
errorhandler decorator:

@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

PART IV: Documenting the API

Good API documentation should include:

1. Overview: This is a high-level introduction that explains what the


API does.
2. Authentication: Explain how users can authenticate with your API.
This could include steps to generate an API key or how to use
OAuth tokens.

By: Waleed Mousa


3. Endpoint descriptions: For each endpoint, describe what it does,
the HTTP method to use, the URL, the request format, and the
response format.
4. Error codes: List possible error codes, what they mean, and steps
to resolve them.
5. Examples: Include code examples in multiple languages if possible.
This can be as simple as a cURL request or as complex as a fully
implemented client.

There are several ways to create API documentation:

Option 1: Manual Documentation

You can manually create API documentation using a word processor or a


documentation platform like Confluence or GitHub Wiki. Here's an example
for our /items endpoint:

## Get All Items

### 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 }]

By: Waleed Mousa


Option 2: Automatic Documentation with Swagger/OpenAPI

The Swagger or OpenAPI specification allows you to create a JSON or YAML


file that describes your API. Tools like Swagger UI can generate
beautiful, interactive documentation from this file.

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

Option 3: Generate Documentation with Sphinx and Flask

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.

By: Waleed Mousa


For example:

@app.route('/items', methods=['GET'])
def get_items():
"""
Get all items.

:return: A list of items.


:rtype: JSON
"""
return jsonify(items)

By running Sphinx, you'll get a nice HTML (or PDF) document that
includes your API documentation.

PART V: Considering Best Practices and Further


Enhancements

When designing an API, keep these principles in mind:

1. Usability: Your API should be easy to use and understand.


2. Consistency: Naming conventions, request and response formats
should be consistent across all endpoints.
3. Security: Secure your API endpoints with authentication and ensure
sensitive data is handled securely.
4. Performance: Optimize your API for fast response times.
5. Error handling: Provide clear error messages when something goes
wrong.
6. Documentation: Provide clear, comprehensive documentation to help
users understand how to use your API.

Additionally, while our example uses a mock database (a list of


dictionaries), a real-world application should use a proper database
system, like PostgreSQL or MongoDB.

By: Waleed Mousa

You might also like