component_generator 0.1.3 copy "component_generator: ^0.1.3" to clipboard
component_generator: ^0.1.3 copied to clipboard

Annotated HTTP client code generation (REST), optional table/widget helpers, and HTTP/1.1 and HTTP/2 client bases for Dart.

HTTP Gen Method #

A powerful Dart code generation library that automatically generates HTTP client code, Flutter table widgets, and pagination-aware fetch methods from simple annotations.

Features #

  • πŸš€ HTTP Client Generation: Automatically generate HTTP client implementations from annotated interfaces
  • πŸ“Š Table Widget Generation: Create Flutter table widgets with automatic header and data cell generation
  • πŸ“„ Pagination Support: Generate pagination-aware fetch methods for list endpoints
  • πŸ”§ Flexible Annotations: Customize HTTP methods, URLs, field labels, and more
  • 🌐 Multi-Client Support: Support for both HTTP/1.1 and HTTP/2 clients
  • 🎯 Type Safety: Full type checking and compile-time safety

Getting Started #

Installation #

Add component_generator to your pubspec.yaml:

dependencies:
  component_generator: ^0.1.1

dev_dependencies:
  build_runner: ^2.3.2

Basic Setup #

  1. Create your HTTP client:
import 'package:component_generator/http1_client.dart';

class MyClient extends HttpClientBase {
  MyClient() : super();

  @override
  int checkResult(RespData<dynamic> resp, String url, Map<String, String> headers) {
    return 0; // Your response validation logic
  }
}

MyClient client = MyClient();
  1. Define your data models:
class LoginParams extends JSONParameter {
  String loginName;
  String password;
  int pageNum = 0;
  int pageSize = 0;

  LoginParams(this.loginName, this.password);

  @override
  Map<String, dynamic> toJson() => {
    "loginName": loginName,
    "password": password,
    "pageNum": pageNum,
    "pageSize": pageSize,
  };
}

class UserInfo {
  int id;
  String name;
  String email;

  UserInfo({this.id = 0, this.name = "", this.email = ""});

  factory UserInfo.fromJson(Map<String, dynamic> json) => UserInfo(
    id: json['id'] ?? 0,
    name: json['name'] ?? "",
    email: json['email'] ?? "",
  );
}

class UserListResp {
  int total;
  List<UserInfo> list;

  UserListResp({this.total = 0, this.list = const []});

  factory UserListResp.fromJson(Map<String, dynamic> json) => UserListResp(
    total: json['total'] ?? 0,
    list: (json['list'] as List? ?? []).map((e) => UserInfo.fromJson(e)).toList(),
  );
}
  1. Create your network interface:
import 'package:component_generator/component_generator.dart';

part 'network.g.dart';

@DataInterface()
abstract class Network {
  @ReqConfig("/user/login")
  Future<RespData> login(LoginParams data);

  @ReqConfig("/user/list")
  Future<RespData<UserListResp?>> listUser(LoginParams data);
}
  1. Generate code:
dart run build_runner build
  1. Use the generated client:
void main() async {
  client.prefix = "https://api.example.com";

  // Login
  final loginResult = await networkApi.login(LoginParams("user", "pass"));
  print(loginResult.obj);

  // List users
  final userList = await networkApi.listUser(LoginParams("", ""));
  print("Total users: ${userList.obj?.total}");
}

Annotations #

@DataInterface #

Marks an abstract class as a network interface that will generate HTTP client implementations.

@DataInterface(
  name: "customService",    // Optional: Custom service instance name
  client: "myClient",       // Optional: Custom client variable name
  mixins: "LoggingMixin"    // Optional: Mixins for generated implementation
)
abstract class MyApi {
  // Define your HTTP methods here
}

Generated Output:

class MyApiImpl extends BaseMethod implements MyApi {
  MyApiImpl({super.client});

  // Implementation of all abstract methods
}

var customService = MyApiImpl(client: myClient);

@ReqConfig #

Defines an HTTP endpoint for a method in a @DataInterface class.

@DataInterface()
abstract class UserApi {
  @ReqConfig("/users", method: "GET")
  Future<RespData<List<User>>> getUsers();

  @ReqConfig("/users", method: "POST")
  Future<RespData<User>> createUser(CreateUserParams data);

  @ReqConfig("/users/:id", method: "PUT")
  Future<RespData<User>> updateUser(int id, UpdateUserParams data);

  @ReqConfig("/users/:id", method: "DELETE")
  Future<RespData<void>> deleteUser(int id);
}

Parameters:

  • url (required): The API endpoint URL
  • method (optional): HTTP method ("GET", "POST", "PUT", "DELETE"). Default: "POST"
  • keyType (optional): Type for buffer key. Default: "int"

@TableWidget #

Generates Flutter table widgets with automatic header and data cell generation. Used on mixin classes that extend TableContentWidget.

import 'package:flutter/material.dart';
import 'package:component_generator/component_generator.dart';

part 'user_table.g.dart';

@TableWidget(
  fetchClass: UserApi,        // Required: The fetch class type
  fetchMethod: "listUser",    // Required: The fetch method name
  useI18n: false,             // Optional: Enable i18n (default: false)
  i18nFunction: 'tr',         // Optional: i18n function name (default: 'tr')
  columns: [],                // Optional: Custom column order
  skips: []                   // Optional: Fields to skip
)
mixin UserTableMixin on TableContentWidget<UserInfo, UserReq> {
  // Optional: Override specific cells by field name  
  DataCell genIdDataCell(BuildContext context, UserInfo item) {
    return DataCell(
      IconButton(
        icon: const Icon(Icons.edit),
        onPressed: () => _editUser(context, item),
      ),
    );
  }

  // Optional: Override tap handlers by field name
  void onNameTap(BuildContext context, UserInfo item) {
    // Handle name cell tap
    print('Tapped on user: ${item.name}');
  }
}

Generated Output:

class UserTable extends TableContentWidget<UserInfo, UserReq> with UserTableMixin {
  const UserTable({super.key});

  @override
  Future<List<UserInfo>> fetchData(PaginationController<UserReq> controller) {
    return UserApiFetch.listUser(controller); // Auto-generated if not implemented in mixin
  }

  @override
  List<DataColumn> genTableHeader(BuildContext context) {
    return [
      DataColumn(label: const Text('ID')),
      DataColumn(label: const Text('Name')),
      DataColumn(label: const Text('Email')),
    ];
  }

  @override
  List<DataCell> genTableData(BuildContext context, UserInfo item) {
    return [
      DataCell(Text(item.id.toString()), onTap: () => onIdTap(context, item)),
      DataCell(Text(item.name), onTap: () => onNameTap(context, item)),
      DataCell(Text(item.email)),
    ];
  }
}

Predefined Methods #

The @TableWidget annotation supports predefined methods for customizing cell behavior:

Cell Customization Methods

  • genFieldNameDataCell(BuildContext context, T item) - Override cell for specific field

Tap Handler Methods

  • onFieldNameTap(BuildContext context, T item) - Handle tap on cells for specific field

These methods are automatically detected and used by the generator if implemented in your mixin.

Advanced Usage #

Pagination Support #

The @DataInterface annotation automatically generates pagination-aware fetch methods for list endpoints. @DataInterface schema code can be generated by gos.

@DataInterface()
abstract class ProductApi {
  @ReqConfig("/products")
  Future<RespData<ProductListResp?>> listProducts(ProductReq data);
}

// Automatically generates (part file, same library): an implementation class
// named `${InterfaceName}Api` (e.g. `NetworkApi` for `Network`) plus an instance,
// and list helpers such as:
//
//   Future<List<ProductInfo>> listProductsFetch(
//       IPaginationController<ProductReq> controller) async { ... }

Requirements:

  • Response type must have list and total fields
  • Request type must extend JSONParameter and declare both pageNum and pageSize fields; otherwise no *Fetch helper is generated for that method
  • Generated fetch methods use the type name IPaginationController<T> (not prefixed). Your library file that declares part '...g.dart' must import a package that defines that interface (same name and members), so the part can resolve the typeβ€”for example package:component_set/paging/pagination_controller.dart as in example/lib/network.dart, or your own abstraction.

Flutter Integration #

class ProductListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return PaginatedView<ProductReq>(
      initialParam: ProductReq(),
      child: const ProductTableImpl(), // Use the generated Impl class
    );
  }
}

HTTP Client Configuration #

class MyClient extends HttpClientBase {
  MyClient() : super();

  @override
  int checkResult(RespData<dynamic> resp, String url, Map<String, String> headers) {
    // Custom response validation
    if (resp.code == 401) {
      // Handle unauthorized
      return -1;
    }
    return 0; // Success
  }

  @override
  Future<Map<String, String>> getHeaders(String url) async {
    // Add custom headers
    return {
      'Authorization': 'Bearer ${await getToken()}',
      'Content-Type': 'application/json',
    };
  }
}

Build Configuration #

The package includes pre-configured builders, so no additional build.yaml configuration is required. The builders are automatically enabled when you add the package to your dependencies.

Complete Example #

See the /example directory for a complete working example that demonstrates:

  • HTTP client setup
  • Data models with JSON serialization
  • Network interface definition
  • Code generation
  • Flutter table widget usage

Best Practices #

  1. Type Safety: Always use strongly typed response objects
  2. Error Handling: Implement proper error handling in your HTTP client
  3. Naming Conventions: Use consistent naming for services and methods
  4. Pagination: Include pageNum and pageSize fields for list endpoints
  5. Code Generation: Run dart run build_runner build after changing annotations

Troubleshooting #

Common Issues #

  1. "Undefined class" errors: Make sure all imports are correct
  2. "Method not found": Run code generation after adding new methods
  3. Build failures: Ensure all required dependencies are installed

Debug Tips #

  • Use dart run build_runner build --verbose for detailed build output
  • Check generated .g.dart files for issues
  • Ensure all required fields are present in your data models

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This package is licensed under the MIT License. See the LICENSE file for details.

1
likes
130
points
28
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Annotated HTTP client code generation (REST), optional table/widget helpers, and HTTP/1.1 and HTTP/2 client bases for Dart.

Repository (GitHub)
View/report issues

Topics

#codegen #build-runner #http

License

MIT (license)

Dependencies

analyzer, build, component_set, dart_style, path, source_gen

More

Packages that depend on component_generator