Building an Art Gallery SPA with the Met Museum API
Published: 2024-03-04 01:40:01

## Introduction
For my Phase 1 final project at the Flatiron School's Software Engineering program, I developed an Art Gallery Single Page Application (SPA) utilizing the Metropolitan Museum of Art's API. This project allows users to explore artworks from specific artists in the Met's vast collection.


## Background
In this project, I used JavaScript, HTML, and CSS to create the SPA. The key functionalities were implemented using event listeners and Fetch API for making asynchronous HTTP requests to the Met Museum's API endpoints.

## Implementation

The core functionality of the application revolved around fetching data from the Met Museum's API endpoints. Here's how we achieved this:

### API Integration
We made use of the Met Museum's API endpoints to gather information about artworks and artists. The primary endpoints utilized were:

*Search Endpoint*: https://collectionapi.metmuseum.org/public/collection/v1/search?q={query}
This endpoint allowed us to search for specific artists or artworks based on user input.

*Object Details Endpoint*: https://collectionapi.metmuseum.org/public/collection/v1/objects/{objectID}
With this endpoint, we could retrieve detailed information about individual artworks using their unique object IDs.

The following is how we use the API to collect the artwork information.
```{javascript}
async function fetchArtworks(query) {
        const response = await fetch(`https://collectionapi.metmuseum.org/public/collection/v1/search?q=${query}`);
        const data = await response.json();
        const limitedObjectIDs = data.objectIDs.slice(0, 30);
        return limitedObjectIDs;
    }

async function fetchArtworkDetails(objectID) {
        const response = await fetch(`https://collectionapi.metmuseum.org/public/collection/v1/objects/${objectID}`);
        const data = await response.json();
        return data;
    }

async function displayArtworks(query) {
        const objectIDs = await fetchArtworks(query);
        artworksGrid.innerHTML = '';
        objectIDs.forEach(async objectID => {
            const artworkDetails = await fetchArtworkDetails(objectID);
            if (artworkDetails.primaryImageSmall) {
                const artworkImage = artworkDetails.primaryImageSmall;
                const artworkTitle = artworkDetails.title;

                const artworkElement = document.createElement('div');
                artworkElement.innerHTML = `
                <div class="card">
                    <img src="${artworkImage}" class="card-img-top" alt="${artworkTitle}">
                    <div class="card-body">
                        <h5 class="card-title">${artworkTitle}</h5>
                        <button class="btn btn-primary btn-sm view-details-btn" data-artwork-id="${objectID}">View Details</button>
                    </div>
                </div>
                `;
                artworksGrid.appendChild(artworkElement);
        }
    });
}
```

### Scraper Script
To populate our database file db.json with initial artwork data, we utilized a Python script. This script scraped data from the Met Museum's API using the requests library and saved it in JSON format. Here's a snippet of the scraper script:
```{python}
import requests
import json

object_endpoint = "https://collectionapi.metmuseum.org/public/collection/v1/objects/"

def fetch_object_details(object_id):
    response = requests.get(object_endpoint + str(object_id))
    if response.status_code == 200:
        return response.json()
    else:
        return None

def fetch_and_save_objects(object_ids, filename):
    objects_data = {"artworks": []}
    for object_id in object_ids:
        object_details = fetch_object_details(object_id)
        if object_details:
            objects_data["artworks"].append(object_details)
        if len(objects_data["artworks"]) >= 100:
            break
    
    with open(filename, 'w') as f:
        json.dump(objects_data, f, indent=4)

if __name__ == "__main__":
    response = requests.get("https://collectionapi.metmuseum.org/public/collection/v1/search?medium=Paintings|Sculpture&q=europe")
    if response.status_code == 200:
        print(response.json()["total"])
        object_ids = response.json()["objectIDs"]
        fetch_and_save_objects(object_ids, "db.json")
        print("Objects fetched and saved successfully.")
    else:
        print("Failed to fetch objects.")

```

## Implementation
To start, I set up event listeners to handle user interactions such as submitting a search query or clicking on an artwork for more details. Here's a snippet of the JavaScript code:

```{javascript}
// Event listeners for search functionality and modal display
searchForm.addEventListener('submit', function (event) {
    event.preventDefault();
    performSearch();
});

searchButton.addEventListener('click', function (event) {
    event.preventDefault();
    performSearch();
});

modal.addEventListener('click', function (event) {
    if (event.target && event.target.classList.contains('close')) {
        modal.style.display = 'none';
    }
});

artworksGrid.addEventListener('click', function (event) {
    if (event.target && event.target.classList.contains('view-details-btn')) {
        const objectID = event.target.getAttribute('data-artwork-id');
        displayModal(objectID);
    }
});

```
This code sets up event listeners for search functionality, modal display, and artwork details viewing.

The following images is a demo of the website.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/59ij1ha5pztz5doc9xh4.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rsfokp4f59sb1z0p613u.png)