The Flutter API is automatically generated based on source_gen and Build_runner, netnover interface, based on Swagger. Writing is not good, can map and stick code, absolutely not BB. There are comments in the code, all the sensitive information in the code is replaced, but the code is all shared.

A project directory and script engineering drawings

1.1 Api_CODE_generator Engineering code and project structure

ApiSite class, annotated in the main project to generate apis for the corresponding services

class ApiSite {
  final String serviceName;
  final String version;

  const ApiSite({this.serviceName, this.version});
}
Copy the code

1.2 API_CODE_generator_gen engineering code and project structure

Yaml relies on file code

Description: A new Flutter package. Version: 0.0.1 author: homepage: Environment: SDK: ">=2.2.0 <3.0.0" dependencies: source_gen: ^0.9.6 Flutter: SDK: flutter API_code_generator: path:.. / API_code_generator/dio: ^3.0.6 dev_dependencies: build_runner: ^1.10.0 flutter # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter:Copy the code

The build.yaml file is the configuration file

The targets: $default: # define object library, keyword $default default to the current library builders: # building of two libraries api_code_generator | api_code_generator_gen: enabled: Target builders: code_generator: target: ": API_code_generator_gen "# Target library import: "Package :api_code_generator_gen/builder.dart" [".api_code_generator_gen.g.art "]} auto_apply: ["apiCodeGenerator"] Dependents # Apply this Builder to the package directly depending on the package built publicly. Build_to: cache # Export to hidden build cache. Applies_builders will not be published: [" source_gen | combining_builder "] # specifies whether can run delay buildersCopy the code

Dart file code

import 'package:build/build.dart'; import 'package:source_gen/source_gen.dart'; import 'api_code_generator_gen.dart'; Code_generator => SharedPartBuilder([apiCodeGenerator()], 'api_code_generator');Copy the code

Api_code_generator_gen.dart file code

library api_code_generator_gen;

export 'src/api_code_generator_gen_base.dart';
Copy the code

Dart file code Swagger returns API data entity, egg pain, all hand solution

import 'dart:math'; class ApiResponse { String version; String swagger; String host; String basePath; Info info; List<Tags> tags; Map<String, Map<String, PathInfo>> paths; Map<String, Definitions> definitions; ApiResponse.fromJson(Map<String, dynamic> json) { this.swagger = json['swagger']; this.host = json['host']; this.basePath = json['basePath']; this.info = Info.fromJson(json['info']); var pathsJson = json['paths']; if (pathsJson ! = null) { this.paths = Map<String, Map<String, PathInfo>>(); (pathsJson as Map).forEach((key, value) { if (value ! = null) { var m = Map<String, PathInfo>(); (value as Map).forEach((k2, v2) { m[k2 as String] = PathInfo.fromJson(v2); }); this.paths[key as String] = m; }}); } var definitionsJson = json['definitions']; if (definitionsJson ! = null) { this.definitions = Map(); (definitionsJson as Map).forEach((key, value) { this.definitions[key] = Definitions.fromJson(value); }); } var tagsJson = json['tags']; if (tagsJson ! = null) { this.tags = List<Tags>(); (tagsJson as List).forEach((v) { this.tags.add(Tags.fromJson(v)); }); } } } class Info { String description; String version; Info.fromJson(Map<String, dynamic> json) { this.description = json['description']; this.version = json['version']; } } class Tags { String name; String description; Tags.fromJson(Map<String, dynamic> json) { this.name = json['name']; this.description = json['description']; } } class PathInfo { List<String> tags; String summary; String operationId; List<String> produces; List<Parameters> parameters; Map<String, Responses> responses; PathInfo.fromJson(Map<String, dynamic> dynamic) { var tagsJson = dynamic['tags']; if (tagsJson ! = null) { this.tags = List<String>(); (dynamic['tags'] as List).forEach((v) { this.tags.add(v); }); } this.summary = dynamic["summary"]; this.operationId = dynamic["operationId"]; var producesJson = dynamic['produces']; if (producesJson ! = null) { this.produces = List<String>(); (producesJson as List).forEach((v) { this.produces.add(v); }); } var parametersJosn = dynamic['parameters']; if (parametersJosn ! = null) { this.parameters = List<Parameters>(); (parametersJosn as List).forEach((v) { this.parameters.add(Parameters.fromJson(v)); }); } var responsesJson = dynamic['responses']; if (responsesJson ! = null) { this.responses = Map(); (responsesJson as Map).forEach((key, value) { this.responses[key] = Responses.fromJson(value); }); } } } class Parameters { String name; String ins; String description; bool required; String type; dynamic defaults; String format; List<String> enums; String typeName; Parameters items; String $ref; Object schema; Parameters.fromJson(Map<dynamic, dynamic> dynamic) { this.name = dynamic["name"]; this.ins = dynamic["in"]; this.description = dynamic["description"]; this.required = dynamic["required"]; this.type = dynamic["type"]; this.defaults = dynamic["default"]; this.format = dynamic["format"]; this.$ref = dynamic['\$ref']; if (dynamic.containsKey("enums") && dynamic["enum"] ! = null) { this.enums = List(); (dynamic["enum"] as List).forEach((f) => {this.enums.add(f)}); } if (dynamic.containsKey("items") && dynamic["items"] ! = null) { this.items = Parameters.fromJson(dynamic["items"]); } if (dynamic.containsKey("schema") && dynamic["schema"] ! = null) { var schemaJson = dynamic["schema"]; if (schemaJson is Map) { this.schema = Map(); schemaJson.forEach((k, v) { (schema as Map)[k] = v; }); } else if (schemaJson is String) { this.schema = schemaJson; } } } } class Responses { String description; Parameters schema; Responses.fromJson(Map<String, dynamic> dynamic) { this.description = dynamic["description"]; var schemaJson = dynamic["schema"]; if (schemaJson ! = null) { this.schema = Parameters.fromJson(schemaJson); } } } class Definitions { String type; Map<String, Parameters> properties; String title; String description; Definitions.fromJson(Map<String, dynamic> dynamic) { this.type = dynamic["type"]; this.title = dynamic["title"]; this.description = dynamic["description"]; var propertiesJson = dynamic['properties']; if (propertiesJson ! = null) { this.properties = Map(); (propertiesJson as Map).forEach((key, value) { this.properties[key] = Parameters.fromJson(value); }); } } } class HttpFunction { String className; String typeName; String url; String method; List<Parameters> parameters; String summary; } class TsType { String typeName; String description; String title; Map<String, Parameters> properties; }Copy the code

Api_code_generator_gen_base. Dart file code, which is automatically generated by code based on GeneratorForAnnotation. Dart is not as good as Android gradle plugin on Groovey. Groovey encapsulates nodule requests into entity maps, and groovey is a scripting language that is very flexible in accessing object property fields.

import 'dart:math';

import 'package:analyzer/dart/element/element.dart';
import 'package:build/src/builder/build_step.dart';
import 'package:dio/dio.dart';
import 'package:source_gen/source_gen.dart';
import 'package:api_code_generator/index.dart';
import './api_response.dart';

/*
 *  flutter packages pub run build_runner build
 */
class ApiCodeGenerator extends GeneratorForAnnotation<ApiSite> {
  @override
  generateForAnnotatedElement(
      Element element, ConstantReader annotation, BuildStep buildStep) async {
    print("element is $element");
    if (element is! ClassElement) {
      throw InvalidGenerationSourceError(
          "Request class is not ok for ${element.displayName}");
    }
    var classElement = (element as ClassElement);
    var metadatas = classElement.metadata;
    var apiSiteMeta = metadatas
        .firstWhere((e) => (e.computeConstantValue().type.name == "ApiSite"));
    var apiSiteConstantValue = apiSiteMeta.computeConstantValue();
    var serviceName =
        apiSiteConstantValue.getField("serviceName").toStringValue();
    var version = apiSiteConstantValue.getField("version").toStringValue();
    print("ApiSite apiName  $serviceName");
    var singGenerator = SingGenerator();
    var code = await singGenerator.buildSing(serviceName, version);
    return code;
  }
}

class SingGenerator {
  var apiPaths = Map<String, Map<String, HttpFunction>>();

  Map<String, TsType> typeDefinitionMap = Map();

  Future<String> buildSing(String serviceName, String version) async {
    var apiResponse = await _getApi(serviceName);
    apiResponse.version = version;
    return _buildCode(apiResponse).toString();
  }

  Future<ApiResponse> _getApi(String serviceName) async {
    var dio = Dio()
      ..options = BaseOptions(
          baseUrl: "对不起,baseUrl 我不能提供",
          connectTimeout: 10000,
          receiveTimeout: 10000)
      ..interceptors
          .add(LogInterceptor(responseBody: false, requestBody: false));
    var url = "/$serviceName/v2/api-docs";
    Response<dynamic> response = await dio.get(url);
    return ApiResponse.fromJson(response.data);
  }

  StringBuffer _buildCode(ApiResponse apiResponse) {
    var stringBuffer = StringBuffer();
    _buildDescription(apiResponse, stringBuffer);
    _buildRef(apiResponse);
    _buildDefinitionMap(apiResponse);
    _buildApiCode(stringBuffer);
    _buildEntityCode(stringBuffer);

    return stringBuffer;
  }

  /// 生成注解
  void _buildDescription(ApiResponse apiResponse, StringBuffer stringBuffer) {
    stringBuffer.write("/*");
    stringBuffer.write("\n");
    stringBuffer.write("basePath: " + apiResponse.basePath);
    stringBuffer.write("\n");
    stringBuffer.write("description: " + apiResponse.info.description);
    stringBuffer.write("\n");
    stringBuffer.write("*/");
  }

  ///生成API文件
  void _buildApiCode(StringBuffer stringBuffer) {
    void buildSingApi(String methodName, HttpFunction httpFunction) {
      var summary = httpFunction.summary;
      var parameters = httpFunction.parameters;
      var method = httpFunction.method;
      var typeName = httpFunction.typeName;
      var paramsQuery = [];
      if (summary != null && summary.isNotEmpty) {
        stringBuffer.writeln("  /*");
        stringBuffer.writeln("  * $summary");
        stringBuffer.writeln("  */");
      }
      String data = "";
      var paramsPath = Map<String, String>();

      parameters?.forEach((p) {
        var nameAndType = "${p.name}: ${p.typeName}";
        if (p.ins == 'query') {
          paramsQuery.add(nameAndType);
        } else if (p.ins == 'body') {
          data = p.typeName;
        } else if (p.ins == 'path') {
          if (p.name != "version") {
            paramsPath[p.name] = p.typeName;
          }
        } else if (p.ins == 'formData') {}
      });

      if (parameters != null && parameters.isNotEmpty) {
        stringBuffer.writeln("  /*");
        parameters.forEach((p) {
          if (p.ins == "header") {
            return;
          }
          if (p.name == "version") {
            return;
          }
          var required = p.required ? '必填' : '选填';
          var nameAndType = "${p.ins} ${p.name}:${p.typeName}($required)";
          stringBuffer.writeln("   $nameAndType");
        });

        stringBuffer.writeln("  */");
      }

      var paramsComment = "";
      var params = "";
      if (method == "get") {
        if (paramsQuery.isNotEmpty) {
          paramsComment += "Map<String,dynamic> params";
          params = ",queryParameters:params";
        }
      } else if (method == "post" || method == "delete" || method == "put") {
        paramsComment += "$data data";
        params = ",data";
      }
      //复杂对象,调用方写josn解析器
      if (typeName.startsWith("Map<")) {
        paramsComment += ",{Function(dynamic dynamic) beanCreator}";
      }
      stringBuffer.writeln(
          "   static  Future<BaseEntrty<$typeName>> $methodName($paramsComment) async{");
      stringBuffer.writeln(
          "   Response<dynamic> response = await HttpRequest.instance");
      stringBuffer.writeln(".$method('${httpFunction.url}'$params);");
      stringBuffer.writeln(
          "return BaseEntrty<$typeName>.fromJson(response.data,(dynamic)=>");
      if (typeName == "bool" ||
          typeName == "int" ||
          typeName == "double" ||
          typeName == "String") {
        stringBuffer.writeln("dynamic as $typeName");
      } else if (typeName.startsWith("Map<")) {
        stringBuffer.writeln("beanCreator(dynamic)");
      } else if (typeName.startsWith("PageList<")) {
        var beanType = typeName
            .replaceAll("PageList", "")
            .replaceFirst("<", "")
            .replaceFirst(">", "");
        var code = _isBasics(beanType)
            ? "dynamic as $beanType"
            : "$beanType.fromJson(dynamic)";
        stringBuffer.writeln(
            "PageList<$beanType>.fromJson(dynamic, (dynamic) =>$code)");
      } else if (typeName.startsWith("List<")) {
        var beanType = typeName
            .replaceAll("List", "")
            .replaceFirst("<", "")
            .replaceFirst(">", "");
        var code = _isBasics(beanType)
            ? "dynamic as $beanType"
            : "$beanType.fromJson(dynamic)";
        stringBuffer.writeln("$code , listCreator : () => List<$beanType>()");
      } else {
        stringBuffer.writeln("$typeName.fromJson(dynamic)");
      }
      stringBuffer.writeln(");");
      stringBuffer.writeln("}");
    }

    this.apiPaths?.forEach((className, entity) {
      stringBuffer.writeln("class ${_toUpperCaseOne(className)}Server {");
      entity.forEach(buildSingApi);
      stringBuffer.writeln("}");
    });
  }

  /// 生成实体文件
  void _buildEntityCode(StringBuffer stringBuffer) {
    //from json 方法
    void _buildFromJsonFunction(
        String className, Map<String, Parameters> properties) {
      //
      var beanCreator = "";
      properties?.forEach((filedName, parameters) {
        if (parameters.typeName == "T") {
          beanCreator = "Function(dynamic dynamic) ${filedName}Creator";
          beanCreator = "," + beanCreator;
        }
      });
      stringBuffer.writeln("");
      stringBuffer.writeln(
          "${className.replaceAll("<T>", "")}.fromJson(Map<dynamic, dynamic> dynamic $beanCreator) {");
      properties?.forEach((filedName, parameters) {
        var ref = parameters.$ref;
        if (ref != null && ref.isNotEmpty) {
          if (parameters.typeName == "T") {
            stringBuffer.writeln(
                "this.$filedName=${filedName}Creator(dynamic['$filedName']);");
          } else {
            stringBuffer.writeln(
                "this.$filedName=${parameters.typeName}.fromJson(dynamic['$filedName']);");
          }
        } else {
          switch (parameters.type) {
            case 'array':
            case 'list':
              stringBuffer
                  .writeln("var ${filedName}Json = dynamic['$filedName'];");
              stringBuffer.writeln("if (${filedName}Json != null) {");
              stringBuffer.writeln("this.$filedName = List();");
              stringBuffer.writeln(
                  "(dynamic['$filedName'] as List).forEach((f) => this.$filedName.add(f));");
              stringBuffer.writeln("}");
              break;
//            case 'object':
//              stringBuffer.writeln(
//                  "    this.$filedName=${parameters.typeName}.fromJson(dynamic['$filedName']);");
//              break;
            default:
              stringBuffer.writeln("this.$filedName=dynamic['$filedName'];");
              break;
          }
        }
      });

      stringBuffer.writeln("}");
    }

    void _buildFiled(String name, Parameters parameters) {
      stringBuffer.writeln("  /*");
      stringBuffer.writeln("  description: ${parameters?.description}");
      stringBuffer.writeln("  type       : ${parameters?.type}");
      stringBuffer.writeln("  */");
      //print("  ${parameters?.typeName} $name ;");
      stringBuffer.writeln("");
      stringBuffer.writeln("  ${parameters?.typeName} $name ;");
    }

    void _buildSingEntity(String name, TsType tsType) {
      stringBuffer.writeln("/*");
      stringBuffer.writeln("description ${tsType.description}");
      stringBuffer.writeln("*/");
      stringBuffer.writeln("class $name {");
      tsType.properties?.forEach(_buildFiled);
      //构造方法
      stringBuffer.writeln("${name.replaceAll("<T>", "")}();");
      //fromJson 方法
      _buildFromJsonFunction(name, tsType.properties);
      stringBuffer.writeln("}");
    }

    typeDefinitionMap.forEach(_buildSingEntity);
  }

  void _buildRef(ApiResponse apiResponse) {
    var paths = apiResponse.paths;
    var version = apiResponse.version;
    /**
     * 解析具体的方法参数
     */
    void _analysisMethodInfo(
        String path, List<String> pathParts, String method, PathInfo info) {
      var produces = info.produces;
      if (produces.contains("application/octet-stream")) {
        return;
      }
      var tags = info.tags;
      if (tags.contains("ignore")) {
        return;
      }
      var className = "";
      if (path.contains('/action/')) {
        className = pathParts[pathParts.length - 3];
      } else if (pathParts[pathParts.length - 1].contains('{')) {
        className = pathParts[pathParts.length - 2];
      } else {
        className = pathParts[pathParts.length - 1];
      }
      className = _transformCamelCase(className);
      if (className == 'geetest') {
        return;
      }
      if (apiPaths[className] == null) {
        apiPaths[className] = Map();
      }
      var responseOk = info.responses["200"];
      try {
        var ref = responseOk.schema.$ref;
        if (ref == null || ref.isEmpty) {
          ref = responseOk.schema?.items?.$ref;
        }
        if (ref == null || ref.indexOf('Response«') < 0) {
          throw new Exception("接口返回类型出错");
        }
        var typeName = _formatType(_getType(responseOk.schema));
        var methodName = path.contains('/action/')
            ? _transformCamelCase(pathParts[pathParts.length - 1])
            : method;
        if (apiPaths[className][methodName] != null) {
          var result = apiPaths[className][methodName];
          var message = "解析出相同的方法名 $result,$path";
          throw new Exception(message);
        }

        var parameters = info.parameters;
        parameters.forEach((it) {
          it.typeName = _formatType(_getParametersType(it));
        });

        var summary = info.summary;

        var httpFunction = HttpFunction();
        httpFunction.className = className;
        httpFunction.typeName = typeName;
        httpFunction.url = path.replaceFirst("{version}", version);
        httpFunction.method = method;
        httpFunction.parameters = parameters;
        httpFunction.summary = summary;

        apiPaths[className][methodName] = httpFunction;
      } catch (e) {
        var message = "解析出错 $e path:$path  responseSchema:$responseOk";
        // throw `${ex}${this.serviceName} path:${path} responseSchema:${JSON.stringify(responseOk)}`
        throw new Exception(message);
      }
    }

    /**
     * 解析path info
     */
    void _analysisPathInfo(String path, Map<String, PathInfo> pathInfo) {
      print("path $path");
      var pathParts = path.split('/');

      pathInfo.forEach((method, info) =>
          {_analysisMethodInfo(path, pathParts, method, info)});
    }

    //去除不符合条件的API
    paths.removeWhere((key, value) => (key == null ||
        key.isEmpty ||
        !key.contains('/{version}/') ||
        key.contains('/pv/') ||
        key.contains('/pvs/') ||
        key.contains('pb/images/action/download') ||
        value.isEmpty));

    paths.forEach((path, pathInfo) => _analysisPathInfo(path, pathInfo));
  }

  void _buildDefinitionMap(ApiResponse apiResponse) {
    var definitions = apiResponse.definitions;

    TsType _buildTsType(String name, Definitions definitions) {
      var tsType = TsType();
      tsType.typeName = name;
      tsType.description = definitions.description;
      tsType.title = definitions.title;
      tsType.properties = definitions.properties;
      definitions.properties?.forEach((properties, parameters) {
        if (name.contains("<T>") && properties == "data") {
          parameters.typeName = "T";
        } else {
          var typeName = _getType(parameters);
          parameters.typeName = typeName;
        }
      });

      return tsType;
    }

    definitions.removeWhere((key, value) {
      return key.contains("PageList«") ||
          key.contains("PageRequest«") ||
          key.contains("Response«") ||
          key.contains("ObjectNode") ||
          key.contains("List«") ||
          key.contains("Map«");
    });

    definitions?.forEach((name, vo) {
      var regExp = new RegExp(r"«.*»");
      if (name.contains(regExp)) {
        name = name.replaceAll(regExp, "<T>");
        if (!typeDefinitionMap.containsKey(name)) {
          typeDefinitionMap[name] = _buildTsType(name, vo);
        }
      } else {
        typeDefinitionMap[name] = _buildTsType(name, vo);
      }
    });
  }

  String _formatType(String type) {
    if (type == "string") {
      return "String";
    }
    if (type.toLowerCase() == "boolean") {
      return "bool";
    }
    if (type.toLowerCase() == "long") {
      return "int";
    }
    if (type.toLowerCase() == "bigdecimal") {
      return "double";
    }
    return type
        .replaceAll("<long", "<int")
        .replaceAll("<Long", "<int")
        .replaceAll("<Double", "<double")
        .replaceAll("<float", "<double")
        .replaceAll("<Float", "<double")
        .replaceAll("<string", "<String")
        .replaceAll("<Boolean", "<bool")
        .replaceAll("<boolean>", "<bool");
  }

  bool _isBasics(String type) {
    return type == "int" ||
        type == "double" ||
        type == "String" ||
        type == "int" ||
        type == "bool";
  }

  String _getType(Object parameters) {
    var refKey = '\$ref';

    String _getRefType(String refStr) {
      var refType = refStr.replaceFirst('#/definitions/', '');
      refType = refType.replaceFirst('Response«', '').replaceFirst('»', '');
      refType = refType.replaceAll("«", "<").replaceAll("»", ">");
      if (refType.contains("<") && !refType.contains(">")) {
        refType += ">";
      }
      return refType;
    }

    if (parameters is String) {
      return _getRefType(parameters);
    }
    if (parameters is Map && parameters.containsKey(refKey)) {
      var ref = parameters[refKey] as String;
      return _getRefType(ref);
    }
    if (parameters is Map) {
      print("parameters is map " + parameters.toString());
      return "";
    }
    return _getParametersType(parameters as Parameters);
  }

  String _getParametersType(Parameters parameters) {
    var ref = parameters.$ref;
    if (ref != null && ref.isNotEmpty) {
      return _getType(ref);
    }
    var schema = parameters.schema;
    if (schema != null) {
      if (schema is Map) {
        return _getType(schema);
      }
    }

    var type = parameters.type;
    var format = parameters.format;
    var items = parameters.items;
    switch (type) {
      case 'int':
      case 'int32':
      case 'integer':
      case 'number':
      case 'long':
      case 'int64':
        if (format == "double" || format == "float") {
          return "double";
        }
        return "int";
      case 'bigdecimal':
      case 'double':
      case 'float':
        return 'double';
      case 'string':
        return 'String';
      case 'boolean':
        return 'bool';
      case 'array':
      case 'list':
        var refType = _getParametersType(items);
        return "List<$refType>";
      case 'object':
        return 'Object';
      default:
        return "";
    }
  }

  String _transformCamelCase(String str) {
    var array = str.split("-");
    String result = "";
    for (int i = 0; i < array.length; i++) {
      var indexValue = array[i];
      if (i != 0) {
        var index0 = indexValue.substring(0, 1);
        indexValue = indexValue.replaceFirst(index0, index0.toUpperCase());
      }
      result += indexValue;
    }
    return result;
  }

  String _toUpperCaseOne(String string) {
    return "${string.substring(0, 1).toUpperCase()}${string.substring(1)}";
  }
}
Copy the code

The above code is not much, is JSON parsing, generating code logic.

Two: the application in the main project.

The yamL file of the main project needs to be configured as follows

Dev_dependencies: build_runner: ^1.10.0#build_runner /api_code_generator_gen/ dependencies: flutter: SDK: flutter dio: ^3.0.6 Flutter_bloc: API_code_generator :# Annotation depends on path:./ API_code_generator /Copy the code

In the main project, THE Framework of Netnol adopts DIO, because I do Android development, all entity encapsulation is based on Java object-oriented thought, dart data parsing, no one taught, do not know, can only explore by myself, sad. The auto-generated API is based on the following Netnovo framework and entity classes.

import 'package:dio/dio.dart'; class HttpRequest { static Dio dio; static HttpRequest get instance => _getInstance(); static HttpRequest _instance; static HttpRequest _getInstance() { if (_instance == null) { _instance = new HttpRequest._internal(); } return _instance; } HttpRequest._internal() { dio = Dio() .. options = BaseOptions( baseUrl: "bserUrl", connectTimeout: 10000, receiveTimeout: 10000) .. interceptors.add(LogInterceptor(responseBody: true, requestBody: true)) .. interceptors .add(InterceptorsWrapper(onRequest: (RequestOptions options) { var headers = options.headers; Headers [" appversion "] = "1.1.1"; return options; })); } get(String path, {Map<String, dynamic> queryParameters}) async { if (queryParameters == null || queryParameters.isEmpty) { return dio.get(path); } await dio.get(path, queryParameters: queryParameters); } post(String path, dynamic data) async { Options options = Options(); options.contentType = ""; options.method = "POST"; return await dio.post(path, data: data, options: options); } delete(String path, dynamic data) async { Options options = Options(); options.contentType = ""; options.method = "DELETE"; return await dio.post(path, data: data, options: options); } put(String path, dynamic data) async { Options options = Options(); options.contentType = ""; options.method = "PUT"; return await dio.post(path, data: data, options: options); }}Copy the code

Standard entity classes based on server-side data encapsulation

Dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty.dart standard entity class base_entrty. I don’t know why.

import 'dart:math'; class BaseEntrty<T> { BaseEntrty(); T data; bool status; String code; String msg; String errorMsg; int currentTime; BaseEntrty.fromJson( Map<String, dynamic> json, Function(dynamic dynamic) beanCreator, {Function() listCreator}) { this.status = json["status"]; this.code = json["code"]; this.msg = json["msg"]; this.errorMsg = json["errorMsg"]; this.currentTime = json["currentTime"]; dynamic jsonData = json["data"]; if (jsonData ! If (jsonData is List<dynamic>) {if (jsonData is List<dynamic>) {if (jsonData is List<dynamic>) { jsonData.forEach((v) { list.add(beanCreator(v)); }); this.data = list as T; } else { var bean = beanCreator(jsonData); this.data = bean as T; }}}}Copy the code

Base_page_entity. dart Standard paging interface entity

class PageList<T> { List<T> entities; int pageNo; int count; int pageSize; //dynamic excludeFields; PageList({ this.entities, this.pageNo, this.count, this.pageSize, // this.excludeFields }); PageList.fromJson( Map<String, dynamic> json, Function(dynamic dynamic) beanCreator) { if (json['entities'] ! = null) { entities = List<T>(); (json['entities'] as List).forEach((v) { entities.add(beanCreator(v) as T); }); } pageNo = json['pageNo']; count = json['count']; pageSize = json['pageSize']; // excludeFields = json['excludeFields']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); // if (this.entities ! = null) { // data['entities'] = this.entities.map((v) => v.toJson()).toList(); // } data['pageNo'] = this.pageNo; data['count'] = this.count; data['pageSize'] = this.pageSize; // data['excludeFields'] = this.excludeFields; return data; }} class PageRequest<T> {/* Parameter object */ T param; /* page number */ /* Parameter format: int32 */ int pageNo; /* Number of pages per page */ /* Parameter format: int32 */ int pageSize; /* startTime */ String startTime; /* endTime */ String endTime; /* timeRange */ String timeRange; }Copy the code

Application (highlight)

Dart, part ‘API_platform_behavior.g.art ‘; For the target file of the auto-generated file, ApiSite is the annotation that the auto-generated will be based on.

import 'package:api_code_generator/index.dart'; / / import net framework package and entity, automatically generated code, the code will automatically import packages inside the import 'package: nutritionplan/HTTP/HTTP) dart'; part 'api_platform_behavior.g.dart'; @apisite (serviceName: "platform-behavior", version: "v5.0") Class PlatformBehavior {}Copy the code

Enter the api_platform_behavior.g.art file in the command line, and the script automatically runs

flutter packages pub run build_runner build
Copy the code

The following post part of the generated code, URL I have all shielded, hope understanding

part of 'api_platform_behavior.dart'; Class CommentInfoServer {/* Query commentKid:String (mandatory) query pageNo:int (optional) Query pageSize:int (optional) */ // Static Future<BaseEntrty<PageList< T>> Example Static Future<BaseEntrty<PageList<CommentContentDTO>> searchChild(Map<String, dynamic> params) async { Response<dynamic> response = await HttpRequest.instance.get( '/url', queryParameters: params); return BaseEntrty<PageList<CommentContentDTO>>.fromJson( response.data, (dynamic) => PageList<CommentContentDTO>.fromJson( dynamic, (dynamic) => CommentContentDTO.fromJson(dynamic))); //BaseEntrty<int>> Example static Future<BaseEntrty<int>> delete(data) async {Response<dynamic> Response = await HttpRequest.instance .delete('/url', data); return BaseEntrty<int>.fromJson(response.data, (dynamic) => dynamic as int); } //BaseEntrty<T>> Example static Future<BaseEntrty<StatisticResult>> Simple (Map<String, dynamic> params) async { Response<dynamic> response = await HttpRequest.instance .get('/url', queryParameters: params); return BaseEntrty<StatisticResult>.fromJson( response.data, (dynamic) => StatisticResult.fromJson(dynamic)); } // Complex entity example, the method of parsing the data, Static Future<BaseEntrty<Map<String, PageList<CommentContentDTO>>>> searchPreview(Map<String, dynamic> params, {Function(dynamic dynamic) beanCreator}) async { Response<dynamic> response = await HttpRequest.instance.get( '/ v5.0 / pb/comment - info/action/search - preview', queryParameters: params); return BaseEntrty<Map<String, PageList<CommentContentDTO>>>.fromJson( response.data, (dynamic) => beanCreator(dynamic));  Example generated entities class StatisticResult {/* description: Number of comments type: integer */ int commentCount; Type: object */ object customMapper; /* description: favoriteCount type: integer */ int favoriteCount; Type: integer */ int finishCount; /* description: followCount type: integer */ int followCount; /* description: joinCount type: integer */ int joinCount; /* description: likeCount type: integer */ int likeCount; /* description: share number type: integer */ int sharecounts; /* description: unique identifier of the target resource type: string */ string targetKid; /* description: target resource type type: string */ string targetType; Type: integer */ int viewCount; StatisticResult(); StatisticResult.fromJson(Map<dynamic, dynamic> dynamic) { this.commentCount = dynamic['commentCount']; this.customMapper = dynamic['customMapper']; this.favoriteCount = dynamic['favoriteCount']; this.finishCount = dynamic['finishCount']; this.followCount = dynamic['followCount']; this.joinCount = dynamic['joinCount']; this.likeCount = dynamic['likeCount']; this.shareCount = dynamic['shareCount']; this.targetKid = dynamic['targetKid']; this.targetType = dynamic['targetType']; this.viewCount = dynamic['viewCount']; }}}Copy the code

Flutter automatically generates code based on GeneratorForAnnotation, which is the same idea. My data parsing method is not good enough. If there is a better data parsing method, I hope to learn it.

Finally, attached is the Android VERSION API generation script: juejin.cn/post/686522…