Modern Testing Practices

Modern Testing Practices

RESTful API Design

Resource-Oriented

Design APIs around resources and their relationships

Stateless

Each request contains all information needed

Uniform Interface

Consistent resource identification and manipulation

URL Structure Best Practices

Good Practices


# Collection endpoints
GET /api/v1/users
POST /api/v1/users

# Single resource endpoints
GET /api/v1/users/{id}
PUT /api/v1/users/{id}
PATCH /api/v1/users/{id}
DELETE /api/v1/users/{id}

# Nested resources
GET /api/v1/users/{id}/orders
POST /api/v1/users/{id}/orders

# Filtering and pagination
GET /api/v1/users?role=admin&status=active
GET /api/v1/users?page=2&limit=20

Anti-Patterns


# Avoid verbs in URLs
❌ /api/v1/getUsers
❌ /api/v1/createUser

# Avoid deep nesting
❌ /api/v1/users/{id}/orders/{orderId}/items/{itemId}

# Avoid query operations in URL
❌ /api/v1/users/search/findByEmail
❌ /api/v1/users/filter

Response Structure

Success Response


{
    "status": "success",
    "data": {
        "id": "123",
        "name": "John Doe",
        "email": "john@example.com",
        "created_at": "2024-02-01T10:00:00Z"
    },
    "meta": {
        "version": "1.0",
        "timestamp": "2024-02-01T10:00:00Z"
    }
}

Error Response


{
    "status": "error",
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Invalid input data",
        "details": [
            {
                "field": "email",
                "message": "Invalid email format"
            }
        ]
    }
}

API Versioning

URL Versioning


/api/v1/users
/api/v2/users
Pros
  • Simple to implement
  • Explicit versioning
  • Easy to document
Cons
  • URL pollution
  • Not RESTful purist

Header Versioning


Accept: application/vnd.company.api+json;version=1
Accept: application/vnd.company.api+json;version=2
Pros
  • Clean URLs
  • More RESTful
Cons
  • More complex
  • Less visible

Authentication Patterns

JWT Authentication


Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Implementation

// Token generation
const token = jwt.sign(
    { userId: user.id },
    process.env.JWT_SECRET,
    { expiresIn: '24h' }
);

// Token verification
const verifyToken = (req, res, next) => {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) {
        return res.status(401).json({
            status: 'error',
            error: {
                code: 'UNAUTHORIZED',
                message: 'No token provided'
            }
        });
    }
    try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        req.user = decoded;
        next();
    } catch (error) {
        return res.status(401).json({
            status: 'error',
            error: {
                code: 'INVALID_TOKEN',
                message: 'Invalid token'
            }
        });
    }
};

API Documentation


openapi: 3.0.0
info:
  title: User Management API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List all users
      parameters:
        - in: query
          name: role
          schema:
            type: string
        - in: query
          name: status
          schema:
            type: string
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
    post:
      summary: Create a new user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserInput'
      responses:
        '201':
          description: User created

API Tester


Response


                            
Author

Milan Salvi

Machine Learning Engineer & Data Scientist