DEV Community

zhonghua
zhonghua

Posted on • Edited on

Practical Development of HarmonyOS: The Art of Network Layer - Elegant Encapsulation and Construction Guide (Part III)

Practical Development of HarmonyOS: The Art of Network Layer - Elegant Encapsulation and Construction Guide (Part III)

Foreword
In the previous two articles, we delved into the encapsulation and optimization techniques of the network layer. This article will take you into the practical application of the network layer, guiding you step by step on how to use the carefully constructed network framework from architectural design to specific implementation.

I. Network Layer Architecture Design
In HarmonyOS application development, a clear and rational network layer architecture is key to ensuring the maintainability and scalability of the project. Here is the recommended network layer directory structure:

Project
|-- network
    |-- data
        |-- models
            |-- params            // Request models
            |-- responses         // Response models
        |-- service             // Network interface definitions
        |-- sources
            |-- remote            // Network data sources
Enter fullscreen mode Exit fullscreen mode

II. Service Network Interface Design and Implementation

  1. Building Network Interfaces The interface constant file ApiMethod.ets, used for centralized management of all network request paths.
// Interface request path constant definition for unified management and reference
const HARMONY_INDEX = "harmony/index/json";
export { HARMONY_INDEX };
Enter fullscreen mode Exit fullscreen mode
  1. Network Request Class The ApiRequest class serves as the center for network requests, responsible for initializing and configuring the network library, as well as invoking and assembling requests.
type DataClassConstructor<T> = ClassConstructor<ApiResult<T>>;
export class ApiRequest{

  private static instance: ApiRequest


  static getInstance (): ApiRequest {
    if (!ApiRequest.instance) {
      ApiRequest.instance = new ApiRequest()
    }
    return ApiRequest.instance
  }

  net : NetworkService

  constructor() {
    this.net =  new NetworkService("https://www.wanandroid.com/");
    this.net.dataConverter = new JsonDataConverter()
    this.net.addInterceptor(new DefaultInterceptor())
  }

  public getService() : NetworkService{
    return this.net;
  }

  private plainToClassApiResult<T>(ctor: DataClassConstructor<T>, data: object) : ApiResult<T>{
    return plainToClass(ctor,data,{
      enableImplicitConversion: false,
      exposeDefaultValues: true,}) as ApiResult<T>;
  }
  async requestHarmonyIndex(harmonyIndex: HarmonyIndexParam): Promise<ApiResult<HarmonyIndexResponse>> {
    let data =  await ApiRequest.getInstance().getService().request({
      act : HARMONY_INDEX,
      expectDataType : http.HttpDataType.OBJECT,
      queryParams : new Map(Object.entries(harmonyIndex)),
      method: RequestMethod.GET
    })
    let result :ApiResult<HarmonyIndexResponse> = this.plainToClassApiResult<HarmonyIndexResponse>( ApiResult , data.result as object,)
    return result;
  }


}
Enter fullscreen mode Exit fullscreen mode

III. Network Data Source Layer

  1. Network Data Source The BaseRemoteSource class provides basic network request processing, including displaying loading dialogs and basic error handling.
// BaseRemoteSource class implements basic network requests and error handling
class BaseRemoteSource {
  async baseRequest<T>(request: Promise<ApiResult<T>>, option?: DataSourceOption): Promise<DataResult<ApiResult<T>>> {
    try {
      // Show loading prompt
      NetworkUtil.showSpinner(option);
      const result = await request;
      // Hide loading prompt
      NetworkUtil.hideSpinner(option);
      // Process results accordingly
      return result.errorCode === 0
        ? new SuccessData(result)
        : new ErrorData(new AppBusinessError(result.errorCode!, result.errorMsg!));
    } catch (e) {
      // Exception handling
      const error = e as BaseError;
      NetworkUtil.hideSpinner(option);
      if (option?.showErrorTips) {
        LibToast.show(error.message);
      }
      return new ErrorData(e);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Network Data Source Implementation Class The WanRemoteSource class inherits from BaseRemoteSource and implements specific network requests.
// WanRemoteSource class implements specific business network requests
class WanRemoteSource extends BaseRemoteSource {
  async requestHarmonyIndex(harmonyIndex: HarmonyIndexParam): Promise<DataResult<ApiResult<HarmonyIndexResponse>>> {
    const option = new DataSourceOption();
    option.showSpinner = true;
    return this.baseRequest(ApiRequest.getInstance().requestHarmonyIndex(harmonyIndex), option);
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Data Repository The WanResponsitory class acts as a data repository, responsible for coordinating remote data sources and potential local data sources.
// WanResponsitory class implements the data repository pattern
class WanResponsitory implements IWanSource {
  private static instance: WanResponsitory;
  private remoteSource: IWanSource;

  private constructor() {
    this.remoteSource = new WanRemoteSource();
    // ... (omitted code)
  }

  public static getInstance(): WanResponsitory {
    if (!WanResponsitory.instance) {
      WanResponsitory.instance = new WanResponsitory();
    }
    return WanResponsitory.instance;
  }

  requestHarmonyIndex(harmonyIndex: HarmonyIndexParam): Promise<DataResult<ApiResult<HarmonyIndexResponse>>> {
    return this.remoteSource.requestHarmonyIndex(harmonyIndex);
  }
}
Enter fullscreen mode Exit fullscreen mode

IV. Page Business End Usage
In the page business logic, we execute network requests by calling methods of the data repository and process the returned results.

// Handling button click events in the page
Button('Network Request')
  .attributeModifier(new ColumnButtonStyle)
  .onClick(() => {
    WanResponsitory.getInstance().requestHarmonyIndex(new HarmonyIndexParam()).then((value) => {
      if (value instanceof SuccessData) {
        const data = value as SuccessData<ApiResult<HarmonyIndexResponse>>;
        LibToast.show(`Display: ${data.data?.data?.links?.name}`);
      } else if (value instanceof ErrorData) {
        const error = value.error;
        if (error instanceof AppBusinessError) {
          LibToast.show(`Business exception: ${error.code}`);
        }
      }
    });
  });
Enter fullscreen mode Exit fullscreen mode

Conclusion
This article has provided a detailed introduction on how to use the network framework we have written, from architectural design to specific implementation, each step reflects the pursuit of efficient and maintainable code. It is hoped that this knowledge will help you to be more proficient in HarmonyOS development and build more robust and user-friendly applications.

Top comments (0)