Skip to main content

Overview

The NASA Explorer app uses multiple model classes to represent data across different layers of the architecture. This page documents the response models, domain models, and favorite models.

Architecture Layers

Data Layer

NasaResponse - Raw API response mapping

Domain Layer

NasaModel - Business logic model

Persistence Layer

FavoriteNasaModel - Firebase storage model

NasaResponse (Data Layer)

Maps the complete structure of NASA’s APOD API response using Gson serialization.
package com.ccandeladev.nasaexplorer.data.api

import com.ccandeladev.nasaexplorer.domain.NasaModel
import com.google.gson.annotations.SerializedName

data class NasaResponse(
    @SerializedName("title") val title: String,
    @SerializedName("url") val url: String,
    @SerializedName("date") val date: String,
    @SerializedName("explanation") val explanation: String,
    @SerializedName("media_type") val mediaType: String?,
    @SerializedName("hdurl") val hdUrl: String?,
    @SerializedName("service_version") val serviceVersion: String?,
    @SerializedName("copyright") val copyright: String?
)

Fields

title
String
required
Title of the astronomy picture or video
url
String
required
URL of the standard resolution media
date
String
required
Date of the APOD in YYYY-MM-DD format
explanation
String
required
Detailed explanation of the astronomical content
mediaType
String
Type of media: “image” or “video”
hdUrl
String
URL of the high-definition version (if available)
serviceVersion
String
Version of the APOD API service
Copyright information for the media

Extension Function

Converts API response to domain model:
fun NasaResponse.toNasaModel(): NasaModel {
    return NasaModel(
        title = this.title,
        url = this.url,
        date = this.date,
        explanation = this.explanation
    )
}
The extension function filters out optional fields, keeping only essential data for the UI layer.

NasaModel (Domain Layer)

Simplified model containing only the data needed for business logic and UI rendering.
package com.ccandeladev.nasaexplorer.domain

data class NasaModel(
    val title: String,
    val url: String,
    val date: String,
    val explanation: String,
)

Purpose

Decouples data layer from business logic and UI
Simplifies UI components by providing only necessary fields
Protects against API changes affecting the entire application

Fields

title
String
Display title for the astronomy image
url
String
Image or video URL for display
date
String
Date in YYYY-MM-DD format for sorting and display
explanation
String
Full explanation text for detail screens

Usage Example

// In ViewModel
val nasaImage = NasaModel(
    title = "The Horsehead Nebula",
    url = "https://apod.nasa.gov/apod/image/2401/horsehead.jpg",
    date = "2024-01-15",
    explanation = "One of the most identifiable nebulae in the sky..."
)

// In Composable
@Composable
fun ImageCard(nasaModel: NasaModel) {
    Column {
        Text(text = nasaModel.title, style = MaterialTheme.typography.h6)
        AsyncImage(model = nasaModel.url, contentDescription = nasaModel.title)
        Text(text = nasaModel.date, style = MaterialTheme.typography.caption)
        Text(text = nasaModel.explanation)
    }
}

FavoriteNasaModel (Persistence Layer)

Model for storing favorite images in Firebase with unique identifiers.
package com.ccandeladev.nasaexplorer.domain

data class FavoriteNasaModel(
    val firebaseImageId: String,
    val title: String,
    val url: String
)

Fields

firebaseImageId
String
required
Unique ID generated by Firebase for each saved image
title
String
required
Title of the favorited astronomy image
url
String
required
Image URL for display in favorites list

Purpose

The firebaseImageId is essential for:
  • Uniquely identifying favorites in Firebase
  • Enabling delete operations
  • Linking images to user comments

Usage Example

// Saving a favorite
fun saveFavorite(nasaModel: NasaModel) {
    val favoriteRef = firestore.collection("favorites").document()
    val favorite = FavoriteNasaModel(
        firebaseImageId = favoriteRef.id,
        title = nasaModel.title,
        url = nasaModel.url
    )
    favoriteRef.set(favorite)
}

// Deleting a favorite
fun deleteFavorite(favoriteNasaModel: FavoriteNasaModel) {
    firestore.collection("favorites")
        .document(favoriteNasaModel.firebaseImageId)
        .delete()
}

Model Transformation Flow

1

API Response

NASA API returns JSON, deserialized to NasaResponse
2

Domain Conversion

Repository converts NasaResponse to NasaModel using toNasaModel()
3

UI Display

ViewModel exposes NasaModel to Composables
4

Persistence

User favorites are saved as FavoriteNasaModel in Firebase

Best Practices

Always use domain models (NasaModel) in your UI layer, never expose raw API responses.
Keep domain models immutable using val properties for thread safety.
Use data classes for automatic equals(), hashCode(), and copy() implementations.

Build docs developers (and LLMs) love