Search code examples
javascriptreactjsarchitecturehexagonal-architecture

Hexagonal Architecture on a front end React app


I have been requested to do a mini app using Hexagonal Architecture for a front end app using a rest api. And I got a great dilema.

In an effort to make use of the ports and adapters approach, I have creates this folder structure

adapters = `fetching the data`
application = `hooks to store the data`
domain = `logic to filter the data for the hooks`
presentation = `the rendering of the data`

The problem is that the response from the itunes api returns about 15 properties and I only need about 4 so I am tempted to filter at the adapter level to get only what I need. But I feel I will be breaking the pricinpel of the architecture.

What gives? Would I be doing something good performance wise by pre filtering?

Adapter raw

export async function fetchTopPodcasts() {
  const endpoint =
    'https://itunes.apple.com/us/rss/toppodcasts/limit=100/genre=1310/json';
  const proxy = `https://api.allorigins.win/get?url=${encodeURIComponent(
    endpoint,
  )}`;

  try {
    const response = await fetch(proxy);
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    const podcasts = JSON.parse(data.contents);

    return podcasts.feed.entry;
  } catch (error) {
    console.error('Fetch error:', error);
    throw error;
  }
}

Adapter filtered

export async function fetchTopPodcasts() {
  const endpoint =
    'https://itunes.apple.com/us/rss/toppodcasts/limit=100/genre=1310/json';
  const proxy = `https://api.allorigins.win/get?url=${encodeURIComponent(
    endpoint,
  )}`;

  try {
    const response = await fetch(proxy);
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    const podcasts = JSON.parse(data.contents).feed.entry;

    // Filter the necessary data
    return podcasts.map(podcast => ({
      id: podcast.id.attributes['im:id'],
      name: podcast['im:name'].label,
      image: podcast['im:image'][2].label,
      author: podcast['im:artist'].label,
    }));
  } catch (error) {
    console.error('Fetch error:', error);
    throw error;
  }
}

Solution

  • Remeber that buisness (core/domain) layers should not know about the infrastructure layer (because otherwise you cannot swap adapters, breaking hexagonal principles).

    So your usecase shouldn't know the model of an itunes object. The answer to your question is to filter out what you don't need at the adapter level. That way, you can swap out the itunes adapter for another vendor say Spotify while not having to change the buissness layer. This requires the buisness layer to have a description of what is a podcast of its own.

    This is also helpful for testing for you can now pass a test double/stub to the usecase instead of having to mock the adapter.