AgroNet — Agricultural Marketplace API
A mobile backend REST API that connects Nigerian farmers directly to buyers, eliminating middlemen from the agricultural supply chain.
The Problem
Smallholder farmers in Nigeria lack direct access to buyers, forcing them to sell through middlemen who take large margins. AgroNet removes that layer by giving farmers a platform to list produce and negotiate directly with buyers.
My Approach
Built a layered Django REST Framework API following a strict Views → Services → Models architecture. Business logic lives exclusively in service modules, keeping views thin and testable. Role-based access control (farmer/buyer) is enforced at the permission layer using custom DRF permission classes. JWT authentication gates every endpoint. External integrations (Interswitch payments, Google Vision image classification, TensorFlow price prediction) are isolated in dedicated service modules.
Challenges & Solutions
Designing a clean state machine for the order lifecycle (pending → confirmed → paid → completed) that prevents illegal state transitions. Integrating Interswitch's payment gateway in a sandbox environment with limited documentation. Keeping the AI price prediction and image classification services decoupled from core business logic so they can fail gracefully without breaking the main flow.
Results & Impact
Fully functional REST API covering auth, product listings, offer negotiation, payment processing, AI price prediction, and image classification. Comprehensive test suite including property-based tests (Hypothesis) validating correctness properties across randomised inputs.
Architecture Overview
Layered REST API with a strict Views → Services → Models separation. Five domain apps (users, products, orders, payments, ai) each own their models, serializers, views, services, and permissions. All external API calls are isolated in service modules.
Tech Stack
API Showcase
Obtain a JWT access + refresh token pair using email and password.
{ "access": "<jwt>", "refresh": "<jwt>" }Register a new user with a farmer or buyer role.
{ "id": "uuid", "email": "user@example.com", "role": "farmer" }Paginated list of available produce listings with filtering and search.
{ "count": 42, "next": "...", "results": [ { "id": "uuid", "title": "Fresh Tomatoes", "price_per_unit": "300.00" } ] }Create a new produce listing. Restricted to farmers.
{ "id": "uuid", "title": "Fresh Tomatoes", "is_available": true }Retrieve the authenticated farmer's own product listings (available and unavailable), newest first.
{ "count": 5, "next": null, "results": [ { "id": "uuid", "title": "Yam", "is_available": false } ] }Buyer places an offer on a product, creating an order in pending state.
{ "id": "uuid", "status": "pending", "product": "uuid", "offered_price": "250.00" }Farmer confirms or declines an order; buyer triggers payment to advance state.
{ "id": "uuid", "status": "confirmed" }Initiate an Interswitch payment for a confirmed order.
{ "payment_url": "https://sandbox.interswitchng.com/...", "reference": "TXN-uuid" }Get a TensorFlow-based price prediction for a given crop type and quantity.
{ "predicted_price": "320.00", "currency": "NGN" }Upload a product image; Google Vision classifies the crop and Cloudinary stores it.
{ "image_url": "https://res.cloudinary.com/..." }Deployment
Docker / Gunicorn
Yes