Skip to content

Connectors

Connectors are the server’s interface for talking to the scraper microservices. They abstract HTTP communication, normalize response formats, and provide a unified API for both platforms.

Backend Service Layer
ConnectorInterface
┌────┴─────────────────┐
▼ ▼
ITunesLookupConnector GooglePlayConnector
│ │
▼ ▼
scraper-ios :7462 scraper-android :7463

All connectors implement the same interface:

interface ConnectorInterface
{
public function supports(string $platform): bool;
public function fetchIdentity(App $app, string $country = 'us'): ConnectorResult;
public function fetchListings(App $app, string $country = 'us', ?string $locale = null): ConnectorResult;
public function fetchMetrics(App $app, string $country = 'us'): ConnectorResult;
public function fetchDeveloperApps(string $developerExternalId): ConnectorResult;
public function fetchSearch(string $term, int $limit = 10, string $country = 'us'): array;
public function fetchChart(string $collection, string $country, ?string $categoryExternalId = null): array;
public function getSourceName(): string;
}

Every connector method returns a ConnectorResult:

class ConnectorResult
{
public readonly bool $success;
public readonly array $data;
public readonly ?string $error;
public readonly ?int $statusCode;
}
  • ConnectorResult::success($data) — Successful response carrying normalized data
  • ConnectorResult::failure($error, $statusCode) — Failed response with error details (404 becomes empty_response)

Talks to the App Store scraper microservice (scraper-ios).

MethodScraper EndpointKey Response Fields
fetchIdentityGET /apps/:appId/identityname, publisher, category, locales, release_date, is_free
fetchListingsGET /apps/:appId/listingstitle, subtitle, promotional_text, description, whats_new, screenshots, icon, price
fetchMetricsGET /apps/:appId/metricsrating, rating_count, rating_breakdown, file_size
fetchDeveloperAppsGET /developers/:id/appsapps[] with basic details
fetchSearchGET /apps/searchresults[] with app_id, name, developer
fetchChartGET /chartsranked results (up to 200 apps)

The iOS identity response conveys free/paid information as an is_free boolean. The listing payload includes a promotional_text field.

Configuration: appstorecat.connectors.appstore.base_url, appstorecat.connectors.appstore.timeout

Talks to the Google Play scraper microservice (scraper-android).

MethodScraper EndpointKey Response Fields
fetchIdentityGET /apps/{app_id}/identitySame as the iTunes connector
fetchListingsGET /apps/{app_id}/listingsSame (uses locale instead of lang; promotional_text is always null)
fetchMetricsGET /apps/{app_id}/metricsSame (no file_size_bytes; rating is global for Play)
fetchDeveloperAppsGET /developers/{id}/appsSame
fetchSearchGET /apps/searchSame
fetchChartGET /chartsSame (default category: APPLICATION, maximum 100)

Since Android metrics have no per-country separation, AppSyncer writes them to the app_metrics table under the zz “Global” sentinel country.

Configuration: appstorecat.connectors.gplay.base_url, appstorecat.connectors.gplay.timeout

Both connectors normalize store-specific response formats into a consistent structure. For example:

  • Screenshots: Both return string[] URL arrays
  • Rating breakdown: Both return {1: count, 2: count, ..., 5: count}
  • Publisher: Both return publisher_name, publisher_external_id, publisher_url
  • Identity: Both return the same fields (some may be null depending on platform)

This normalization happens in the connector layer so that the service layer (AppSyncer) needs no platform-specific logic.

  • 404 responses: Indicate the app is not available on this storefront. The connector returns a failure with an empty_response error. The syncer treats this as a permanent “not in this country” signal — the pipeline writes app_metrics.is_available = false for the country and does not retry forever. The Android scraper raises an explicit AppNotFoundError that the FastAPI exception handler converts to 404.
  • Timeout: Configurable per connector (default 30 seconds). Jobs retry with exponential backoff.
  • Rate limiting: Handled at the job level via Redis throttle, not in the connector.