Skip to main content

Google Books Integration

Google Books provides a comprehensive book database with excellent cover images and search capabilities. BookWish uses Google Books API as a secondary metadata source and for cover artwork.

Overview

BookWish uses Google Books for:

  • Book Search: Full-text search across millions of books
  • ISBN Lookup: Get book details by ISBN
  • Cover Images: High-quality cover artwork
  • Metadata: Title, authors, publisher, description
  • International Coverage: Better global book coverage
  • Free Tier: Generous free usage quota

Implementation

Location: /backend/src/integrations/google-books.ts

Configuration

Required environment variables:

GOOGLE_BOOKS_API_KEY=AIzaSy...

The integration uses Redis for caching with 24-hour TTL.

Features

1. Search Books

Search across Google's book database.

import { createGoogleBooksClient } from '../integrations/google-books';

const googleBooks = createGoogleBooksClient(process.env.GOOGLE_BOOKS_API_KEY);

const books = await googleBooks.searchBooks('Great Gatsby', 20);

// Returns array of GoogleBookData:
// [
// {
// googleBooksId: 'iXn5U2IzVH0C',
// isbn13: '9780743273565',
// isbn10: '0743273565',
// title: 'The Great Gatsby',
// subtitle: undefined,
// authors: ['F. Scott Fitzgerald'],
// publisher: 'Scribner',
// publishedDate: Date('2004-05-01'),
// description: 'The exemplary novel of the Jazz Age...',
// pageCount: 180,
// categories: ['Fiction'],
// coverImageUrl: 'https://books.google.com/books/content?id=...&zoom=1',
// thumbnailUrl: 'https://books.google.com/books/content?id=...&zoom=5'
// },
// // ... more results
// ]

Query Operators

Google Books supports advanced search:

// Search by title
await googleBooks.searchBooks('intitle:Harry Potter');

// Search by author
await googleBooks.searchBooks('inauthor:Rowling');

// Search by ISBN
await googleBooks.searchBooks('isbn:9780743273565');

// Search by publisher
await googleBooks.searchBooks('inpublisher:Penguin');

// Combine operators
await googleBooks.searchBooks('intitle:gatsby inauthor:fitzgerald');

2. ISBN Lookup

Get book details by ISBN-10 or ISBN-13.

Get Book by ISBN

const book = await googleBooks.getBookByISBN('9780743273565');

if (book) {
console.log('Title:', book.title);
console.log('Authors:', book.authors.join(', '));
console.log('Cover:', book.coverImageUrl);
} else {
console.log('Book not found');
}

3. Get Book by ID

Retrieve book using Google Books volume ID.

Get by Volume ID

const book = await googleBooks.getBookById('iXn5U2IzVH0C');

// Returns GoogleBookData or null

Volume IDs are permanent identifiers in Google Books.

Data Structures

GoogleBookData

interface GoogleBookData {
googleBooksId: string; // Google Books volume ID
isbn13?: string; // ISBN-13 if available
isbn10?: string; // ISBN-10 if available
title: string; // Book title
subtitle?: string; // Subtitle if present
authors: string[]; // Array of authors
publisher?: string; // Publisher name
publishedDate?: Date; // Publication date
description?: string; // Book description
pageCount?: number; // Number of pages
categories: string[]; // Subject categories
coverImageUrl?: string; // Full-size cover (zoom=1)
thumbnailUrl?: string; // Small thumbnail (zoom=5)
}

Cover Image Sizes

Google Books provides cover images at different zoom levels:

  • zoom=0: Thumbnail (128px)
  • zoom=1: Small (256px)
  • zoom=2: Medium (512px)
  • zoom=3: Large (1024px)
  • zoom=5: Extra small (96px)

The integration uses:

  • coverImageUrl: zoom=1 (256px) - good for display
  • thumbnailUrl: zoom=5 (96px) - good for lists

API Details

Base URL

https://www.googleapis.com/books/v1/volumes

Authentication

Query parameter authentication:

?key={GOOGLE_BOOKS_API_KEY}

Rate Limits

Google Books API free tier:

  • 1,000 requests per day per API key
  • 100 requests per 100 seconds per user

Rate limits can be increased by:

  • Using OAuth 2.0 authentication
  • Purchasing additional quota

Caching Strategy

Cache Configuration

private cachePrefix = 'google-books:';
private cacheTTL = 24 * 60 * 60; // 24 hours

Cache Keys

  • Search: google-books:search:{query}:{maxResults}
  • ISBN: google-books:isbn:{isbn}
  • Volume ID: google-books:id:{volumeId}

Why Cache?

  • Reduces API calls against quota
  • Improves response time
  • Book metadata rarely changes
  • Handles API downtime gracefully

Error Handling

Rate Limit Errors

try {
const books = await googleBooks.searchBooks(query);
} catch (error) {
if (error.message === 'Rate limit exceeded for Google Books API') {
// Serve from cache or wait
}
}

Not Found

Returns null for ISBN lookups without throwing:

const book = await googleBooks.getBookByISBN('invalid-isbn');
// book === null

Network Errors

Returns empty array for search failures:

const results = await googleBooks.searchBooks('query');
// results === [] on error (fallback behavior)

Image URL Handling

HTTP to HTTPS Conversion

Google Books sometimes returns HTTP URLs. The integration automatically converts them:

const convertToHttps = (url?: string) =>
url?.replace(/^http:\/\//i, 'https://');

This prevents mixed content warnings in HTTPS apps.

Image Quality

To get higher quality images, modify zoom parameter:

// Original URL
const url = 'https://books.google.com/books/content?id=ABC&zoom=1';

// Higher quality
const highQuality = url.replace('zoom=1', 'zoom=2');

ISBN Extraction

Google Books returns ISBNs in industryIdentifiers:

{
industryIdentifiers: [
{ type: 'ISBN_13', identifier: '9780743273565' },
{ type: 'ISBN_10', identifier: '0743273565' }
]
}

The integration extracts both formats for maximum compatibility.

Integration with Book Service

Example fallback pattern:

import { createISBNdbClient } from '../integrations/isbndb';
import { createGoogleBooksClient } from '../integrations/google-books';

async function enrichBookMetadata(isbn: string) {
// Try ISBNdb first (more complete ISBN database)
const isbndb = createISBNdbClient(process.env.ISBNDB_API_KEY);
let book = await isbndb.getBookByISBN(isbn);

if (!book) {
// Fallback to Google Books
const googleBooks = createGoogleBooksClient(process.env.GOOGLE_BOOKS_API_KEY);
book = await googleBooks.getBookByISBN(isbn);
}

return book;
}

Cover Image Priority

async function getBestCoverImage(isbn: string) {
const googleBooks = createGoogleBooksClient(process.env.GOOGLE_BOOKS_API_KEY);
const book = await googleBooks.getBookByISBN(isbn);

if (book?.coverImageUrl) {
// Google Books usually has best cover images
return book.coverImageUrl;
}

// Fallback to ISBNdb or other sources
return null;
}

Best Practices

  1. Use as Secondary Source: Google Books is best for cover images and international books
  2. Cache Aggressively: Book metadata doesn't change
  3. Handle Quotas: Monitor daily quota usage
  4. HTTPS Conversion: Always convert image URLs to HTTPS
  5. Fallback Strategy: Have ISBNdb or other source as backup
  6. Advanced Search: Use query operators for better results
  7. Volume IDs: Store Google Books IDs for permanent references

Use Cases

1. Cover Art Enhancement

Get high-quality cover images:

async function updateBookCovers() {
const booksWithoutCovers = await getBooksWithoutCovers();

for (const book of booksWithoutCovers) {
const googleBook = await googleBooks.getBookByISBN(book.isbn);

if (googleBook?.coverImageUrl) {
await updateBookCover(book.id, googleBook.coverImageUrl);
}
}
}

2. International Books

Google Books has better coverage of non-US books:

async function searchInternationalBooks(query: string) {
// Google Books more reliable for international titles
return await googleBooks.searchBooks(query, 50);
}

3. Search Results

Power book search with Google's full-text search:

async function searchCatalog(query: string) {
const results = await googleBooks.searchBooks(query, 20);

return results.map(book => ({
id: book.googleBooksId,
title: book.title,
authors: book.authors,
cover: book.thumbnailUrl,
isbn: book.isbn13 || book.isbn10
}));
}

Comparison with ISBNdb

Google Books Advantages

  • Free with generous quota
  • Better cover images
  • Full-text search
  • International coverage
  • Preview pages available
  • No rate limits (within quota)

ISBNdb Advantages

  • More complete ISBN database
  • Better metadata for US books
  • Includes MSRP pricing
  • Higher reliability
  • Commercial support

Use both in combination:

  1. Use Google Books for:
    • Cover images
    • International books
    • Full-text search
    • Free tier usage
  2. Use ISBNdb for:
    • US book metadata
    • ISBN coverage
    • Pricing data
    • When Google Books quota exceeded

Testing

Mock Data

For testing without API key:

const mockBook: GoogleBookData = {
googleBooksId: 'iXn5U2IzVH0C',
isbn13: '9780743273565',
isbn10: '0743273565',
title: 'The Great Gatsby',
authors: ['F. Scott Fitzgerald'],
publisher: 'Scribner',
publishedDate: new Date('2004-05-01'),
description: 'A classic novel...',
pageCount: 180,
categories: ['Fiction'],
coverImageUrl: 'https://example.com/cover.jpg',
thumbnailUrl: 'https://example.com/thumb.jpg'
};

Test Volume IDs

Known volume IDs for testing:

  • iXn5U2IzVH0C - The Great Gatsby
  • hFfhrCWiLSMC - The Giver
  • PGR2AwAAQBAJ - To Kill a Mockingbird

Test Searches

Common test queries:

  • isbn:9780743273565 - Exact ISBN match
  • intitle:gatsby - Title search
  • inauthor:fitzgerald - Author search

Timeout Configuration

The integration uses 5-second timeout:

const response = await axios.get(this.baseUrl, {
params: { q: query, maxResults, key: this.apiKey },
timeout: 5000
});

This prevents slow API responses from blocking requests.

Limitations

  • No Pricing: Google Books doesn't provide wholesale/retail pricing
  • Quota Limits: Free tier limited to 1,000 requests/day
  • Search Relevance: Search results may include less relevant books
  • Metadata Gaps: Some books missing authors or descriptions
  • Preview Restrictions: Preview content limited by publisher agreements
  • Date Formats: Published dates may be incomplete (year-only)

Monitoring

Track usage against quota:

// Log API calls
logger.info('google_books.api_call', {
query,
resultsCount: results.length,
cached: false
});

// Track daily quota
await redis.incr('metrics:google_books:daily_calls');

Additional Resources