From daee7854b9cb630964d55fd4fd4f0341f1786f4b Mon Sep 17 00:00:00 2001 From: Anjor Date: Sat, 14 Feb 2026 16:02:26 +0530 Subject: [PATCH 1/3] Add comprehensive API documentation section Added complete API reference documentation covering core concepts: - HTTP methods (GET, POST, PUT, PATCH, DELETE) - Request and response structure with headers, body, and query parameters - HTTP status codes (2xx, 3xx, 4xx, 5xx) with examples - REST API design principles and best practices - Authentication methods (API keys, JWT, OAuth, Basic Auth) - API testing with Postman, cURL, pytest, and Jest Each topic includes: - Clear explanations and real-world analogies - Working code examples in Python and JavaScript - Best practices and common pitfalls - Complete reference tables Updated main README with API section link in table of contents. --- API/api_testing.md | 910 ++++++++++++++++++++++++++++++++++++++++++++ API/auth.md | 683 +++++++++++++++++++++++++++++++++ API/http.md | 500 ++++++++++++++++++++++++ API/readme.md | 216 +++++++++++ API/req_&_resp.md | 662 ++++++++++++++++++++++++++++++++ API/rest_api.md | 691 +++++++++++++++++++++++++++++++++ API/status_codes.md | 660 ++++++++++++++++++++++++++++++++ README.md | 7 + 8 files changed, 4329 insertions(+) create mode 100644 API/api_testing.md create mode 100644 API/auth.md create mode 100644 API/http.md create mode 100644 API/readme.md create mode 100644 API/req_&_resp.md create mode 100644 API/rest_api.md create mode 100644 API/status_codes.md diff --git a/API/api_testing.md b/API/api_testing.md new file mode 100644 index 0000000..e86b4be --- /dev/null +++ b/API/api_testing.md @@ -0,0 +1,910 @@ +# API Testing + +Testing ensures your API works correctly, handles errors properly, and meets requirements. + +## Table of Contents +- [Why Test APIs?](#why-test-apis) +- [Types of API Tests](#types-of-api-tests) +- [Testing Tools](#testing-tools) +- [Postman](#postman) +- [cURL](#curl) +- [Python Testing](#python-testing) +- [JavaScript Testing](#javascript-testing) +- [Best Practices](#best-practices) + +--- + +## Why Test APIs? + +API testing verifies: +- **Functionality**: Does it work as expected? +- **Reliability**: Does it handle errors gracefully? +- **Performance**: Is it fast enough? +- **Security**: Is data protected? +- **Integration**: Do components work together? + +### Benefits +- Find bugs early +- Ensure quality +- Document API behavior +- Enable refactoring with confidence +- Prevent regression + +--- + +## Types of API Tests + +### 1. Unit Tests + +Test individual functions or endpoints in isolation. + +```python +def test_get_user(): + response = get_user(user_id=42) + assert response.status_code == 200 + assert response.json()["id"] == 42 +``` + +### 2. Integration Tests + +Test how multiple components work together. + +```python +def test_create_and_retrieve_user(): + # Create user + response = create_user({"name": "John"}) + user_id = response.json()["id"] + + # Retrieve user + response = get_user(user_id) + assert response.json()["name"] == "John" +``` + +### 3. Functional Tests + +Test complete workflows from the user's perspective. + +```python +def test_user_registration_flow(): + # 1. Register + # 2. Verify email + # 3. Login + # 4. Access protected resource +``` + +### 4. Load Tests + +Test API performance under heavy load. + +```python +# Simulate 1000 concurrent users +for i in range(1000): + make_request() +``` + +### 5. Security Tests + +Test for vulnerabilities. + +```python +def test_authentication_required(): + response = requests.get("/api/users") + assert response.status_code == 401 +``` + +--- + +## Testing Tools + +### Overview + +| Tool | Type | Best For | +|------|------|----------| +| **Postman** | GUI | Manual testing, exploration | +| **cURL** | CLI | Quick tests, scripts | +| **pytest** | Framework | Python automated tests | +| **Jest** | Framework | JavaScript automated tests | +| **Thunder Client** | VS Code | Testing within editor | +| **Insomnia** | GUI | API design and testing | +| **JMeter** | Load testing | Performance testing | + +--- + +## Postman + +Popular GUI tool for API testing. + +### Basic Usage + +**1. Create Request** +``` +Method: GET +URL: https://api.example.com/users/42 +Headers: + Authorization: Bearer token123 +``` + +**2. Send Request** + +Click "Send" button + +**3. View Response** +```json +{ + "id": 42, + "name": "John Doe", + "email": "john@example.com" +} +``` + +### Collections + +Group related requests together. + +``` +User API Collection +├── Create User (POST /users) +├── Get User (GET /users/:id) +├── Update User (PUT /users/:id) +└── Delete User (DELETE /users/:id) +``` + +### Environment Variables + +Store reusable values. + +``` +{{base_url}} = https://api.example.com +{{api_key}} = abc123xyz789 + +Usage: {{base_url}}/users +``` + +### Tests in Postman + +**JavaScript snippets to validate responses:** + +```javascript +// Test status code +pm.test("Status code is 200", function () { + pm.response.to.have.status(200); +}); + +// Test response time +pm.test("Response time is less than 200ms", function () { + pm.expect(pm.response.responseTime).to.be.below(200); +}); + +// Test response body +pm.test("User has correct name", function () { + var jsonData = pm.response.json(); + pm.expect(jsonData.name).to.eql("John Doe"); +}); + +// Test header +pm.test("Content-Type is JSON", function () { + pm.response.to.have.header("Content-Type", "application/json"); +}); + +// Save response data to variable +pm.environment.set("user_id", pm.response.json().id); +``` + +### Pre-request Scripts + +Run code before sending request. + +```javascript +// Generate timestamp +pm.environment.set("timestamp", new Date().toISOString()); + +// Create signature +const signature = CryptoJS.SHA256(pm.request.url).toString(); +pm.environment.set("signature", signature); +``` + +--- + +## cURL + +Command-line tool for making HTTP requests. + +### Basic Syntax + +```bash +curl [options] [URL] +``` + +### GET Request + +```bash +# Simple GET +curl https://api.example.com/users + +# With headers +curl -H "Authorization: Bearer token123" \ + https://api.example.com/users + +# Pretty print JSON +curl https://api.example.com/users | jq + +# Save to file +curl https://api.example.com/users -o users.json + +# Include response headers +curl -i https://api.example.com/users + +# Verbose output +curl -v https://api.example.com/users +``` + +### POST Request + +```bash +# JSON data +curl -X POST https://api.example.com/users \ + -H "Content-Type: application/json" \ + -d '{ + "name": "John Doe", + "email": "john@example.com" + }' + +# From file +curl -X POST https://api.example.com/users \ + -H "Content-Type: application/json" \ + -d @user.json + +# Form data +curl -X POST https://api.example.com/users \ + -d "name=John Doe" \ + -d "email=john@example.com" +``` + +### PUT Request + +```bash +curl -X PUT https://api.example.com/users/42 \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer token123" \ + -d '{ + "name": "John Doe", + "email": "john.new@example.com" + }' +``` + +### DELETE Request + +```bash +curl -X DELETE https://api.example.com/users/42 \ + -H "Authorization: Bearer token123" +``` + +### Authentication + +```bash +# Bearer token +curl -H "Authorization: Bearer token123" \ + https://api.example.com/users + +# API key +curl -H "X-API-Key: abc123xyz789" \ + https://api.example.com/users + +# Basic auth +curl -u username:password \ + https://api.example.com/users + +# Or +curl -H "Authorization: Basic $(echo -n user:pass | base64)" \ + https://api.example.com/users +``` + +### Common Options + +```bash +-X, --request METHOD # HTTP method (GET, POST, etc.) +-H, --header HEADER # Add header +-d, --data DATA # Request body +-i, --include # Include response headers +-v, --verbose # Verbose output +-o, --output FILE # Save to file +-u, --user USER:PASS # Basic authentication +-L, --location # Follow redirects +-k, --insecure # Ignore SSL certificate errors +``` + +--- + +## Python Testing + +### Using pytest + +**Install** +```bash +pip install pytest requests --break-system-packages +``` + +**Basic Test** +```python +import requests +import pytest + +BASE_URL = "https://api.example.com" + +def test_get_users(): + response = requests.get(f"{BASE_URL}/users") + + assert response.status_code == 200 + assert isinstance(response.json(), list) + +def test_get_specific_user(): + response = requests.get(f"{BASE_URL}/users/42") + + assert response.status_code == 200 + data = response.json() + assert data["id"] == 42 + assert "name" in data + assert "email" in data + +def test_create_user(): + new_user = { + "name": "John Doe", + "email": "john@example.com" + } + + response = requests.post( + f"{BASE_URL}/users", + json=new_user + ) + + assert response.status_code == 201 + data = response.json() + assert data["name"] == new_user["name"] + assert data["email"] == new_user["email"] + assert "id" in data + +def test_update_user(): + update_data = {"email": "john.new@example.com"} + + response = requests.patch( + f"{BASE_URL}/users/42", + json=update_data + ) + + assert response.status_code == 200 + data = response.json() + assert data["email"] == update_data["email"] + +def test_delete_user(): + response = requests.delete(f"{BASE_URL}/users/42") + + assert response.status_code == 204 + +def test_user_not_found(): + response = requests.get(f"{BASE_URL}/users/99999") + + assert response.status_code == 404 + +def test_unauthorized_access(): + response = requests.get(f"{BASE_URL}/admin/users") + + assert response.status_code == 401 +``` + +**Run Tests** +```bash +pytest test_api.py -v +``` + +### Fixtures for Setup/Teardown + +```python +import pytest +import requests + +@pytest.fixture +def api_client(): + """Create authenticated client""" + class APIClient: + def __init__(self): + self.base_url = "https://api.example.com" + self.headers = {"Authorization": "Bearer token123"} + + def get(self, endpoint): + return requests.get( + f"{self.base_url}{endpoint}", + headers=self.headers + ) + + def post(self, endpoint, data): + return requests.post( + f"{self.base_url}{endpoint}", + json=data, + headers=self.headers + ) + + return APIClient() + +@pytest.fixture +def created_user(api_client): + """Create user for testing, cleanup after""" + new_user = { + "name": "Test User", + "email": "test@example.com" + } + + response = api_client.post("/users", new_user) + user = response.json() + + yield user # Test runs here + + # Cleanup + requests.delete( + f"https://api.example.com/users/{user['id']}", + headers=api_client.headers + ) + +def test_get_created_user(api_client, created_user): + response = api_client.get(f"/users/{created_user['id']}") + + assert response.status_code == 200 + assert response.json()["name"] == created_user["name"] +``` + +### Parameterized Tests + +```python +import pytest + +@pytest.mark.parametrize("user_id,expected_status", [ + (1, 200), # Valid user + (2, 200), # Valid user + (999, 404), # Non-existent user +]) +def test_get_user_status(user_id, expected_status): + response = requests.get(f"https://api.example.com/users/{user_id}") + assert response.status_code == expected_status + +@pytest.mark.parametrize("email,expected_valid", [ + ("valid@example.com", True), + ("invalid", False), + ("", False), +]) +def test_email_validation(email, expected_valid): + response = requests.post( + "https://api.example.com/users", + json={"name": "Test", "email": email} + ) + + if expected_valid: + assert response.status_code == 201 + else: + assert response.status_code == 422 +``` + +--- + +## JavaScript Testing + +### Using Jest + +**Install** +```bash +npm install --save-dev jest node-fetch +``` + +**Basic Test** +```javascript +const fetch = require('node-fetch'); + +const BASE_URL = "https://api.example.com"; + +describe('User API', () => { + + test('GET /users returns list', async () => { + const response = await fetch(`${BASE_URL}/users`); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(Array.isArray(data)).toBe(true); + }); + + test('GET /users/:id returns user', async () => { + const response = await fetch(`${BASE_URL}/users/42`); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(data.id).toBe(42); + expect(data).toHaveProperty('name'); + expect(data).toHaveProperty('email'); + }); + + test('POST /users creates user', async () => { + const newUser = { + name: "John Doe", + email: "john@example.com" + }; + + const response = await fetch(`${BASE_URL}/users`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(newUser) + }); + + const data = await response.json(); + + expect(response.status).toBe(201); + expect(data.name).toBe(newUser.name); + expect(data.email).toBe(newUser.email); + expect(data).toHaveProperty('id'); + }); + + test('DELETE /users/:id removes user', async () => { + const response = await fetch(`${BASE_URL}/users/42`, { + method: 'DELETE' + }); + + expect(response.status).toBe(204); + }); + + test('GET /users/99999 returns 404', async () => { + const response = await fetch(`${BASE_URL}/users/99999`); + + expect(response.status).toBe(404); + }); +}); +``` + +**Run Tests** +```bash +npm test +``` + +### Setup and Teardown + +```javascript +let createdUserId; + +beforeAll(async () => { + // Runs once before all tests + console.log('Setting up tests...'); +}); + +beforeEach(async () => { + // Runs before each test + const newUser = { + name: "Test User", + email: "test@example.com" + }; + + const response = await fetch(`${BASE_URL}/users`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(newUser) + }); + + const data = await response.json(); + createdUserId = data.id; +}); + +afterEach(async () => { + // Runs after each test - cleanup + if (createdUserId) { + await fetch(`${BASE_URL}/users/${createdUserId}`, { + method: 'DELETE' + }); + } +}); + +afterAll(async () => { + // Runs once after all tests + console.log('Tests complete!'); +}); + +test('can get created user', async () => { + const response = await fetch(`${BASE_URL}/users/${createdUserId}`); + expect(response.status).toBe(200); +}); +``` + +--- + +## Best Practices + +### 1. Test Both Success and Failure Cases + +```python +def test_success_case(): + response = requests.get("/api/users/42") + assert response.status_code == 200 + +def test_not_found(): + response = requests.get("/api/users/99999") + assert response.status_code == 404 + +def test_unauthorized(): + response = requests.get("/api/admin/users") + assert response.status_code == 401 + +def test_invalid_data(): + response = requests.post( + "/api/users", + json={"email": "invalid"} # Missing required field + ) + assert response.status_code == 422 +``` + +### 2. Use Meaningful Test Names + +```python +# Good +def test_get_user_returns_user_data_when_user_exists(): + pass + +def test_get_user_returns_404_when_user_not_found(): + pass + +# Bad +def test_1(): + pass + +def test_user(): + pass +``` + +### 3. Test One Thing Per Test + +```python +# Good - separate tests +def test_create_user_returns_201(): + response = create_user({"name": "John"}) + assert response.status_code == 201 + +def test_create_user_returns_user_data(): + response = create_user({"name": "John"}) + assert response.json()["name"] == "John" + +# Bad - testing multiple things +def test_create_user(): + response = create_user({"name": "John"}) + assert response.status_code == 201 + assert response.json()["name"] == "John" + assert "id" in response.json() + # ... many more assertions +``` + +### 4. Clean Up Test Data + +```python +def test_user_workflow(): + # Create + response = create_user({"name": "Test User"}) + user_id = response.json()["id"] + + try: + # Test operations + # ... + finally: + # Always cleanup + delete_user(user_id) +``` + +### 5. Use Environment Variables + +```python +import os + +# Don't hardcode URLs or credentials +BASE_URL = os.environ.get("API_BASE_URL", "http://localhost:5000") +API_KEY = os.environ.get("API_KEY") +``` + +### 6. Test Response Schema + +```python +def test_user_response_schema(): + response = requests.get("/api/users/42") + data = response.json() + + # Check all expected fields are present + required_fields = ["id", "name", "email", "created_at"] + for field in required_fields: + assert field in data + + # Check field types + assert isinstance(data["id"], int) + assert isinstance(data["name"], str) + assert isinstance(data["email"], str) +``` + +### 7. Test Error Messages + +```python +def test_validation_error_message(): + response = requests.post( + "/api/users", + json={"name": "John"} # Missing email + ) + + assert response.status_code == 422 + error = response.json() + assert "email" in error["errors"] + assert "required" in error["errors"]["email"].lower() +``` + +### 8. Use Mocking for External Services + +```python +from unittest.mock import patch + +@patch('requests.get') +def test_external_api_call(mock_get): + # Mock external API response + mock_get.return_value.json.return_value = { + "data": "mocked data" + } + mock_get.return_value.status_code = 200 + + # Your code that calls the external API + result = fetch_external_data() + + assert result == "mocked data" +``` + +--- + +## Complete Testing Example + +**test_user_api.py** +```python +import pytest +import requests +import os + +BASE_URL = os.environ.get("API_BASE_URL", "http://localhost:5000") +API_KEY = os.environ.get("API_KEY", "test-key") + +class TestUserAPI: + + @pytest.fixture + def headers(self): + return {"Authorization": f"Bearer {API_KEY}"} + + @pytest.fixture + def test_user(self, headers): + """Create and cleanup test user""" + new_user = { + "name": "Test User", + "email": "test@example.com", + "age": 25 + } + + response = requests.post( + f"{BASE_URL}/users", + json=new_user, + headers=headers + ) + + user = response.json() + yield user + + # Cleanup + requests.delete( + f"{BASE_URL}/users/{user['id']}", + headers=headers + ) + + def test_create_user_success(self, headers): + new_user = { + "name": "John Doe", + "email": "john@example.com", + "age": 30 + } + + response = requests.post( + f"{BASE_URL}/users", + json=new_user, + headers=headers + ) + + assert response.status_code == 201 + data = response.json() + assert data["name"] == new_user["name"] + assert data["email"] == new_user["email"] + assert "id" in data + + # Cleanup + requests.delete(f"{BASE_URL}/users/{data['id']}", headers=headers) + + def test_get_users_list(self, headers): + response = requests.get(f"{BASE_URL}/users", headers=headers) + + assert response.status_code == 200 + assert isinstance(response.json(), list) + + def test_get_user_by_id(self, headers, test_user): + response = requests.get( + f"{BASE_URL}/users/{test_user['id']}", + headers=headers + ) + + assert response.status_code == 200 + data = response.json() + assert data["id"] == test_user["id"] + assert data["name"] == test_user["name"] + + def test_update_user(self, headers, test_user): + update_data = {"email": "newemail@example.com"} + + response = requests.patch( + f"{BASE_URL}/users/{test_user['id']}", + json=update_data, + headers=headers + ) + + assert response.status_code == 200 + data = response.json() + assert data["email"] == update_data["email"] + + def test_delete_user(self, headers, test_user): + response = requests.delete( + f"{BASE_URL}/users/{test_user['id']}", + headers=headers + ) + + assert response.status_code == 204 + + def test_user_not_found(self, headers): + response = requests.get( + f"{BASE_URL}/users/99999", + headers=headers + ) + + assert response.status_code == 404 + + def test_unauthorized_access(self): + response = requests.get(f"{BASE_URL}/users") + assert response.status_code == 401 + + @pytest.mark.parametrize("invalid_email", [ + "notanemail", + "", + "missing@domain", + ]) + def test_invalid_email_validation(self, headers, invalid_email): + new_user = { + "name": "John", + "email": invalid_email + } + + response = requests.post( + f"{BASE_URL}/users", + json=new_user, + headers=headers + ) + + assert response.status_code == 422 +``` + +--- + +## Summary + +**Key Testing Principles:** +- Test both success and failure cases +- Use meaningful test names +- Clean up test data +- Test one thing per test +- Use fixtures for setup/teardown +- Parameterize similar tests +- Mock external dependencies +- Test response schemas +- Validate error messages + +**Tools:** +- Postman: GUI, manual testing +- cURL: Quick CLI tests +- pytest: Python automated testing +- Jest: JavaScript automated testing \ No newline at end of file diff --git a/API/auth.md b/API/auth.md new file mode 100644 index 0000000..ff106f9 --- /dev/null +++ b/API/auth.md @@ -0,0 +1,683 @@ +# API Authentication + +Authentication verifies the identity of a user or application accessing an API. + +## Table of Contents +- [Why Authentication?](#why-authentication) +- [Authentication vs Authorization](#authentication-vs-authorization) +- [API Keys](#api-keys) +- [Bearer Tokens](#bearer-tokens) +- [JWT (JSON Web Tokens)](#jwt-json-web-tokens) +- [OAuth 2.0](#oauth-20) +- [Basic Authentication](#basic-authentication) +- [Comparison Table](#comparison-table) +- [Best Practices](#best-practices) + +--- + +## Why Authentication? + +Authentication is essential for: +- **Security**: Protect sensitive data +- **Rate Limiting**: Control API usage per user +- **Analytics**: Track who uses what +- **Access Control**: Restrict certain operations +- **Billing**: Charge based on usage + +--- + +## Authentication vs Authorization + +| Aspect | Authentication | Authorization | +|--------|---------------|---------------| +| Question | Who are you? | What can you do? | +| Process | Verify identity | Check permissions | +| Example | Login with password | Admin vs regular user | +| HTTP Code | 401 Unauthorized | 403 Forbidden | + +**Example** +``` +Authentication: "I am user John" (verified by password/token) +Authorization: "Can John delete this post?" (checked against permissions) +``` + +--- + +## API Keys + +Simple authentication using a unique key. + +### How It Works + +1. Generate API key (long random string) +2. Include key in every request +3. Server validates key + +### Implementation + +**Request with API Key** +``` +GET /api/users +Host: api.example.com +X-API-Key: abc123xyz789 +``` + +**Python Example** +```python +import requests + +API_KEY = "abc123xyz789" + +# Method 1: Header +headers = {"X-API-Key": API_KEY} +response = requests.get("https://api.example.com/users", headers=headers) + +# Method 2: Query parameter (less secure) +params = {"api_key": API_KEY} +response = requests.get("https://api.example.com/users", params=params) +``` + +**JavaScript Example** +```javascript +const API_KEY = "abc123xyz789"; + +// Using header +fetch("https://api.example.com/users", { + headers: { + "X-API-Key": API_KEY + } +}) + .then(res => res.json()) + .then(data => console.log(data)); +``` + +### Pros and Cons + +**Pros:** +- Simple to implement +- Easy to understand +- No expiration needed + +**Cons:** +- If leaked, valid until manually revoked +- Hard to rotate +- No built-in expiration +- Usually tied to account, not user + +### Use Cases +- Internal APIs +- Server-to-server communication +- Third-party service integration (Stripe, SendGrid) + +--- + +## Bearer Tokens + +Generic token passed in Authorization header. + +### How It Works + +1. User logs in +2. Server generates token +3. Client includes token in subsequent requests +4. Server validates token + +### Implementation + +**Request with Bearer Token** +``` +GET /api/users +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**Python Example** +```python +import requests + +TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + +headers = {"Authorization": f"Bearer {TOKEN}"} +response = requests.get("https://api.example.com/users", headers=headers) + +print(response.json()) +``` + +**JavaScript Example** +```javascript +const TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."; + +fetch("https://api.example.com/users", { + headers: { + "Authorization": `Bearer ${TOKEN}` + } +}) + .then(res => res.json()) + .then(data => console.log(data)); +``` + +### Complete Login Flow + +**Python** +```python +import requests + +# Step 1: Login +login_data = { + "username": "john@example.com", + "password": "secret123" +} + +response = requests.post( + "https://api.example.com/auth/login", + json=login_data +) + +if response.status_code == 200: + token = response.json()["token"] + print(f"Token: {token}") + + # Step 2: Use token for authenticated requests + headers = {"Authorization": f"Bearer {token}"} + + response = requests.get( + "https://api.example.com/users/me", + headers=headers + ) + + print(response.json()) +``` + +**JavaScript** +```javascript +async function loginAndFetch() { + // Step 1: Login + const loginResponse = await fetch("https://api.example.com/auth/login", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + username: "john@example.com", + password: "secret123" + }) + }); + + const { token } = await loginResponse.json(); + console.log(`Token: ${token}`); + + // Step 2: Use token + const userResponse = await fetch("https://api.example.com/users/me", { + headers: { + "Authorization": `Bearer ${token}` + } + }); + + const user = await userResponse.json(); + console.log(user); +} +``` + +--- + +## JWT (JSON Web Tokens) + +Self-contained tokens that carry user information. + +### Structure + +JWT has three parts separated by dots: +``` +header.payload.signature +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo0MiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoxNjMzMDcyODAwfQ.4pcPyMD09olPSyXnrXCjTwXyr4BsezdI1AVTmud2fU4 +``` + +**Header** +```json +{ + "alg": "HS256", + "typ": "JWT" +} +``` + +**Payload (Claims)** +```json +{ + "user_id": 42, + "name": "John Doe", + "email": "john@example.com", + "exp": 1633072800, + "iat": 1633069200 +} +``` + +**Signature** +``` +HMACSHA256( + base64UrlEncode(header) + "." + + base64UrlEncode(payload), + secret +) +``` + +### Standard Claims + +| Claim | Meaning | +|-------|---------| +| **iss** | Issuer | +| **sub** | Subject (user ID) | +| **aud** | Audience | +| **exp** | Expiration time | +| **iat** | Issued at | +| **nbf** | Not before | + +### Implementation + +**Python - Creating JWT** +```python +import jwt +from datetime import datetime, timedelta + +# Create JWT +payload = { + "user_id": 42, + "name": "John Doe", + "exp": datetime.utcnow() + timedelta(hours=1) # Expires in 1 hour +} + +secret = "your-secret-key" +token = jwt.encode(payload, secret, algorithm="HS256") + +print(token) +``` + +**Python - Verifying JWT** +```python +import jwt + +token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +secret = "your-secret-key" + +try: + payload = jwt.decode(token, secret, algorithms=["HS256"]) + print(f"User ID: {payload['user_id']}") + print(f"Name: {payload['name']}") +except jwt.ExpiredSignatureError: + print("Token has expired") +except jwt.InvalidTokenError: + print("Invalid token") +``` + +**JavaScript - Verifying JWT** +```javascript +// Using jsonwebtoken library +const jwt = require('jsonwebtoken'); + +const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."; +const secret = "your-secret-key"; + +try { + const payload = jwt.verify(token, secret); + console.log(`User ID: ${payload.user_id}`); + console.log(`Name: ${payload.name}`); +} catch (error) { + if (error.name === 'TokenExpiredError') { + console.log('Token has expired'); + } else { + console.log('Invalid token'); + } +} +``` + +### Refresh Tokens + +Long-lived tokens used to get new access tokens. + +```python +import requests + +# Use refresh token to get new access token +refresh_token = "long_lived_refresh_token" + +response = requests.post( + "https://api.example.com/auth/refresh", + json={"refresh_token": refresh_token} +) + +if response.status_code == 200: + new_access_token = response.json()["access_token"] + print(f"New access token: {new_access_token}") +``` + +**Typical Flow:** +1. Login → Receive access token (short-lived) + refresh token (long-lived) +2. Use access token for API calls +3. When access token expires, use refresh token to get new access token +4. Repeat until refresh token expires + +### Pros and Cons + +**Pros:** +- Self-contained (server doesn't need to store sessions) +- Can include user data +- Supports expiration +- Stateless + +**Cons:** +- Cannot be revoked before expiration (unless using token blacklist) +- Larger than simple tokens +- Payload is readable (base64 encoded, not encrypted) + +--- + +## OAuth 2.0 + +Industry-standard authorization framework. + +### Common Use Cases +- "Login with Google" +- "Login with Facebook" +- "Login with GitHub" + +### OAuth Roles + +- **Resource Owner**: User +- **Client**: Your application +- **Resource Server**: API server +- **Authorization Server**: Issues tokens + +### Authorization Code Flow + +``` +1. User clicks "Login with Google" +2. Redirected to Google login page +3. User logs in and grants permissions +4. Google redirects back with authorization code +5. Your server exchanges code for access token +6. Use access token to access user's Google data +``` + +### Implementation Example + +**Python - GitHub OAuth** +```python +import requests + +# Step 1: Redirect user to GitHub authorization +client_id = "your_client_id" +redirect_uri = "http://localhost:5000/callback" +scope = "user:email" + +auth_url = ( + f"https://github.com/login/oauth/authorize" + f"?client_id={client_id}" + f"&redirect_uri={redirect_uri}" + f"&scope={scope}" +) + +print(f"Visit: {auth_url}") + +# Step 2: User is redirected back with code +# http://localhost:5000/callback?code=abc123 + +# Step 3: Exchange code for access token +code = "abc123" # From callback URL +client_secret = "your_client_secret" + +response = requests.post( + "https://github.com/login/oauth/access_token", + data={ + "client_id": client_id, + "client_secret": client_secret, + "code": code + }, + headers={"Accept": "application/json"} +) + +access_token = response.json()["access_token"] + +# Step 4: Use access token to get user data +headers = {"Authorization": f"Bearer {access_token}"} +response = requests.get("https://api.github.com/user", headers=headers) + +user = response.json() +print(f"GitHub user: {user['login']}") +``` + +### OAuth Scopes + +Scopes define what access the token grants. + +```python +# Read-only access to user profile +scope = "user:email" + +# Read and write access +scope = "repo user:email" + +# Limited access +scope = "read:user" +``` + +--- + +## Basic Authentication + +Username and password sent with each request. + +### How It Works + +1. Combine username and password: `username:password` +2. Encode with Base64 +3. Send in Authorization header + +### Implementation + +**Manual Example** +```python +import base64 +import requests + +username = "john@example.com" +password = "secret123" + +# Encode credentials +credentials = f"{username}:{password}" +encoded = base64.b64encode(credentials.encode()).decode() + +headers = {"Authorization": f"Basic {encoded}"} +response = requests.get("https://api.example.com/users", headers=headers) +``` + +**Using Requests Library** +```python +import requests + +response = requests.get( + "https://api.example.com/users", + auth=("john@example.com", "secret123") # Automatically encodes +) + +print(response.json()) +``` + +**JavaScript Example** +```javascript +const username = "john@example.com"; +const password = "secret123"; + +// Encode credentials +const credentials = btoa(`${username}:${password}`); + +fetch("https://api.example.com/users", { + headers: { + "Authorization": `Basic ${credentials}` + } +}) + .then(res => res.json()) + .then(data => console.log(data)); +``` + +### Pros and Cons + +**Pros:** +- Simple to implement +- Widely supported +- No session management + +**Cons:** +- Sends credentials with every request +- Must use HTTPS (credentials easily decoded) +- No built-in token expiration +- Password changes break all sessions + +### When to Use +- Internal tools +- Quick prototypes +- When combined with HTTPS + +--- + +## Comparison Table + +| Method | Security | Complexity | Expiration | Best For | +|--------|----------|------------|------------|----------| +| **API Key** | Low-Medium | Low | Manual | Server-to-server | +| **Bearer Token** | Medium | Medium | Yes | Modern APIs | +| **JWT** | Medium-High | Medium | Yes | Stateless APIs | +| **OAuth 2.0** | High | High | Yes | Third-party auth | +| **Basic Auth** | Low | Low | No | Internal tools | + +--- + +## Best Practices + +### 1. Always Use HTTPS + +**Never** send authentication credentials over HTTP. + +```python +# Good +response = requests.get("https://api.example.com/users", headers=headers) + +# Bad - credentials can be intercepted +response = requests.get("http://api.example.com/users", headers=headers) +``` + +### 2. Store Tokens Securely + +**Never** store tokens in: +- URL parameters +- Local storage (for sensitive tokens) +- Git repositories +- Plain text files + +**Do** store tokens in: +- Environment variables +- Secure credential managers +- HTTP-only cookies (for web apps) + +```python +import os + +# Good - from environment variable +API_KEY = os.environ.get("API_KEY") + +# Bad - hardcoded +API_KEY = "abc123xyz789" +``` + +### 3. Use Token Expiration + +```python +# Short-lived access tokens +access_token_expiry = 1 hour + +# Long-lived refresh tokens +refresh_token_expiry = 30 days +``` + +### 4. Implement Rate Limiting + +```python +# Limit requests per user +max_requests_per_hour = 1000 +``` + +### 5. Validate Tokens on Server + +```python +def validate_token(token): + try: + payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"]) + + # Check if token is expired + if payload["exp"] < time.time(): + return None + + # Check if user still exists + user = get_user(payload["user_id"]) + if not user: + return None + + return payload + except: + return None +``` + +### 6. Handle Token Refresh + +```python +import requests + +def make_authenticated_request(url, access_token, refresh_token): + headers = {"Authorization": f"Bearer {access_token}"} + response = requests.get(url, headers=headers) + + # If access token expired + if response.status_code == 401: + # Refresh access token + refresh_response = requests.post( + "https://api.example.com/auth/refresh", + json={"refresh_token": refresh_token} + ) + + if refresh_response.status_code == 200: + new_access_token = refresh_response.json()["access_token"] + + # Retry original request + headers = {"Authorization": f"Bearer {new_access_token}"} + response = requests.get(url, headers=headers) + + return response +``` + +### 7. Log Authentication Attempts + +```python +# Log failed login attempts +failed_attempts[user_id] += 1 + +# Block after too many failures +if failed_attempts[user_id] > 5: + block_user(user_id, duration=timedelta(minutes=15)) +``` + +--- + +## Summary + +**Choose authentication based on your needs:** + +- **API Key**: Simple internal APIs +- **Bearer Token**: Modern stateless APIs +- **JWT**: Microservices, stateless architecture +- **OAuth 2.0**: Third-party authentication +- **Basic Auth**: Quick prototypes, HTTPS required + +**Key Principles:** +- Always use HTTPS +- Store tokens securely +- Implement expiration +- Validate on server +- Handle refresh gracefully +- Log authentication events \ No newline at end of file diff --git a/API/http.md b/API/http.md new file mode 100644 index 0000000..9cf2a66 --- /dev/null +++ b/API/http.md @@ -0,0 +1,500 @@ +# HTTP Methods + +HTTP methods (also called HTTP verbs) define the type of operation to perform on a resource. + +## Table of Contents +- [Overview](#overview) +- [GET](#get) +- [POST](#post) +- [PUT](#put) +- [PATCH](#patch) +- [DELETE](#delete) +- [HEAD](#head) +- [OPTIONS](#options) +- [Method Comparison](#method-comparison) + +--- + +## Overview + +HTTP methods indicate the desired action to be performed on a resource. The most commonly used methods are: + +| Method | Purpose | Safe | Idempotent | +|--------|---------|------|------------| +| GET | Retrieve data | Yes | Yes | +| POST | Create new resource | No | No | +| PUT | Update/Replace resource | No | Yes | +| PATCH | Partial update | No | No | +| DELETE | Remove resource | No | Yes | + +**Safe**: Method doesn't modify data +**Idempotent**: Multiple identical requests have the same effect as one request + +--- + +## GET + +**Purpose**: Retrieve data from the server + +### Characteristics +- **Read-only operation** +- Data sent via URL (query parameters) +- Can be cached +- Can be bookmarked +- Should not modify server state + +### Syntax +``` +GET /api/users HTTP/1.1 +Host: example.com +``` + +### Examples + +**Python** +```python +import requests + +# Get all users +response = requests.get("https://api.example.com/users") +print(response.json()) + +# Get specific user +response = requests.get("https://api.example.com/users/123") +print(response.json()) + +# Get with query parameters +params = {"age": 25, "city": "Mumbai"} +response = requests.get("https://api.example.com/users", params=params) +print(response.json()) +``` + +**JavaScript** +```javascript +// Get all users +fetch("https://api.example.com/users") + .then(res => res.json()) + .then(data => console.log(data)); + +// Get specific user +fetch("https://api.example.com/users/123") + .then(res => res.json()) + .then(data => console.log(data)); + +// Get with query parameters +fetch("https://api.example.com/users?age=25&city=Mumbai") + .then(res => res.json()) + .then(data => console.log(data)); +``` + +**cURL** +```bash +# Get all users +curl https://api.example.com/users + +# Get specific user +curl https://api.example.com/users/123 + +# Get with query parameters +curl "https://api.example.com/users?age=25&city=Mumbai" +``` + +### Use Cases +- Fetching a list of items +- Retrieving a single resource +- Searching with filters +- Reading configuration data + +--- + +## POST + +**Purpose**: Create a new resource or submit data + +### Characteristics +- **Creates new data** +- Data sent in request body +- Not idempotent (multiple requests create multiple resources) +- Not cacheable +- Cannot be bookmarked + +### Syntax +``` +POST /api/users HTTP/1.1 +Host: example.com +Content-Type: application/json + +{ + "name": "John Doe", + "email": "john@example.com" +} +``` + +### Examples + +**Python** +```python +import requests + +# Create new user +new_user = { + "name": "John Doe", + "email": "john@example.com", + "age": 30 +} + +response = requests.post( + "https://api.example.com/users", + json=new_user +) + +print(response.status_code) # 201 Created +print(response.json()) +``` + +**JavaScript** +```javascript +// Create new user +const newUser = { + name: "John Doe", + email: "john@example.com", + age: 30 +}; + +fetch("https://api.example.com/users", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(newUser) +}) + .then(res => res.json()) + .then(data => console.log(data)); +``` + +**cURL** +```bash +curl -X POST https://api.example.com/users \ + -H "Content-Type: application/json" \ + -d '{ + "name": "John Doe", + "email": "john@example.com", + "age": 30 + }' +``` + +### Use Cases +- Creating a new user account +- Submitting a form +- Uploading a file +- Adding an item to a cart + +--- + +## PUT + +**Purpose**: Update or replace an entire resource + +### Characteristics +- **Replaces entire resource** +- Idempotent (multiple identical requests have same effect) +- Requires sending complete resource data +- Creates resource if it doesn't exist (sometimes) + +### Syntax +``` +PUT /api/users/123 HTTP/1.1 +Host: example.com +Content-Type: application/json + +{ + "name": "John Doe", + "email": "john.doe@example.com", + "age": 31 +} +``` + +### Examples + +**Python** +```python +import requests + +# Update entire user resource +updated_user = { + "name": "John Doe", + "email": "john.doe@example.com", + "age": 31, + "city": "Mumbai" +} + +response = requests.put( + "https://api.example.com/users/123", + json=updated_user +) + +print(response.status_code) # 200 OK +print(response.json()) +``` + +**JavaScript** +```javascript +// Update entire user resource +const updatedUser = { + name: "John Doe", + email: "john.doe@example.com", + age: 31, + city: "Mumbai" +}; + +fetch("https://api.example.com/users/123", { + method: "PUT", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(updatedUser) +}) + .then(res => res.json()) + .then(data => console.log(data)); +``` + +**cURL** +```bash +curl -X PUT https://api.example.com/users/123 \ + -H "Content-Type: application/json" \ + -d '{ + "name": "John Doe", + "email": "john.doe@example.com", + "age": 31, + "city": "Mumbai" + }' +``` + +### Use Cases +- Replacing user profile completely +- Updating configuration settings +- Overwriting a document + +--- + +## PATCH + +**Purpose**: Partially update a resource + +### Characteristics +- **Updates specific fields only** +- More efficient than PUT for small changes +- Not necessarily idempotent +- Requires only changed fields + +### Syntax +``` +PATCH /api/users/123 HTTP/1.1 +Host: example.com +Content-Type: application/json + +{ + "email": "newemail@example.com" +} +``` + +### Examples + +**Python** +```python +import requests + +# Update only email field +partial_update = { + "email": "newemail@example.com" +} + +response = requests.patch( + "https://api.example.com/users/123", + json=partial_update +) + +print(response.status_code) # 200 OK +print(response.json()) +``` + +**JavaScript** +```javascript +// Update only email field +const partialUpdate = { + email: "newemail@example.com" +}; + +fetch("https://api.example.com/users/123", { + method: "PATCH", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(partialUpdate) +}) + .then(res => res.json()) + .then(data => console.log(data)); +``` + +**cURL** +```bash +curl -X PATCH https://api.example.com/users/123 \ + -H "Content-Type: application/json" \ + -d '{ + "email": "newemail@example.com" + }' +``` + +### Use Cases +- Updating a single field (email, password) +- Marking item as complete +- Incrementing a counter + +--- + +## DELETE + +**Purpose**: Remove a resource from the server + +### Characteristics +- **Deletes data** +- Idempotent (deleting same resource multiple times has same effect) +- Usually returns 204 No Content or 200 OK +- No request body needed + +### Syntax +``` +DELETE /api/users/123 HTTP/1.1 +Host: example.com +``` + +### Examples + +**Python** +```python +import requests + +# Delete user +response = requests.delete("https://api.example.com/users/123") + +print(response.status_code) # 204 No Content or 200 OK +``` + +**JavaScript** +```javascript +// Delete user +fetch("https://api.example.com/users/123", { + method: "DELETE" +}) + .then(res => { + if (res.status === 204) { + console.log("User deleted successfully"); + } + }); +``` + +**cURL** +```bash +curl -X DELETE https://api.example.com/users/123 +``` + +### Use Cases +- Deleting a user account +- Removing an item from cart +- Canceling a subscription + +--- + +## HEAD + +**Purpose**: Same as GET, but only retrieves headers (no body) + +### Use Cases +- Checking if resource exists +- Getting metadata (content length, last modified) +- Verifying link validity + +### Example +```bash +curl -I https://api.example.com/users/123 +``` + +--- + +## OPTIONS + +**Purpose**: Describes communication options for the target resource + +### Use Cases +- CORS preflight requests +- Discovering allowed methods +- Checking API capabilities + +### Example +```bash +curl -X OPTIONS https://api.example.com/users +``` + +--- + +## Method Comparison + +### PUT vs PATCH + +| Aspect | PUT | PATCH | +|--------|-----|-------| +| Update Type | Full replacement | Partial update | +| Fields Required | All fields | Only changed fields | +| Idempotent | Yes | Not guaranteed | +| Bandwidth | More data sent | Less data sent | + +**Example Scenario**: Updating user email + +**PUT** (must send all fields) +```json +{ + "name": "John Doe", + "email": "newemail@example.com", + "age": 30, + "city": "Mumbai" +} +``` + +**PATCH** (send only changed field) +```json +{ + "email": "newemail@example.com" +} +``` + +### POST vs PUT + +| Aspect | POST | PUT | +|--------|------|-----| +| Purpose | Create new | Update existing | +| Idempotent | No | Yes | +| Resource ID | Server generates | Client provides | +| Use Case | Unknown ID | Known ID | + +--- + +## Best Practices + +1. **Use the correct method**: Don't use POST for everything +2. **Follow REST conventions**: Use methods as intended +3. **Be idempotent when possible**: Makes APIs more reliable +4. **Use PATCH for small updates**: More efficient than PUT +5. **Return appropriate status codes**: 201 for POST, 204 for DELETE +6. **Don't use GET to modify data**: Breaks expectations and caching + +--- + +## Summary + +- **GET**: Read data +- **POST**: Create new +- **PUT**: Replace entire resource +- **PATCH**: Update specific fields +- **DELETE**: Remove resource + +Choose the method that best matches your operation's intent. \ No newline at end of file diff --git a/API/readme.md b/API/readme.md new file mode 100644 index 0000000..e142c32 --- /dev/null +++ b/API/readme.md @@ -0,0 +1,216 @@ +# API (Application Programming Interface) + +## Table of Contents +- [What is an API?](#what-is-an-api) +- [How APIs Work](#how-apis-work) +- [Client-Server Architecture](#client-server-architecture) +- [HTTP Methods](#http-methods) +- [Request and Response](#request-and-response) +- [Status Codes](#status-codes) +- [REST API](#rest-api) +- [Authentication](#authentication) +- [API Testing](#api-testing) + +--- + +## What is an API? + +An **API (Application Programming Interface)** is a set of rules and protocols that allows different software applications to communicate with each other. It acts as an intermediary that enables data exchange between systems. + +### Real-World Analogy + +Think of an API like a **waiter in a restaurant**: +- **You (Client)**: You look at the menu and decide what you want +- **Waiter (API)**: Takes your order to the kitchen +- **Kitchen (Server)**: Prepares your food +- **Waiter (API)**: Brings the food back to you + +The waiter (API) is the messenger between you and the kitchen, just like an API is the messenger between your application and a server. + +### Why APIs Matter + +- **Integration**: Connect different services (payment gateways, weather data, social media) +- **Efficiency**: Reuse existing functionality instead of building from scratch +- **Scalability**: Separate frontend and backend concerns +- **Security**: Control access to data and functionality + +--- + +## How APIs Work + +APIs enable communication through **requests** and **responses**: + +1. **Client** sends a request to the API +2. **API** processes the request and communicates with the server +3. **Server** performs the operation and sends data back +4. **API** returns the response to the client + +``` +[Client Application] + ↓ (Request) + [API Layer] + ↓ + [Server/Database] + ↓ + [API Layer] + ↓ (Response) +[Client Application] +``` + +--- + +## Client-Server Architecture + +### Client +The **client** is the application or device that requests data: +- Web browsers +- Mobile apps +- Desktop applications +- Other servers + +### Server +The **server** is the system that provides data or services: +- Stores data in databases +- Processes business logic +- Manages authentication +- Returns responses to clients + +### Communication Flow +``` +Client → Request → API → Server → Database + ↓ +Client ← Response ← API ← Server +``` + +--- + +## HTTP Methods + +APIs use HTTP methods to perform different operations. See [http.md](http.md) for detailed information. + +### Quick Reference + +| Method | Purpose | Example | +|--------|---------|---------| +| **GET** | Retrieve data | Get user profile | +| **POST** | Create new data | Create new user | +| **PUT** | Update entire resource | Replace user data | +| **PATCH** | Partial update | Update user email only | +| **DELETE** | Remove data | Delete user account | + +--- + +## Request and Response + +Every API interaction consists of a **request** from the client and a **response** from the server. See [req_&_resp.md](req_&_resp.md) for complete details. + +### Request Components +- **URL/Endpoint**: Where to send the request +- **Method**: What operation to perform +- **Headers**: Metadata about the request +- **Body**: Data being sent (for POST/PUT/PATCH) + +### Response Components +- **Status Code**: Success or error indicator +- **Headers**: Metadata about the response +- **Body**: Data returned from the server + +--- + +## Status Codes + +HTTP status codes indicate the result of an API request. See [status_codes.md](status_codes.md) for the complete list. + +### Categories + +- **2xx Success**: Request succeeded +- **3xx Redirection**: Further action needed +- **4xx Client Error**: Problem with the request +- **5xx Server Error**: Server failed to process request + +--- + +## REST API + +**REST (Representational State Transfer)** is an architectural style for designing APIs. See [rest_api.md](rest_api.md) for comprehensive coverage. + +### Key Principles +- **Stateless**: Each request contains all necessary information +- **Resource-based**: Everything is a resource with a unique URL +- **Standard methods**: Use HTTP methods appropriately +- **JSON format**: Typically use JSON for data exchange + +--- + +## Authentication + +Authentication ensures only authorized users can access API resources. See [auth.md](auth.md) for security details. + +### Common Methods +- **API Keys**: Simple token passed in headers +- **OAuth**: Industry-standard authorization framework +- **JWT (JSON Web Tokens)**: Encoded tokens with user data +- **Basic Auth**: Username and password encoded in headers + +--- + +## API Testing + +Testing ensures your API works correctly and handles errors properly. See [api_testing.md](api_testing.md) for testing strategies. + +### Popular Tools +- **Postman**: GUI-based API testing +- **cURL**: Command-line tool +- **Thunder Client**: VS Code extension +- **Insomnia**: API design and testing platform + +--- + +## Quick Start Example + +### Python Example +```python +import requests + +# GET request +response = requests.get("https://api.example.com/users") +print(response.json()) + +# POST request +new_user = {"name": "John Doe", "email": "john@example.com"} +response = requests.post("https://api.example.com/users", json=new_user) +print(response.status_code) +``` + +### JavaScript Example +```javascript +// GET request +fetch("https://api.example.com/users") + .then(res => res.json()) + .then(data => console.log(data)); + +// POST request +fetch("https://api.example.com/users", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + name: "John Doe", + email: "john@example.com" + }) +}) + .then(res => res.json()) + .then(data => console.log(data)); +``` + +--- + +## Further Reading + +- [HTTP Methods](http.md) - Detailed guide to GET, POST, PUT, DELETE, PATCH +- [Request & Response](req_&_resp.md) - Structure and examples +- [Status Codes](status_codes.md) - Complete reference guide +- [REST API](rest_api.md) - Design principles and best practices +- [Authentication](auth.md) - Security methods and implementation +- [API Testing](api_testing.md) - Tools and techniques \ No newline at end of file diff --git a/API/req_&_resp.md b/API/req_&_resp.md new file mode 100644 index 0000000..5a925cb --- /dev/null +++ b/API/req_&_resp.md @@ -0,0 +1,662 @@ +# Request and Response + +Every API interaction consists of a **request** sent by the client and a **response** returned by the server. + +## Table of Contents +- [Request Structure](#request-structure) +- [Response Structure](#response-structure) +- [Headers](#headers) +- [Request Body](#request-body) +- [Response Body](#response-body) +- [Query Parameters](#query-parameters) +- [Complete Examples](#complete-examples) + +--- + +## Request Structure + +An HTTP request consists of: + +``` +[METHOD] [URL] HTTP/[VERSION] +[HEADERS] + +[BODY] +``` + +### Components + +1. **Method**: HTTP verb (GET, POST, PUT, DELETE, etc.) +2. **URL**: Endpoint to access +3. **Headers**: Metadata about the request +4. **Body**: Data being sent (for POST, PUT, PATCH) + +### Example Request +``` +POST /api/users HTTP/1.1 +Host: api.example.com +Content-Type: application/json +Authorization: Bearer abc123xyz +User-Agent: MyApp/1.0 + +{ + "name": "John Doe", + "email": "john@example.com" +} +``` + +--- + +## Response Structure + +An HTTP response consists of: + +``` +HTTP/[VERSION] [STATUS CODE] [STATUS MESSAGE] +[HEADERS] + +[BODY] +``` + +### Components + +1. **Status Code**: Indicates success or failure +2. **Headers**: Metadata about the response +3. **Body**: Data returned from the server + +### Example Response +``` +HTTP/1.1 201 Created +Content-Type: application/json +Content-Length: 123 +Date: Fri, 14 Feb 2026 10:00:00 GMT + +{ + "id": 42, + "name": "John Doe", + "email": "john@example.com", + "created_at": "2026-02-14T10:00:00Z" +} +``` + +--- + +## Headers + +Headers provide additional information about the request or response. + +### Common Request Headers + +| Header | Purpose | Example | +|--------|---------|---------| +| **Content-Type** | Format of request body | `application/json` | +| **Authorization** | Authentication credentials | `Bearer token123` | +| **Accept** | Desired response format | `application/json` | +| **User-Agent** | Client application info | `Mozilla/5.0` | +| **Cookie** | Session information | `session_id=xyz` | + +### Common Response Headers + +| Header | Purpose | Example | +|--------|---------|---------| +| **Content-Type** | Format of response body | `application/json` | +| **Content-Length** | Size of response body | `1234` | +| **Cache-Control** | Caching directives | `max-age=3600` | +| **Set-Cookie** | Set client cookie | `token=abc; HttpOnly` | +| **Location** | URL of created resource | `/api/users/42` | + +### Examples + +**Python - Setting Headers** +```python +import requests + +headers = { + "Content-Type": "application/json", + "Authorization": "Bearer abc123xyz", + "User-Agent": "MyApp/1.0" +} + +response = requests.get( + "https://api.example.com/users", + headers=headers +) + +print(response.headers) # View response headers +``` + +**JavaScript - Setting Headers** +```javascript +fetch("https://api.example.com/users", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer abc123xyz", + "User-Agent": "MyApp/1.0" + }, + body: JSON.stringify({ name: "John" }) +}) + .then(res => { + console.log(res.headers.get("Content-Type")); + return res.json(); + }); +``` + +--- + +## Request Body + +The request body contains data being sent to the server (for POST, PUT, PATCH). + +### JSON Format (Most Common) + +```json +{ + "name": "John Doe", + "email": "john@example.com", + "age": 30 +} +``` + +**Python** +```python +import requests + +data = { + "name": "John Doe", + "email": "john@example.com", + "age": 30 +} + +response = requests.post( + "https://api.example.com/users", + json=data # Automatically sets Content-Type to application/json +) +``` + +**JavaScript** +```javascript +const data = { + name: "John Doe", + email: "john@example.com", + age: 30 +}; + +fetch("https://api.example.com/users", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(data) +}); +``` + +### Form Data + +``` +name=John+Doe&email=john@example.com&age=30 +``` + +**Python** +```python +import requests + +data = { + "name": "John Doe", + "email": "john@example.com", + "age": 30 +} + +response = requests.post( + "https://api.example.com/users", + data=data # Sends as form data +) +``` + +### File Upload + +**Python** +```python +import requests + +files = { + "file": open("profile.jpg", "rb") +} + +data = { + "name": "John Doe" +} + +response = requests.post( + "https://api.example.com/upload", + files=files, + data=data +) +``` + +**JavaScript** +```javascript +const formData = new FormData(); +formData.append("file", fileInput.files[0]); +formData.append("name", "John Doe"); + +fetch("https://api.example.com/upload", { + method: "POST", + body: formData // Don't set Content-Type, browser sets it automatically +}); +``` + +--- + +## Response Body + +The response body contains data returned from the server. + +### JSON Response (Most Common) + +```json +{ + "status": "success", + "data": { + "id": 42, + "name": "John Doe", + "email": "john@example.com" + } +} +``` + +**Python - Parsing Response** +```python +import requests + +response = requests.get("https://api.example.com/users/42") + +# Parse JSON +data = response.json() +print(data["name"]) # John Doe + +# Access raw text +print(response.text) + +# Access raw bytes +print(response.content) +``` + +**JavaScript - Parsing Response** +```javascript +fetch("https://api.example.com/users/42") + .then(res => res.json()) // Parse JSON + .then(data => { + console.log(data.name); // John Doe + }); + +// Alternative with async/await +async function getUser() { + const response = await fetch("https://api.example.com/users/42"); + const data = await response.json(); + console.log(data.name); +} +``` + +### Error Response + +```json +{ + "status": "error", + "message": "User not found", + "code": 404, + "details": { + "user_id": 42 + } +} +``` + +**Python - Handling Errors** +```python +import requests + +response = requests.get("https://api.example.com/users/999") + +if response.status_code == 200: + data = response.json() + print(data) +else: + error = response.json() + print(f"Error: {error['message']}") +``` + +**JavaScript - Handling Errors** +```javascript +fetch("https://api.example.com/users/999") + .then(res => { + if (!res.ok) { + throw new Error(`HTTP error! status: ${res.status}`); + } + return res.json(); + }) + .then(data => console.log(data)) + .catch(error => console.error("Error:", error)); +``` + +--- + +## Query Parameters + +Query parameters add additional information to GET requests via the URL. + +### Syntax +``` +https://api.example.com/users?age=25&city=Mumbai&sort=name +``` + +### Structure +- Start with `?` +- Key-value pairs: `key=value` +- Multiple parameters separated by `&` +- Values should be URL-encoded + +### Examples + +**Python** +```python +import requests + +# Method 1: String concatenation +response = requests.get("https://api.example.com/users?age=25&city=Mumbai") + +# Method 2: Using params (recommended) +params = { + "age": 25, + "city": "Mumbai", + "sort": "name" +} + +response = requests.get( + "https://api.example.com/users", + params=params +) + +print(response.url) # Shows full URL with encoded parameters +``` + +**JavaScript** +```javascript +// Method 1: String concatenation +fetch("https://api.example.com/users?age=25&city=Mumbai") + .then(res => res.json()); + +// Method 2: Using URLSearchParams +const params = new URLSearchParams({ + age: 25, + city: "Mumbai", + sort: "name" +}); + +fetch(`https://api.example.com/users?${params}`) + .then(res => res.json()); +``` + +### Common Use Cases + +**Filtering** +``` +/api/products?category=electronics&price_max=1000 +``` + +**Pagination** +``` +/api/users?page=2&limit=20 +``` + +**Sorting** +``` +/api/posts?sort=created_at&order=desc +``` + +**Searching** +``` +/api/search?q=laptop&type=product +``` + +--- + +## Complete Examples + +### GET Request Example + +**Python** +```python +import requests + +response = requests.get( + "https://api.example.com/users/42", + headers={ + "Authorization": "Bearer token123", + "Accept": "application/json" + } +) + +if response.status_code == 200: + user = response.json() + print(f"User: {user['name']}") + print(f"Email: {user['email']}") +else: + print(f"Error: {response.status_code}") +``` + +**JavaScript** +```javascript +fetch("https://api.example.com/users/42", { + method: "GET", + headers: { + "Authorization": "Bearer token123", + "Accept": "application/json" + } +}) + .then(res => { + if (!res.ok) { + throw new Error(`HTTP error! status: ${res.status}`); + } + return res.json(); + }) + .then(user => { + console.log(`User: ${user.name}`); + console.log(`Email: ${user.email}`); + }) + .catch(error => console.error("Error:", error)); +``` + +### POST Request Example + +**Python** +```python +import requests + +new_user = { + "name": "John Doe", + "email": "john@example.com", + "age": 30 +} + +response = requests.post( + "https://api.example.com/users", + json=new_user, + headers={ + "Authorization": "Bearer token123", + "Content-Type": "application/json" + } +) + +if response.status_code == 201: + created_user = response.json() + print(f"Created user with ID: {created_user['id']}") +else: + error = response.json() + print(f"Error: {error['message']}") +``` + +**JavaScript** +```javascript +const newUser = { + name: "John Doe", + email: "john@example.com", + age: 30 +}; + +fetch("https://api.example.com/users", { + method: "POST", + headers: { + "Authorization": "Bearer token123", + "Content-Type": "application/json" + }, + body: JSON.stringify(newUser) +}) + .then(res => { + if (res.status === 201) { + return res.json(); + } else { + throw new Error(`HTTP error! status: ${res.status}`); + } + }) + .then(createdUser => { + console.log(`Created user with ID: ${createdUser.id}`); + }) + .catch(error => console.error("Error:", error)); +``` + +### PUT Request Example + +**Python** +```python +import requests + +updated_user = { + "name": "John Doe", + "email": "john.doe@example.com", + "age": 31 +} + +response = requests.put( + "https://api.example.com/users/42", + json=updated_user, + headers={ + "Authorization": "Bearer token123" + } +) + +if response.status_code == 200: + print("User updated successfully") + print(response.json()) +``` + +**JavaScript** +```javascript +const updatedUser = { + name: "John Doe", + email: "john.doe@example.com", + age: 31 +}; + +fetch("https://api.example.com/users/42", { + method: "PUT", + headers: { + "Authorization": "Bearer token123", + "Content-Type": "application/json" + }, + body: JSON.stringify(updatedUser) +}) + .then(res => res.json()) + .then(data => { + console.log("User updated successfully"); + console.log(data); + }); +``` + +### DELETE Request Example + +**Python** +```python +import requests + +response = requests.delete( + "https://api.example.com/users/42", + headers={ + "Authorization": "Bearer token123" + } +) + +if response.status_code == 204: + print("User deleted successfully") +elif response.status_code == 404: + print("User not found") +``` + +**JavaScript** +```javascript +fetch("https://api.example.com/users/42", { + method: "DELETE", + headers: { + "Authorization": "Bearer token123" + } +}) + .then(res => { + if (res.status === 204) { + console.log("User deleted successfully"); + } else if (res.status === 404) { + console.log("User not found"); + } + }); +``` + +--- + +## Best Practices + +1. **Always check status codes**: Don't assume success +2. **Handle errors gracefully**: Provide meaningful error messages +3. **Use appropriate Content-Type**: Match your request body format +4. **Include authentication**: Most APIs require authorization +5. **Parse JSON safely**: Check response format before parsing +6. **Set timeouts**: Prevent requests from hanging indefinitely +7. **Log requests**: Helps with debugging + +### Python Timeout Example +```python +import requests + +try: + response = requests.get( + "https://api.example.com/users", + timeout=5 # 5 seconds timeout + ) +except requests.Timeout: + print("Request timed out") +``` + +### JavaScript Timeout Example +```javascript +const controller = new AbortController(); +const timeoutId = setTimeout(() => controller.abort(), 5000); + +fetch("https://api.example.com/users", { + signal: controller.signal +}) + .then(res => res.json()) + .catch(error => { + if (error.name === 'AbortError') { + console.log('Request timed out'); + } + }) + .finally(() => clearTimeout(timeoutId)); +``` + +--- + +## Summary + +- **Request**: Method + URL + Headers + Body +- **Response**: Status Code + Headers + Body +- **Headers**: Provide metadata +- **Body**: Contains actual data (JSON most common) +- **Query Parameters**: Add filters/options to GET requests +- **Always handle errors**: Check status codes and parse errors \ No newline at end of file diff --git a/API/rest_api.md b/API/rest_api.md new file mode 100644 index 0000000..15c3376 --- /dev/null +++ b/API/rest_api.md @@ -0,0 +1,691 @@ +# REST API + +**REST (Representational State Transfer)** is an architectural style for designing networked applications. + +## Table of Contents +- [What is REST?](#what-is-rest) +- [REST Principles](#rest-principles) +- [Resources and URIs](#resources-and-uris) +- [CRUD Operations](#crud-operations) +- [REST Constraints](#rest-constraints) +- [Best Practices](#best-practices) +- [API Design Examples](#api-design-examples) + +--- + +## What is REST? + +REST is an architectural style that defines a set of constraints for creating web services. A RESTful API: +- Uses HTTP methods explicitly +- Is stateless +- Exposes directory structure-like URIs +- Transfers data in JSON or XML + +### Key Characteristics + +- **Client-Server**: Separation of concerns +- **Stateless**: Each request is independent +- **Cacheable**: Responses can be cached +- **Uniform Interface**: Consistent resource access +- **Layered System**: Client doesn't know if it's connected to the end server + +--- + +## REST Principles + +### 1. Resource-Based + +Everything is a **resource** with a unique identifier (URI). + +``` +Resources (nouns): +- User: /users +- Product: /products +- Order: /orders + +Not actions (verbs): +❌ /getUsers +❌ /createUser +❌ /deleteProduct +``` + +### 2. HTTP Methods for Actions + +Use HTTP methods to perform operations: + +| Operation | HTTP Method | Example | +|-----------|-------------|---------| +| Create | POST | POST /users | +| Read | GET | GET /users/42 | +| Update | PUT/PATCH | PUT /users/42 | +| Delete | DELETE | DELETE /users/42 | + +### 3. Representations + +Resources can have multiple representations (JSON, XML, HTML). + +```json +// JSON representation +{ + "id": 42, + "name": "John Doe", + "email": "john@example.com" +} +``` + +### 4. Stateless Communication + +Each request must contain all information needed to understand it. + +```python +# Bad: Relies on server-side session state +GET /next-page + +# Good: Request contains all necessary information +GET /users?page=2&limit=20 +``` + +--- + +## Resources and URIs + +### URI Structure + +``` +https://api.example.com/v1/users/42/orders/123 + +Protocol: https +Domain: api.example.com +Version: v1 +Resource: users +ID: 42 +Sub-resource: orders +Sub-ID: 123 +``` + +### URI Best Practices + +**Use Nouns (not verbs)** +``` +✅ GET /users +❌ GET /getUsers + +✅ POST /orders +❌ POST /createOrder +``` + +**Use Plural Names** +``` +✅ /users +❌ /user + +✅ /products +❌ /product +``` + +**Use Hierarchies for Relationships** +``` +✅ /users/42/orders # All orders for user 42 +✅ /users/42/orders/123 # Specific order for user 42 +``` + +**Use Hyphens (not underscores)** +``` +✅ /user-profiles +❌ /user_profiles +``` + +**Use Lowercase** +``` +✅ /users +❌ /Users +❌ /USERS +``` + +--- + +## CRUD Operations + +REST maps CRUD operations to HTTP methods. + +### Create (POST) + +Create a new resource. + +```python +import requests + +new_user = { + "name": "John Doe", + "email": "john@example.com" +} + +response = requests.post( + "https://api.example.com/users", + json=new_user +) + +# Response: 201 Created +# Location: /users/42 +``` + +**Endpoint Pattern** +``` +POST /users +POST /products +POST /orders +``` + +--- + +### Read (GET) + +Retrieve resource(s). + +**Get Collection** +```python +import requests + +# Get all users +response = requests.get("https://api.example.com/users") +users = response.json() +``` + +**Get Single Resource** +```python +# Get specific user +response = requests.get("https://api.example.com/users/42") +user = response.json() +``` + +**Endpoint Patterns** +``` +GET /users # List all users +GET /users/42 # Get user 42 +GET /users/42/orders # Get orders for user 42 +``` + +--- + +### Update (PUT / PATCH) + +**PUT: Replace entire resource** +```python +import requests + +updated_user = { + "name": "John Doe", + "email": "john.new@example.com", + "age": 31 +} + +response = requests.put( + "https://api.example.com/users/42", + json=updated_user +) +``` + +**PATCH: Update specific fields** +```python +import requests + +partial_update = { + "email": "john.new@example.com" +} + +response = requests.patch( + "https://api.example.com/users/42", + json=partial_update +) +``` + +**Endpoint Patterns** +``` +PUT /users/42 # Replace user 42 +PATCH /users/42 # Update user 42 partially +``` + +--- + +### Delete (DELETE) + +Remove a resource. + +```python +import requests + +response = requests.delete("https://api.example.com/users/42") + +# Response: 204 No Content +``` + +**Endpoint Pattern** +``` +DELETE /users/42 +DELETE /products/99 +DELETE /orders/123 +``` + +--- + +## REST Constraints + +### 1. Stateless + +**Server doesn't store client context between requests.** + +Each request must contain: +- Authentication credentials +- Session information +- All necessary data + +```python +# Every request includes auth token +headers = {"Authorization": "Bearer token123"} + +requests.get("https://api.example.com/users", headers=headers) +requests.get("https://api.example.com/products", headers=headers) +``` + +### 2. Client-Server + +**Separation of concerns.** + +- **Client**: User interface and experience +- **Server**: Data storage and business logic + +This allows them to evolve independently. + +### 3. Cacheable + +**Responses must define themselves as cacheable or not.** + +``` +HTTP/1.1 200 OK +Cache-Control: max-age=3600 +Content-Type: application/json + +{ + "id": 42, + "name": "John Doe" +} +``` + +### 4. Uniform Interface + +**Consistent way to interact with resources.** + +- Identify resources via URIs +- Manipulate resources via representations +- Self-descriptive messages +- HATEOAS (optional) + +### 5. Layered System + +**Client can't tell if connected directly to end server.** + +``` +[Client] → [Load Balancer] → [API Gateway] → [Server] → [Database] +``` + +Client doesn't know about intermediate layers. + +--- + +## Best Practices + +### 1. Versioning + +**Include API version in URL or header.** + +``` +✅ /v1/users +✅ /v2/users + +Header: Accept: application/vnd.api.v1+json +``` + +### 2. Filtering, Sorting, Pagination + +**Use query parameters.** + +```python +import requests + +# Filtering +params = { + "status": "active", + "age": "25" +} +response = requests.get("https://api.example.com/users", params=params) + +# Sorting +params = { + "sort": "name", + "order": "asc" +} +response = requests.get("https://api.example.com/users", params=params) + +# Pagination +params = { + "page": 2, + "limit": 20 +} +response = requests.get("https://api.example.com/users", params=params) +``` + +**URL Examples** +``` +/users?status=active&age=25 +/users?sort=name&order=asc +/users?page=2&limit=20 +``` + +### 3. Use HTTP Status Codes Correctly + +```python +# Create +return 201 Created + +# Success +return 200 OK + +# No content (delete) +return 204 No Content + +# Not found +return 404 Not Found + +# Validation error +return 422 Unprocessable Entity +``` + +### 4. Consistent Error Format + +```json +{ + "status": "error", + "code": 422, + "message": "Validation failed", + "errors": [ + { + "field": "email", + "message": "Email is already taken" + } + ] +} +``` + +### 5. Use Nouns, Not Verbs + +``` +✅ GET /users/42 +❌ GET /getUser/42 + +✅ POST /users +❌ POST /createUser + +✅ DELETE /users/42 +❌ DELETE /deleteUser/42 +``` + +### 6. Relationships + +**Use sub-resources for relationships.** + +``` +/users/42/orders # Orders belonging to user 42 +/users/42/orders/123 # Specific order for user 42 +/products/99/reviews # Reviews for product 99 +``` + +### 7. Rate Limiting + +**Include rate limit info in headers.** + +``` +HTTP/1.1 200 OK +X-RateLimit-Limit: 1000 +X-RateLimit-Remaining: 999 +X-RateLimit-Reset: 1633072800 +``` + +--- + +## API Design Examples + +### User Management API + +```python +# Create user +POST /v1/users +{ + "name": "John Doe", + "email": "john@example.com" +} +→ 201 Created, Location: /v1/users/42 + +# Get all users +GET /v1/users +→ 200 OK + +# Get specific user +GET /v1/users/42 +→ 200 OK + +# Update user +PUT /v1/users/42 +{ + "name": "John Doe", + "email": "john.new@example.com" +} +→ 200 OK + +# Partial update +PATCH /v1/users/42 +{ + "email": "john.new@example.com" +} +→ 200 OK + +# Delete user +DELETE /v1/users/42 +→ 204 No Content + +# Search users +GET /v1/users?search=john&status=active +→ 200 OK + +# Paginate users +GET /v1/users?page=2&limit=20 +→ 200 OK +``` + +### E-commerce API + +```python +# Products +GET /v1/products # List products +GET /v1/products/99 # Get product +GET /v1/products?category=electronics&price_max=1000 +POST /v1/products # Create product +PUT /v1/products/99 # Update product +DELETE /v1/products/99 # Delete product + +# Product reviews +GET /v1/products/99/reviews # Get reviews for product +POST /v1/products/99/reviews # Add review +DELETE /v1/products/99/reviews/5 # Delete review + +# Orders +GET /v1/orders # List orders +GET /v1/orders/123 # Get order +POST /v1/orders # Create order +PUT /v1/orders/123 # Update order + +# User orders +GET /v1/users/42/orders # Orders for user 42 +GET /v1/users/42/orders/123 # Specific order + +# Shopping cart +GET /v1/users/42/cart # Get cart +POST /v1/users/42/cart/items # Add item +DELETE /v1/users/42/cart/items/7 # Remove item +``` + +### Complete Python Example + +```python +import requests + +BASE_URL = "https://api.example.com/v1" +headers = {"Authorization": "Bearer token123"} + +# Create user +new_user = { + "name": "John Doe", + "email": "john@example.com", + "age": 30 +} + +response = requests.post( + f"{BASE_URL}/users", + json=new_user, + headers=headers +) + +if response.status_code == 201: + user = response.json() + user_id = user["id"] + print(f"Created user: {user_id}") + + # Get user + response = requests.get( + f"{BASE_URL}/users/{user_id}", + headers=headers + ) + print(response.json()) + + # Update user + update = {"email": "john.new@example.com"} + response = requests.patch( + f"{BASE_URL}/users/{user_id}", + json=update, + headers=headers + ) + print(response.json()) + + # Get user's orders + response = requests.get( + f"{BASE_URL}/users/{user_id}/orders", + headers=headers + ) + print(response.json()) + + # Delete user + response = requests.delete( + f"{BASE_URL}/users/{user_id}", + headers=headers + ) + + if response.status_code == 204: + print("User deleted") +``` + +### Complete JavaScript Example + +```javascript +const BASE_URL = "https://api.example.com/v1"; +const headers = { + "Authorization": "Bearer token123", + "Content-Type": "application/json" +}; + +async function userWorkflow() { + try { + // Create user + const newUser = { + name: "John Doe", + email: "john@example.com", + age: 30 + }; + + let response = await fetch(`${BASE_URL}/users`, { + method: "POST", + headers: headers, + body: JSON.stringify(newUser) + }); + + const user = await response.json(); + const userId = user.id; + console.log(`Created user: ${userId}`); + + // Get user + response = await fetch(`${BASE_URL}/users/${userId}`, { + headers: headers + }); + console.log(await response.json()); + + // Update user + response = await fetch(`${BASE_URL}/users/${userId}`, { + method: "PATCH", + headers: headers, + body: JSON.stringify({ email: "john.new@example.com" }) + }); + console.log(await response.json()); + + // Get user's orders + response = await fetch(`${BASE_URL}/users/${userId}/orders`, { + headers: headers + }); + console.log(await response.json()); + + // Delete user + response = await fetch(`${BASE_URL}/users/${userId}`, { + method: "DELETE", + headers: headers + }); + + if (response.status === 204) { + console.log("User deleted"); + } + + } catch (error) { + console.error("Error:", error); + } +} + +userWorkflow(); +``` + +--- + +## REST vs GraphQL vs SOAP + +| Feature | REST | GraphQL | SOAP | +|---------|------|---------|------| +| Data Format | JSON, XML | JSON | XML | +| Over/Under Fetching | Yes | No | Yes | +| Versioning | URL/Header | Schema evolution | WSDL versions | +| Caching | HTTP caching | Complex | Limited | +| Learning Curve | Easy | Medium | Steep | + +--- + +## Summary + +**REST Key Points:** +- Resource-based (nouns, not verbs) +- Use HTTP methods correctly +- Stateless communication +- Use standard status codes +- Version your API +- Keep URIs simple and hierarchical +- Support filtering, sorting, pagination + +**When to use REST:** +- Public APIs +- Simple CRUD operations +- Caching is important +- Standard HTTP clients +- Wide compatibility needed \ No newline at end of file diff --git a/API/status_codes.md b/API/status_codes.md new file mode 100644 index 0000000..1884ce5 --- /dev/null +++ b/API/status_codes.md @@ -0,0 +1,660 @@ +# HTTP Status Codes + +HTTP status codes indicate the result of an API request. + +## Table of Contents +- [Status Code Categories](#status-code-categories) +- [1xx Informational](#1xx-informational) +- [2xx Success](#2xx-success) +- [3xx Redirection](#3xx-redirection) +- [4xx Client Error](#4xx-client-error) +- [5xx Server Error](#5xx-server-error) +- [Quick Reference](#quick-reference) +- [Handling Status Codes](#handling-status-codes) + +--- + +## Status Code Categories + +Status codes are grouped into five categories: + +| Range | Category | Meaning | +|-------|----------|---------| +| **1xx** | Informational | Request received, continuing process | +| **2xx** | Success | Request successfully received and processed | +| **3xx** | Redirection | Further action needed to complete request | +| **4xx** | Client Error | Request contains bad syntax or cannot be fulfilled | +| **5xx** | Server Error | Server failed to fulfill valid request | + +--- + +## 1xx Informational + +Rarely used in REST APIs. Indicates the request was received and is being processed. + +| Code | Status | Description | +|------|--------|-------------| +| **100** | Continue | Client should continue with request | +| **101** | Switching Protocols | Server is switching protocols as requested | + +--- + +## 2xx Success + +Indicates the request was successfully received, understood, and accepted. + +### 200 OK +**General success status** + +Used for successful GET, PUT, PATCH requests. + +```json +{ + "status": "success", + "data": { + "id": 42, + "name": "John Doe" + } +} +``` + +**Example** +```python +import requests + +response = requests.get("https://api.example.com/users/42") +if response.status_code == 200: + data = response.json() + print(data) +``` + +--- + +### 201 Created +**Resource successfully created** + +Used for successful POST requests that create new resources. + +**Response should include Location header** pointing to the new resource. + +``` +HTTP/1.1 201 Created +Location: /api/users/42 +Content-Type: application/json + +{ + "id": 42, + "name": "John Doe", + "email": "john@example.com" +} +``` + +**Example** +```python +import requests + +new_user = {"name": "John Doe", "email": "john@example.com"} +response = requests.post("https://api.example.com/users", json=new_user) + +if response.status_code == 201: + print("User created successfully") + created_user = response.json() + print(f"New user ID: {created_user['id']}") +``` + +--- + +### 202 Accepted +**Request accepted for processing** + +Used for asynchronous operations. The request is valid but processing hasn't completed yet. + +```json +{ + "status": "accepted", + "message": "Your request is being processed", + "job_id": "abc-123", + "status_url": "/api/jobs/abc-123" +} +``` + +--- + +### 204 No Content +**Success but no content to return** + +Commonly used for successful DELETE requests or updates that don't return data. + +``` +HTTP/1.1 204 No Content +``` + +**Example** +```python +import requests + +response = requests.delete("https://api.example.com/users/42") + +if response.status_code == 204: + print("User deleted successfully") + # No response body to parse +``` + +--- + +### Other 2xx Codes + +| Code | Status | Usage | +|------|--------|-------| +| **206** | Partial Content | Used for range requests (downloading parts of a file) | + +--- + +## 3xx Redirection + +Indicates the client must take additional action to complete the request. + +| Code | Status | Description | +|------|--------|-------------| +| **301** | Moved Permanently | Resource permanently moved to new URL | +| **302** | Found | Resource temporarily at different URL | +| **304** | Not Modified | Cached version is still valid | +| **307** | Temporary Redirect | Like 302, but method must not change | +| **308** | Permanent Redirect | Like 301, but method must not change | + +**Example** +```python +import requests + +response = requests.get("https://api.example.com/old-endpoint") + +if response.status_code == 301: + new_url = response.headers["Location"] + print(f"Resource moved to: {new_url}") +``` + +--- + +## 4xx Client Error + +Indicates the client made an error in the request. + +### 400 Bad Request +**Invalid request syntax** + +The request is malformed or has invalid parameters. + +```json +{ + "status": "error", + "message": "Invalid request", + "errors": [ + { + "field": "email", + "message": "Email format is invalid" + } + ] +} +``` + +**Example** +```python +import requests + +# Invalid data (missing required field) +new_user = {"name": "John Doe"} # email is required + +response = requests.post("https://api.example.com/users", json=new_user) + +if response.status_code == 400: + error = response.json() + print(f"Bad request: {error['message']}") +``` + +--- + +### 401 Unauthorized +**Authentication required or failed** + +The request lacks valid authentication credentials. + +```json +{ + "status": "error", + "message": "Authentication required", + "code": 401 +} +``` + +**Example** +```python +import requests + +# Request without authentication +response = requests.get("https://api.example.com/protected") + +if response.status_code == 401: + print("Authentication required. Please provide valid credentials.") + +# Request with authentication +headers = {"Authorization": "Bearer your-token-here"} +response = requests.get("https://api.example.com/protected", headers=headers) +``` + +--- + +### 403 Forbidden +**Client lacks permission** + +Authentication succeeded but user doesn't have permission to access the resource. + +```json +{ + "status": "error", + "message": "You don't have permission to access this resource", + "code": 403 +} +``` + +**401 vs 403** +- **401**: Not authenticated (login required) +- **403**: Authenticated but not authorized (insufficient permissions) + +--- + +### 404 Not Found +**Resource doesn't exist** + +The requested resource was not found on the server. + +```json +{ + "status": "error", + "message": "User not found", + "code": 404 +} +``` + +**Example** +```python +import requests + +response = requests.get("https://api.example.com/users/999") + +if response.status_code == 404: + print("User not found") +elif response.status_code == 200: + user = response.json() + print(f"User found: {user['name']}") +``` + +--- + +### 405 Method Not Allowed +**HTTP method not supported** + +The endpoint exists, but the HTTP method is not allowed. + +```json +{ + "status": "error", + "message": "Method DELETE not allowed", + "allowed_methods": ["GET", "POST"] +} +``` + +--- + +### 409 Conflict +**Request conflicts with current state** + +Commonly used when trying to create a resource that already exists. + +```json +{ + "status": "error", + "message": "User with this email already exists", + "code": 409 +} +``` + +**Example** +```python +import requests + +new_user = { + "name": "John Doe", + "email": "existing@example.com" # Already exists +} + +response = requests.post("https://api.example.com/users", json=new_user) + +if response.status_code == 409: + print("User already exists") +``` + +--- + +### 422 Unprocessable Entity +**Validation error** + +Request is well-formed but contains semantic errors. + +```json +{ + "status": "error", + "message": "Validation failed", + "errors": [ + { + "field": "age", + "message": "Age must be between 0 and 120" + }, + { + "field": "email", + "message": "Email is already taken" + } + ] +} +``` + +--- + +### 429 Too Many Requests +**Rate limit exceeded** + +Client has sent too many requests in a given time period. + +```json +{ + "status": "error", + "message": "Rate limit exceeded", + "retry_after": 60 +} +``` + +**Example** +```python +import requests +import time + +response = requests.get("https://api.example.com/users") + +if response.status_code == 429: + retry_after = int(response.headers.get("Retry-After", 60)) + print(f"Rate limited. Retry after {retry_after} seconds") + time.sleep(retry_after) + # Retry the request + response = requests.get("https://api.example.com/users") +``` + +--- + +### Other 4xx Codes + +| Code | Status | Description | +|------|--------|-------------| +| **402** | Payment Required | Reserved for future use | +| **406** | Not Acceptable | Server cannot produce response matching Accept headers | +| **408** | Request Timeout | Client took too long to send request | +| **410** | Gone | Resource permanently removed | +| **413** | Payload Too Large | Request body exceeds size limit | +| **414** | URI Too Long | URL is too long | +| **415** | Unsupported Media Type | Content-Type not supported | + +--- + +## 5xx Server Error + +Indicates the server failed to fulfill a valid request. + +### 500 Internal Server Error +**Generic server error** + +Something went wrong on the server, but the server doesn't know what. + +```json +{ + "status": "error", + "message": "Internal server error", + "code": 500 +} +``` + +**Example** +```python +import requests + +response = requests.get("https://api.example.com/users") + +if response.status_code == 500: + print("Server error. Please try again later.") +``` + +--- + +### 502 Bad Gateway +**Invalid response from upstream server** + +Server acting as gateway received invalid response from upstream server. + +--- + +### 503 Service Unavailable +**Server temporarily unavailable** + +Server is temporarily unable to handle the request (maintenance, overload). + +```json +{ + "status": "error", + "message": "Service temporarily unavailable", + "retry_after": 300 +} +``` + +--- + +### 504 Gateway Timeout +**Gateway timeout** + +Server acting as gateway didn't receive timely response from upstream server. + +--- + +### Other 5xx Codes + +| Code | Status | Description | +|------|--------|-------------| +| **501** | Not Implemented | Server doesn't support the functionality | +| **505** | HTTP Version Not Supported | HTTP version not supported | + +--- + +## Quick Reference + +### Most Common Codes + +| Code | Name | Use Case | +|------|------|----------| +| **200** | OK | Successful GET, PUT, PATCH | +| **201** | Created | Successful POST (resource created) | +| **204** | No Content | Successful DELETE | +| **400** | Bad Request | Invalid request data | +| **401** | Unauthorized | Missing/invalid authentication | +| **403** | Forbidden | Insufficient permissions | +| **404** | Not Found | Resource doesn't exist | +| **409** | Conflict | Duplicate resource | +| **422** | Unprocessable Entity | Validation error | +| **429** | Too Many Requests | Rate limit exceeded | +| **500** | Internal Server Error | Server error | +| **503** | Service Unavailable | Server temporarily down | + +--- + +## Handling Status Codes + +### Python Complete Example + +```python +import requests + +def make_api_request(url, method="GET", **kwargs): + """Make API request with comprehensive error handling""" + + try: + response = requests.request(method, url, **kwargs) + + # Handle different status codes + if response.status_code == 200: + return response.json() + + elif response.status_code == 201: + print("Resource created successfully") + return response.json() + + elif response.status_code == 204: + print("Resource deleted successfully") + return None + + elif response.status_code == 400: + error = response.json() + print(f"Bad request: {error.get('message')}") + return None + + elif response.status_code == 401: + print("Authentication required") + return None + + elif response.status_code == 403: + print("Permission denied") + return None + + elif response.status_code == 404: + print("Resource not found") + return None + + elif response.status_code == 409: + print("Resource already exists") + return None + + elif response.status_code == 422: + error = response.json() + print(f"Validation error: {error.get('errors')}") + return None + + elif response.status_code == 429: + retry_after = response.headers.get("Retry-After", 60) + print(f"Rate limited. Retry after {retry_after} seconds") + return None + + elif 500 <= response.status_code < 600: + print("Server error. Please try again later") + return None + + else: + print(f"Unexpected status code: {response.status_code}") + return None + + except requests.RequestException as e: + print(f"Request failed: {e}") + return None + +# Usage +data = make_api_request("https://api.example.com/users/42") +``` + +### JavaScript Complete Example + +```javascript +async function makeApiRequest(url, options = {}) { + try { + const response = await fetch(url, options); + + // 2xx Success + if (response.ok) { + if (response.status === 204) { + console.log("Resource deleted successfully"); + return null; + } + return await response.json(); + } + + // 4xx Client Error + if (response.status === 400) { + const error = await response.json(); + console.error(`Bad request: ${error.message}`); + return null; + } + + if (response.status === 401) { + console.error("Authentication required"); + return null; + } + + if (response.status === 403) { + console.error("Permission denied"); + return null; + } + + if (response.status === 404) { + console.error("Resource not found"); + return null; + } + + if (response.status === 409) { + console.error("Resource already exists"); + return null; + } + + if (response.status === 422) { + const error = await response.json(); + console.error("Validation error:", error.errors); + return null; + } + + if (response.status === 429) { + const retryAfter = response.headers.get("Retry-After") || 60; + console.error(`Rate limited. Retry after ${retryAfter} seconds`); + return null; + } + + // 5xx Server Error + if (response.status >= 500) { + console.error("Server error. Please try again later"); + return null; + } + + console.error(`Unexpected status code: ${response.status}`); + return null; + + } catch (error) { + console.error("Request failed:", error); + return null; + } +} + +// Usage +const data = await makeApiRequest("https://api.example.com/users/42"); +``` + +--- + +## Best Practices + +1. **Always check status codes**: Never assume success +2. **Handle errors gracefully**: Provide user-friendly messages +3. **Use appropriate codes**: Match the situation +4. **Return consistent error format**: Makes client-side handling easier +5. **Include error details**: Help clients understand what went wrong +6. **Log server errors**: For debugging and monitoring +7. **Respect rate limits**: Implement retry logic with backoff + +--- + +## Summary + +- **2xx**: Success +- **4xx**: Client error (check your request) +- **5xx**: Server error (not your fault) + +Remember: Status codes are the first thing to check when debugging API issues. \ No newline at end of file diff --git a/README.md b/README.md index 01e1e3a..0a740fd 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ - [Software Engineering](#software-engineering) - [Integrated Circuits](#integrated-circuits) - [Object Oriented Programming](#object-oriented-programming) +- [API Basics](#api-basics) - [Operating Systems](#operating-systems) - [Memory and Storage](#memory-and-storage) - [File System](#file-system) @@ -210,6 +211,12 @@ It is the standard way of code that every programmer has to abide by for better Read more about these concepts of OOP [here](Object%20Oriented%20Programming/readme.md) +## [API Basics](API/readme.md) + +APIs (Application Programming Interfaces) allow different software systems to communicate with each other. They are commonly used to connect frontend applications with backend servers. + +Read more about API basics [here](API/readme.md) + ## [Data Structures](Data%20Structures/readme.md) In computer science, a data structure is a data organization, management, and storage format that enables efficient access and modification. More precisely, a data structure is a collection of data values, the relationships among them, and the functions or operations that can be applied to the data. From a0d9b26e5dbdc6d444b861e009adbf8740be660b Mon Sep 17 00:00:00 2001 From: Anjor Date: Sat, 14 Feb 2026 16:05:20 +0530 Subject: [PATCH 2/3] Fixing the heading of API in Main README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a740fd..92f3691 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ It is the standard way of code that every programmer has to abide by for better Read more about these concepts of OOP [here](Object%20Oriented%20Programming/readme.md) -## [API Basics](API/readme.md) +## [API (Application Programming Interface)](API/readme.md) APIs (Application Programming Interfaces) allow different software systems to communicate with each other. They are commonly used to connect frontend applications with backend servers. From 565c566955636aedabd15fc5b97265bc0f939c27 Mon Sep 17 00:00:00 2001 From: Anjor Date: Sat, 14 Feb 2026 16:09:43 +0530 Subject: [PATCH 3/3] Changing the link to the API section in the README file to point to the correct section in the Main README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 92f3691..8959ef2 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ - [Software Engineering](#software-engineering) - [Integrated Circuits](#integrated-circuits) - [Object Oriented Programming](#object-oriented-programming) -- [API Basics](#api-basics) +- [API (Application Programming Interface)](#api-application-programming-interface) - [Operating Systems](#operating-systems) - [Memory and Storage](#memory-and-storage) - [File System](#file-system)