Application Programming Interface API Development Lab Experiments With Solutions
Application Programming Interface API Development Lab Experiments With Solutions
**Experiment**: Design a RESTful API for a hypothetical e-commerce platform. Define endpoints for
products, orders, and users, and determine what HTTP methods should be supported (e.g., `GET`,
`POST`, `PUT`, `DELETE`).
**Solution**:
- **Products Endpoint**:
- `GET /products`: Retrieve a list of products
- `GET /products/{id}`: Retrieve a specific product by ID
- `POST /products`: Add a new product
- `PUT /products/{id}`: Update a product by ID
- `DELETE /products/{id}`: Delete a product by ID
- **Orders Endpoint**:
- `GET /orders`: Retrieve a list of orders
- `POST /orders`: Create a new order
- `PUT /orders/{id}`: Update an order by ID
- **Users Endpoint**:
- `GET /users`: Retrieve a list of users
- `GET /users/{id}`: Retrieve a user by ID
- `POST /users`: Create a new user
- `DELETE /users/{id}`: Delete a user by ID
**Experiment**: Implement a secure authentication mechanism using OAuth2, JWT, or API keys.
Add role-based access control (RBAC) to different endpoints (e.g., only admins can delete products).
**Solution**:
- Use **JWT (JSON Web Token)** for secure stateless authentication:
- Client logs in and receives a JWT token.
- Token is sent in the header of subsequent requests (e.g., `Authorization: Bearer <token>`).
- On the server side, verify the token and decode user info.
- Implement **RBAC**:
- Define roles such as `admin`, `user`, etc.
- Check role-based permissions in middleware before allowing actions like `DELETE /products`.
**Experiment**: Set up rate limiting to prevent abuse. For instance, allow users to call the API 100
times per hour and block further requests once the limit is reached.
**Solution**:
- Use middleware like **express-rate-limit** (for Node.js) or **Django Rest Framework’s
Throttling** (for Python):
- Define rate limits (e.g., `100 requests/hour` per IP address or API key).
- Configure blocking or returning HTTP status code `429 (Too Many Requests)` when the limit is
exceeded.
**Experiment**: Implement error handling and validation mechanisms for inputs. For example,
ensure that a product creation request has all required fields and that their values are valid (e.g.,
price is a positive number).
**Solution**:
- Use schema validation libraries like **Joi** (for Node.js) or **pydantic** (for Python):
- Validate request payloads for required fields and correct data types.
- Return appropriate HTTP error codes such as `400 (Bad Request)` for invalid inputs.
- Example in Node.js:
```javascript
const Joi = require('joi');
const productSchema = Joi.object({
name: Joi.string().required(),
price: Joi.number().greater(0).required(),
});
**Experiment**: Implement versioning for the API so that older clients can still work with the API
even when breaking changes are introduced.
**Solution**:
- Add versioning to the URL or header:
- URL-based versioning: `/api/v1/products`, `/api/v2/products`
- Header-based versioning: Use custom headers like `Accept: application/vnd.company.v1+json`
- Maintain backward compatibility by routing requests to the correct version based on the URL or
header.
**Solution**:
- Use tools like **Swagger** or **Postman** for automatic API documentation:
- Define API endpoints, expected request/response formats, and example inputs/outputs in a YAML
or JSON format (for Swagger).
- Generate interactive API documentation for developers to test endpoints directly in the browser.
- Example Swagger YAML:
```yaml
swagger: "2.0"
info:
version: "1.0.0"
title: "E-commerce API"
paths:
/products:
get:
summary: "Get all products"
responses:
200:
description: "List of products"
```
**Solution**:
- Use a caching layer such as **Redis** or HTTP caching (using response headers like `Cache-
Control`).
- Cache responses for frequent `GET` requests and set an appropriate expiration time.
- Invalidate the cache when data changes (e.g., after a `POST` or `PUT` request).
**Experiment**: Write unit tests and integration tests for the API to ensure that all functionality
works as expected.
**Solution**:
- Use testing libraries like **Mocha/Chai** (for Node.js) or **pytest** (for Python):
- Write unit tests for individual functions like data validation.
- Write integration tests to ensure that endpoints return expected results.
- Example Mocha test:
```javascript
const request = require('supertest');
const app = require('../app');
describe('GET /products', () => {
it('should return all products', async () => {
const res = await request(app).get('/products');
expect(res.statusCode).toEqual(200);
expect(res.body).toBeInstanceOf(Array);
});
});
```
**Experiment**: Implement logging and monitoring to track API usage and identify issues such as
slow response times.
**Solution**:
- Use tools like **Loggly**, **ELK Stack**, or **New Relic** for monitoring and alerting.
- Log requests and responses, along with metadata like response times and error rates.
- Set up alerts for abnormal patterns, like sudden spikes in error rates.
**Experiment**: Implement asynchronous tasks in the API, such as background job processing for
tasks like sending emails after an order is placed.
**Solution**:
- Use job queues like **RabbitMQ** or **Bull** (for Node.js) to handle background tasks:
- When an order is placed, queue the task to send an email confirmation.
- Allow the API to respond immediately while the email is processed asynchronously.
---
These experiments cover many core aspects of API development. For each one, implementing
solutions involves working with relevant frameworks, libraries, and best practices in your tech stack.