Integrating Google Books API with HarmonyOS Next using Remote Communication Kit (RCP)
Introduction
Greetings everyone! This article will guide you through the process of integrating with the Google Books API to retrieve book data within an HarmonyOS Next application, utilizing Huawei’s Remote Communication Kit (RCP). We’ll demonstrate a practical example, showing how to fetch and display information about books.
Understanding the Remote Communication Kit (RCP)
The Remote Communication Kit (RCP) is a fundamental module in HarmonyOS that empowers applications with robust HTTP data request capabilities. It allows your app to perform various HTTP operations, including common methods like GET, POST, PUT, DELETE, and more. For our demonstration, RCP will be instrumental in making GET requests to the Google Books API.
Let’s dive into an example where we’ll use RCP to retrieve book details from the Google Books API and render them on the user interface.
Project Implementation Overview
To effectively manage data and UI, our project follows a structured approach involving data models, a network service layer, a ViewModel, and UI components.
Data Models
We define a series of TypeScript interfaces to represent the structure of the data we expect from the Google Books API:
- BookModel: This interface encapsulates the essential details of a book, such as title, page count, image URL, description, and categories, in a simplified format suitable for our application.
- ImagesModel: Represents the image links for a book, specifically
smallThumbnail
. - RSPModel: The top-level response structure from the API, containing an array of
items
. - volModel: An intermediate model representing an individual item from the API response, holding
volumeInfo
. - VolumeInfoModel: Contains the detailed information about a book’s volume, including title, page count, image links, description, and categories, directly mapping to the API’s
volumeInfo
object.
These models ensure type safety and clear data handling throughout the application.
Constants
To maintain a clean and configurable codebase, we define constants for our API endpoints:
* BASE_URL
: The root URL for the Google Books API (https://www.googleapis.com/books/v1/`).
url`: The specific API endpoint, including query parameters, to fetch books and select specific fields like title, page count, image links, description, and categories.
*
Network Service with RCP
The core of our data fetching mechanism resides in a utility function, getHttp
, which leverages the rcp
module:
import { rcp } from '@kit.RemoteCommunicationKit';
import { BASE_URL } from './Constants';
function sessionConfig(): rcp.SessionConfiguration {
return {
baseAddress: BASE_URL
}
}
export function getHttp(url: string) {
const session = rcp.createSession(sessionConfig());
return session.get(`${url}`).then((res) => res.toJSON()).finally(() => {
session.close();
});
}
This function initiates an RCP session with the defined base address, sends a GET request to the specified URL, converts the response to JSON, and critically, ensures the session is closed afterward to release resources.
ViewModel for Data Management
The BookViewModel
acts as a central point for fetching and preparing book data for the UI. It’s implemented as a singleton and uses @Observed
to enable reactive updates to the UI.
import BookModel from '../model/BookModel';
import { RSPModel } from '../model/RSPModel';
import { volModel } from '../model/volModel';
import { getHttp } from '../utils/RCP';
import { url } from '../utils/Constants';
@Observed
export class BookViewModel {
private static _instance: BookViewModel;
allBooks: BookModel[] = []
private constructor() {
}
public static get instance(): BookViewModel {
if (!BookViewModel._instance) {
BookViewModel._instance = new BookViewModel();
}
return BookViewModel._instance;
}
async getBooks() {
const response = await getHttp(url) ?? []
const rsp = response as RSPModel
this.allBooks = rsp.items.map<BookModel>((i: volModel) => {
return {
title: i.volumeInfo.title,
pageCount: i.volumeInfo.pageCount,
image: i.volumeInfo.imageLinks.smallThumbnail,
description: i.volumeInfo.description,
categories: i.volumeInfo.categories
}
})
console.info('getBooks', JSON.stringify(this.allBooks, null, 3))
}
}
The getBooks
method asynchronously calls our getHttp
service, processes the raw API response into our simplified BookModel
array, and updates the allBooks
property, which then notifies observing UI components.
UI Components
BookCardComponent
This is a reusable component responsible for displaying the details of a single book. It receives title
, pageCount
, image
, and categories
as properties.
@Component
export struct BookCardComponent {
@Prop title: string
@Prop pageCount: number
@Prop image: string
@Prop categories: Array<string>
build() {
Column() {
Image(this.image).width(60).height(70).padding({ bottom: 3 })
Text(this.categories.join(', ')).fontSize(9).fontColor(Color.White).padding({ bottom: 3 })
Text(this.title).fontSize(11).fontColor(Color.White).padding({ bottom: 3 })
Text(this.pageCount.toString() + ' pages').fontSize(9).fontColor(Color.White)
}.padding(2).width('70%').borderRadius(20)
}
}
It arranges an image, categories, title, and page count within a Column
layout, styled for presentation.
BooksPage
The BooksPage
is the main entry point for displaying the list of books. It utilizes the BookViewModel
and the BookCardComponent
.
import { BookCardComponent } from '../component/BookCardComponent'
import { BookViewModel } from '../viewmodel/BookViewModel';
import BookModel from '../model/BookModel';
@Entry
@Component
struct HomePage {
scroller: Scroller = new Scroller()
@State viewModel: BookViewModel = BookViewModel.instance;
aboutToAppear() {
this.viewModel.getBooks()
}
build() {
Column() {
Text($r('app.string.books'))
Scroll(this.scroller) {
Column() {
ForEach(this.viewModel.allBooks, (book: BookModel, index: number) => {
BookCardComponent({
image: book.image,
title: book.title,
pageCount: book.pageCount,
categories: book.categories
}).padding({ bottom: 4 })
Divider().height(2).color(0xCCCCCC).padding({ left: 40, right: 40, bottom: 10 });
}, (item: string, index: number) => item)
}.padding({ bottom: 25 })
}.width('100%').height('100%')
}.backgroundColor(Color.Black).padding({ top: 10, bottom: 10 }).width('100%').height('100%')
}
}
Upon the page appearing (aboutToAppear
), it triggers the getBooks
method in the ViewModel. The build
method then uses a Scroll
container with a ForEach
loop to render each book using the BookCardComponent
, dynamically updating as allBooks
in the ViewModel changes.
Output
The application successfully fetches and displays book information, presenting a scrollable list of book cards with their respective images, titles, page counts, and categories.
Conclusion
This article has demonstrated a complete workflow for integrating with external APIs, specifically the Google Books API, within an ArkTS-based HarmonyOS Next project. By leveraging Huawei’s Remote Communication Kit (RCP), we established an efficient network service. Combined with a clear ViewModel architecture and modular UI components, we achieved a clean, maintainable, and responsive application capable of fetching and displaying dynamic data.