Dart Package Tutorial – Getting Started
Learn how to create your first Dart package using test-driven development, generate documentation and publish it to pub.dev. By Agustinus Theodorus.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Dart Package Tutorial – Getting Started
25 mins
- Getting Started
- Understanding Dart Packages
- Dart Package vs. Flutter Plugin
- Knowing When to Create a Dart Package
- Writing Your First Dart Package
- Creating a Dart Package
- Understanding Dart Package Project Structure
- Test-Driven Development of the Dart Package
- Adding the Dependencies Through Terminal
- Importing Dependencies
- Dart Package Business Logic
- Exporting Your Dart Package
- Publishing Your Dart Package
- Creating the Basic Documentation README.md
- LICENSE
- Generating Package Documentation
- Importing Your Package Locally
- Publishing a Package Dry Run
- Publishing Dart Packages
- Importing Your Dart Package as Dependencies
- Where to Go From Here?
Adding the Dependencies Through Terminal
Open the terminal and navigate genderizeio. Type the following commands to add the dependencies:
dart pub add HTTP
dart pub add build_runner --dev
dart pub add mockito --dev
dart pub get
Press Enter, and check the output.
You’ll see repeated similar messages for each command:
Resolving dependencies...
....
Changed ... dependencies!
This command helps add dependencies directly through the terminal.
Mockito requires you to run build_runner
to generate mocks for annotated classes. Look at genderizeio_test.dart and you’ll see @GenerateMocks([http.Client])
. Mockito will generate test/genderizeio_test.mocks.dart with a mocked http.Client
class.
To generate mocks, run the following command in the terminal:
dart run build_runner build
Press Enter, and check the output:
$ dart run build_runner build
[INFO] Generating build script completed, took 238ms
[INFO] Reading cached asset graph completed, took 26ms
[INFO] Checking for updates since last build completed, took 296ms
[INFO] Running build completed, took 6ms
[INFO] Caching finalized dependency graph completed, took 15ms
[INFO] Succeeded after 27ms with 0 outputs (0 actions)
Create a public interface for your package by replacing lib/src/genderizeio_base.dart with:
import 'package:http/http.dart' as http;
class Genderize {
Genderize({
required this.gender,
});
final String gender; // The gender prediction
}
class GenderizeAPI {
GenderizeAPI([http.Client? client]) : client = client ?? http.Client();
/// Http client dependency to send network requests.
final http.Client client;
Future<Genderize> send(String name) async {
return Genderize(gender: 'unknown');
}
}
Now all the errors have been fixed
This minimal public interface lets consumers call your package and run tests on it.
Rerun the tests using dart test test/genderizeio_test.dart
:
$ dart test test/genderizeio_test.dart
Building package executable... (2.5s)
Built test:test.
00:00 +0 -1: Genderize.io Peter is male [E]
Expected: 'male'
Actual: 'unknown'
Which: is different.
Expected: male
Actual: unknown
^
Differ at offset 0
package:test_api expect
test/genderizeio_test.dart 55:7 main.<fn>.<fn>
00:00 +0 -2: Genderize.io API exception [E]
Expected: throws <Instance of 'Exception'>
Actual: <Instance of 'Future<Genderize>'>
Which: emitted <Instance of 'Genderize'>
test/genderizeio_test.dart 67:7 main.<fn>.<fn>
00:00 +0 -2: Some tests failed.
Consider enabling the flag chain-stack-traces to receive more detailed exceptions.
For example, 'dart test --chain-stack-traces'.
Tests failed, but they were supposed to fail.
You finished the first part of the TTD process. The next sections help you implement business logic so that all the tests can pass.
Importing Dependencies
Since you need to interact with a REST API, you must add a dependency to communicate with HTTP services.
Open pubspec.yaml, and add the following line in the dependencies
section:
dependencies:
http: ^0.13.4
Open your terminal, and install your Dart dependencies:
dart pub get
Press Enter, and check the result:
$ dart pub get
Resolving dependencies...
Got dependencies!
The above code adds all the packages mentioned in pubspec.yaml
into our project.
Now that you have the HTTP package you can write HTTP functions to get a response from Genderize API.
Dart Package Business Logic
To pass the tests, you must implement the goals you previously defined. Go to lib/src/genderizeio_base.dart and replace its content with:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
//1
class Genderize {
Genderize({
required this.name,
required this.gender,
required this.probability,
required this.count,
});
final String name; /// The name submitted through the query parameters
final String gender; /// The gender prediction
final double probability; /// The probability of the prediction validity
final int count; /// The number of names in the database
// 2
factory Genderize.fromJson(Map<String, dynamic> data) {
final name = data['name'] as String;
final gender = data['gender'] as String;
final probability = data['probability'] as double;
final count = data['count'] as int;
return Genderize(
name: name,
gender: gender,
probability: probability,
count: count,
);
}
}
// 3
class GenderizeAPI {
GenderizeAPI([http.Client? client]) : client = client ?? http.Client();
/// Http client dependency to send network requests.
final http.Client client;
// 4
Future<Genderize> send(String name) async {
final response = await client.get(Uri.parse('https://api.genderize.io?name=$name'));
if (response.statusCode == 200) {
// 5
final json = jsonDecode(response.body) as Map<String, dynamic>;
return Genderize.fromJson(json);
} else {
// 6
throw Exception('Failed to load gender');
}
}
}
Here’s a code breakdown:
- You add a model class named
Genderize
for the API response. -
fromJson
returns a Genderize model object. -
GenderizeAPI Class
is a primary wrapper interface. - A future
send(String name)
method to call an API which returns a Genderize object or throws an exception if the gender fails to load. - You return the Genderize instance in case of success.
- Or throw an exception in case of error.
You fulfilled all your goals for TTD. Now, open the terminal and rerun the tests with the following command:
dart test
Press Enter, and run tests:
$ dart test
00:01 +2: All tests passed!
It works! Your Dart package is working well and has passed the tests.
Exporting Your Dart Package
After implementing your Dart project, you need to verify that your package is exportable and importable. lib/genderizeio.dart will be the main entry point to export the project.
Go to lib/genderizeio.dart, and check if your file looks like the code below:
library genderizeio;
export 'src/genderizeio_base.dart';
This file defines that all public variables from src/genderizeio_base.dart are visible to anyone who imports your package using import 'package:genderizeio/genderizeio.dart';
.
Now it’s time to check the package you created. You’ll use the example app for this.
Go to example/genderizeio_example.dart, and replace its content with:
import 'package:genderizeio/genderizeio.dart';
void main() async {
final genderize = GenderizeAPI();
final result = await genderize.send('peter');
print('${result.name}: ${result.gender}');
}
In the above code, you:
- Create a
GenderizeAPI
instance object named genderize. Now the Genderize methods will be accessible. - Call the send function from
GenderizeAPI
, which takes a name parameter and returns a gender object. - Print in the console the genderize object name and gender.
If you’ve done the testing part, you’ll realize this is similar to the unit testing part.
Run the example app to make sure the above code is working.
In the terminal, run the following command to run the example app:
dart run example/genderizeio_example.dart
Press Enter, and check the output:
$ dart run example/genderizeio_example.dart
peter: male
You’ll get the above output. The example app is running and you get an output that tells Peter’s gender.