When we are developing mobile applications, making network calls is one of the most common tasks we do. Writing raw HTTP requests can quickly become repetitive and messy. This is where Chopper, a Flutter package, comes to the picture.
Chopper helps us manage HTTP requests in a clean, reusable, and efficient manner. In this article, In this article, we will see a step-by-step guide on how to use Chopper effectively and minimize our efforts.
What is Chopper?
Chopper is a powerful HTTP client generator for Dart and Flutter. It provides:
A clean and structured way to make API calls.
Automatic code generation for services.
Built-in features like interceptors, logging, and converters.
Instead of writing boilerplate HTTP code, you just define your API endpoints, and Chopper generates the implementation for you.
Installation
First, add the chopper to the dependencies and include build_runner and chopper_generator in the dev_dependencies section of your pubspec.yaml file.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
chopper: ^8.3.0
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.7.1
chopper_generator: ^8.3.0
Then, run:
flutter pub get
Project Folder Structure
![Screenshot 2025-09-16 at 9.27.48 PM]()
Creating the Network Manager
Let’s create a new file called ChopperNetworkManager.dart. This file will hold our service definition.
import 'package:chopper/chopper.dart';
part 'ChopperNetworkManager.chopper.dart';
@ChopperApi(baseUrl: "")
abstract class ChopperNetworkManager extends ChopperService {}
Now, generate the implementation by running the build command in your project root:
dart run build_runner build
This will generate a file named ChopperNetworkManager.chopper.dart with the actual implementation of your API calls.
Adding Singleton and API Setup
To make our service accessible throughout the app, we’ll use the singleton design pattern and configure Chopper with logging and JSON conversion.
Here, we defined one API call: getUsers, which fetches a list of users
import 'package:chopper/chopper.dart';
part 'ChopperNetworkManager.chopper.dart';
/// Chopper service defining API endpoints and client configuration.
@ChopperApi(baseUrl: "")
abstract class ChopperNetworkManager extends ChopperService {
static ChopperNetworkManager? manager;
/// Fetches users from the `/users` endpoint.
@GET(path: "users")
Future<Response> getUsers();
/// Creates a configured instance of [ChopperNetworkManager].
static ChopperNetworkManager create([ChopperClient? client]) {
client ??= ChopperClient(
baseUrl: Uri.parse("https://dummyjson.com"),
services: [_$ChopperNetworkManager()],
converter: JsonConverter(),
errorConverter: JsonConverter(),
interceptors: [HttpLoggingInterceptor()],
authenticator: null,
);
return _$ChopperNetworkManager(client);
}
/// Returns a lazily-initialized singleton instance.
static ChopperNetworkManager getInstance() {
manager ??= ChopperNetworkManager.create();
return manager!;
}
}
Creating a User Model
Let’s create a simple model class, users_model.dart to parse the API response:
class UsersModel {
int? id;
String? firstName;
String? lastName;
UsersModel({this.id, this.firstName, this.lastName});
factory UsersModel.fromMap(Map<String, dynamic> map) {
return UsersModel(
id: map['id'],
firstName: map['firstName'],
lastName: map['lastName'],
);
}
Map<String, dynamic> toMap() {
return {'id': id, 'firstName': firstName, 'lastName': lastName};
}
}
Making the API Call in UI
Finally, let’s use our Chopper service inside a Flutter screen.
Here, when the screen loads, it fetches users from the API and displays them in a list.
import 'package:chopper_network_app/models/users_model.dart';
import 'package:chopper_network_app/network/ChopperNetworkManager.dart';
import 'package:flutter/material.dart';
class WelcomeScreen extends StatefulWidget {
const WelcomeScreen({super.key});
@override
State<WelcomeScreen> createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> {
// List to store fetched users
List<UsersModel> users = [];
// Boolean to track loading state
bool isLoading = false;
@override
void initState() {
super.initState();
// Fetch all users when the widget is initialized
getAllUsers();
}
// Method to fetch all users from the API
void getAllUsers() async {
setState(() {
// Set loading to true before starting the API call
isLoading = true;
});
await ChopperNetworkManager.getInstance()
.getUsers()
.then((response) {
// If the response is successful
if (response.statusCode == 200) {
// Iterate over each user in the response and add to the users list
response.body['users'].forEach((userData) {
users.add(UsersModel.fromMap(userData));
});
}
setState(() {
// Set loading to false after data is fetched
isLoading = false;
});
})
.catchError((error) {
// Handle errors and set loading to false
setState(() {
isLoading = false;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Chopper Network Manager")),
body: isLoading
? Center(child: CircularProgressIndicator())
: ListView.builder(
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(users[index].firstName ?? ""),
subtitle: Text(users[index].firstName ?? ""),
);
},
),
);
}
}
![chopper-manager]()
Conclusion
Chopper simplifies API integration in Flutter by eliminating repetitive boilerplate code. You only need to define your endpoints and run the build_runner command, and Chopper handles the rest.
With built-in features like interceptors, logging, and JSON conversion, Chopper enables us to create clean, maintainable, and reusable network layers for our applications.
Thank you for reading :)