45 ways to break an API server (negative tests with examples)
Tags: webdev, api, testing, javascript
Published: 2023-04-19 13:12:16

As developers, we strive to write error-free code, but no one actually does so because...well, bugs. In order to catch those pesky bugs before they wreak havoc on our applications, we rely on automated testing. While positive tests ensure our code works as intended, negative tests play a crucial role in validating that our applications are robust enough to handle unexpected input and edge cases.

I'm working on [Pythagora](https://github.com/Pythagora-io/pythagora), an open source tool that writes automated integration tests by itself (well, with a bit of help from GPT-4) without you, the dev, having to write a single line of code. Basically, you can get from 0 to 80% code code coverage within 30 minutes ([video](https://www.youtube.com/watch?v=vGk4dRPnvyY)).

We just created a feature that automatically generates negative tests from the entire test suite with a single command. While building that feature, I researched what are different ways one can break an API server to test if it handles errors gracefully so here it is - a comprehensive list of ways with which you can break your server, if it doesn't handle errors properly.

### 1. Empty or missing required fields
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "",
        "email": ""
    },
    "method": "POST"
}
```
---
### 2. Invalid field values - exceeding character limits
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "ThisIsAnIncrediblyLongUsernameThatExceedsTheCharacterLimit"
    },
    "method": "POST"
}
```
---
### 3. Invalid field values - malformed data
```json
{
    "endpoint": "/api/users",
    "body": {
        "email": "invalid-email@"
    },
    "method": "POST"
}
```
---
### 4. Extra or irrelevant keys in the payload
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "validuser",
        "extra_key": "irrelevant_value"
    },
    "method": "POST"
}
```
---
### 5. Incorrect or invalid HTTP methods
```json
{
    "endpoint": "/api/users/123",
    "body": {},
    "method": "POST"
}
```
---
### 6. Invalid endpoint paths
```json
{
    "endpoint": "/api/nonexistent_endpoint",
    "body": {},
    "method": "GET"
}
```
---
### 7. Query parameters instead of using the request body in POST requests
```json
{
    "endpoint": "/api/users?username=testuser",
    "body": {},
    "method": "POST"
}
```
---
### 8. Missing or invalid authentication headers (e.g., API keys)
```json
{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Authorization": "Invalid API_KEY"
    }
}
```
---
### 9. Incorrect data structure - array instead of an object
```json
{
    "endpoint": "/api/users",
    "body": [
        "username": "testuser",
        "email": "test@example.com"
    ],
    "method": "POST"
}
```
---
### 10. Incorrect data structure - object instead of an array
```json
{
    "endpoint": "/api/users",
    "body": {
        "users": {
            "username": "testuser",
            "email": "test@example.com"
        }
    },
    "method": "POST"
}
```
---
### 11. JSON formatting issues - invalid Unicode characters
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "test\uFFFFuser"
    },
    "method": "POST"
}
```
---
### 12. Duplicate keys in the payload
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "testuser",
        "username": "duplicate"
    },
    "method": "POST"
}
```
---
### 13. Invalid or unsupported content types (e.g., sending XML instead of JSON)
```json
{
    "endpoint": "/api/users",
    "body": "<user><username>testuser</username><email>test@example.com</email></user>",
    "method": "POST",
    "headers": {
        "Content-Type": "application/xml"
    }
}
```
---
### 14. Exceeding payload size limits
```json
{
    "endpoint": "/api/users",
    "body": {
        "large_data": "A very large data string that exceeds the server's payload size limit..."
    },
    "method": "POST"
}
```
---
### 15. Invalid or expired authentication tokens
```json
{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Authorization": "Bearer expired_token"
    }
}
```
---
### 16. Using special characters in field values
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "test!@#$%^&*()-user"
    },
    "method": "POST"
}
```
---
### 17. Sending nested objects instead of simple key-value pairs
```json
{
    "endpoint": "/api/users",
    "body": {
        "user": {
            "username": "testuser",
            "email": "test@example.com"
        }
    },
    "method": "POST"
}
```
---
### 18. Sending data in the wrong data type (e.g., string instead of integer)
```json
{
    "endpoint": "/api/users",
    "body": {
        "age": "25"
    },
    "method": "POST"
}
```
---
### 19. Sending null values for required fields
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": null
    },
    "method": "POST"
}
```
---
### 20. Using reserved keywords in field names
```json
{
    "endpoint": "/api/users",
    "body": {
        "class": "user"
    },
    "method": "POST"
}
```
---
### 21. Sending incomplete or malformed multipart file uploads
```json
{
    "endpoint": "/api/upload",
    "body": {
        "file": "incomplete_file_data"
    },
    "method": "POST",
    "headers": {
        "Content-Type": "multipart/form-data"
    }
}
```
---
### 22. Incorrect or missing URL encoding for special characters
```json
{
    "endpoint": "/api/users?username=test user",
    "body": {},
    "method": "GET"
}
```
---
### 23. Sending the request body in GET requests
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "testuser"
    },
    "method": "GET"
}
```
---
### 24. Invalid date or time formats
```json
{
    "endpoint": "/api/users",
    "body": {
        "birthdate": "01-25-1990"
    },
    "method": "POST"
}
```
---
### 25. Using non-ASCII characters in field names
```json
{
    "endpoint": "/api/users",
    "body": {
        "üsername": "testuser"
    },
    "method": "POST"
}
```
---
### 26. Sending deeply nested objects
```json
{
    "endpoint": "/api/users",
    "body": {
        "user": {
            "profile": {
                "details": {
                    "nested": "too_deep"
                }
            }
        }
    },
    "method": "POST"
}
```
---
### 27. Using non-printable or control characters in field values
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "test\u0008user"
    },
    "method": "POST"
}
```
---
### 28. Sending the same field multiple times with different values
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "testuser",
        "username": "different"
    },
    "method": "POST"
}
```
---
### 29. Missing or invalid content-length headers for request bodies
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "testuser"
    },
    "method": "POST",
    "headers": {
        "Content-Length": "invalid"
    }
}
```
---
### 30. Using spaces or special characters in field names
```json
{
    "endpoint": "/api/users",
    "body": {
        "user name": "testuser"
    },
    "method": "POST"
}
```
---
### 31. Sending invalid or malformed JSONP callbacks
```json
{
    "endpoint": "/api/users?callback=invalid(callback)",
    "body": {},
    "method": "GET"
}
```
---
### 32. Sending the payload as a single string instead of key-value pairs
```json
{
    "endpoint": "/api/users",
    "body": "username=testuser&email=test@example.com",
    "method": "POST"
}
```
---
### 33. Sending boolean values as strings (e.g., "true" instead of true)
```json
{
    "endpoint": "/api/users",
    "body": {
        "active": "true"
    },
    "method": "POST"
}
```
---
### 34. Using non-standard HTTP methods (e.g., PATCH, CONNECT)
```json
{
    "endpoint": "/api/users/123",
    "body": {
        "username": "updateduser"
    },
    "method": "PATCH"
}
```
---
### 35. Sending unsupported HTTP version numbers
```json
{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "httpVersion": "HTTP/3.0"
}
```
---
### 36. Sending multiple authentication headers (e.g., both API key and token)
```json
{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Authorization": "Bearer token_value",
        "API-Key": "api_key_value"
    }
}
```
---
### 37. Sending unnecessary or invalid CORS headers
```json
{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Access-Control-Allow-Origin": "*"
    }
}
```
---
### 38. Sending conflicting query parameters and request body data
```json
{
    "endpoint": "/api/users?username=testuser",
    "body": {
        "username": "different_user"
    },
    "method": "POST"
}
```
---
### 39. Using non-standard characters in authentication header values
```json
{
    "endpoint": "/api/users",
    "body": {},
    "method": "GET",
    "headers": {
        "Authorization": "Bearer t@ken_value"
    }
}
```
---
### 40. Sending negative numbers for fields that should only accept positive values
```json
{
    "endpoint": "/api/users",
    "body": {
        "age": -25
    },
    "method": "POST"
}
```
---
### 41. Sending timestamps in the future or past beyond expected range
```json
{
    "endpoint": "/api/users",
    "body": {
        "birthdate": "01-25-1800"
    },
    "method": "POST"
}
```
---
### 42. Using HTML, JavaScript, or SQL code in field values to attempt code injection
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "<script>alert('test')</script>"
    },
    "method": "POST"
}
```
---
### 43. Using different character encodings in the payload (e.g., UTF-8, UTF-16)
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": "téstuser"
    },
    "method": "POST",
    "headers": {
        "Content-Type": "application/json; charset=UTF-16"
    }
}
```
---
### 44. Sending arrays with mixed data types
```json
{
    "endpoint": "/api/users",
    "body": {
        "values": [1, "string", true]
    },
    "method": "POST"
}
```
---
### 45. Sending field values as arrays or objects instead of simple data types (e.g., string, number)
```json
{
    "endpoint": "/api/users",
    "body": {
        "username": ["testuser"]
    },
    "method": "POST"
}
```

That's it. I hope this list gave you new ideas to test and protect your server.

If you found this post valuable, it would mean the world to me if you could support us by starring [Pythagora Github repo](https://github.com/Pythagora-io/pythagora).

And, if you try it out, please let us know your feedback, we're happy to hear it.