Skip to main content
In this guide we’ll validate a Flask image upload endpoint and exercise the application’s error handling with Postman and curl. You will learn how to:
  • Enforce allowed file extensions (PNG, JPG, JPEG) and intentionally reject GIFs because OpenCV’s decoder is unreliable for animated GIFs.
  • Verify file contents using imghdr and Pillow to prevent renamed non-image files from being accepted.
  • Require and validate a quality parameter (integer between 0 and 100).
  • Decode and re-encode images using OpenCV and return a validated JPEG binary response.
  • Return structured JSON errors with appropriate HTTP status codes for each failure case.
A presentation slide that says "Testing with Postman" on the left and shows a large blue "Demo" on a dark curved background on the right. The slide also has a small "© Copyright KodeKloud" in the bottom-left corner.

Upload route: validation overview

The upload route should perform these checks, in order:
  1. Confirm the image file part exists and the filename is not empty.
  2. Secure the filename and enforce allowed extensions: png, jpg, jpeg.
  3. Read the file bytes once, then verify content:
    • Use imghdr to detect the image signature in the bytes.
    • Use Pillow (Image.verify()) for an additional sanity check.
  4. Require a quality form parameter and validate it as an integer in [0, 100].
  5. Decode the bytes with OpenCV, process and re-encode as JPEG with the requested quality.
  6. Validate the processed output with Pillow before returning it as image/jpeg.
  7. Return clear JSON errors and proper HTTP status codes for every failure branch.
The consolidated implementation below follows these steps and includes robust logging and error handling.
If you must accept GIFs, decode them with Pillow (e.g., iterate frames) and convert a chosen frame(s) to an image OpenCV can process. OpenCV’s imdecode is not suitable for animated GIF decoding.

How to test

  • Postman (form-data)
    • URL: POST http://127.0.0.1:5000/upload
    • Body (form-data)
      • Key: image — File: DSC08804.JPG
      • Key: quality — Text: 100
  • curl example (uploads a JPEG at quality 100):

Common test cases and expected responses

Additionally, the same JSON examples are shown here as sample responses:
  • Missing file:
  • Empty filename:
  • Disallowed extension:
  • Wrong file content:
  • Missing or invalid quality parameter:
or
  • Failed to decode with OpenCV:

Example server logs

Why multi-layer validation matters

  • File extension checks provide a fast fail for obvious bad uploads.
  • imghdr inspects raw file bytes and prevents trivial bypass by renaming files.
  • Pillow’s Image.verify() ensures the bytes represent a valid image file structure.
  • OpenCV is used for image processing and re-encoding, but it requires decodable bytes — hence the prior validations.
  • Together, these layers improve security and robustness while producing deterministic failure responses for clients.

Next steps

With the backend validated and robust error handling in place, you can:
  • Build a React front-end to consume this API and show upload progress and errors.
  • Add rate limiting and size limits to prevent abuse.
  • Implement background processing (e.g., Celery) for heavy image transformations.
  • If GIF support is required, use Pillow to extract frames and convert frames to an OpenCV-friendly format.
References and further reading Thank you for following this lesson.

Watch Video