private function getChangelogFromApi(string $uri, string $body_attribute, string $tag_attribute): string
    {
        try {
            return cache()->remember($this->getChangelogCacheKey($uri), 30, function () use ($uri, $body_attribute, $tag_attribute) {
                $changelog = '';

                // retrieve releases from provided API endpoint
                $client = new Client();
                $response = $client->request('GET', $uri);

                // decode the response
                $json_object = json_decode($response->getBody());

                // spawn a new Markdown parser
                $parser = new Parsedown();
                $parser->setSafeMode(true);

                // iterate over each release and build proper view
                foreach ($json_object as $release) {
                    $changelog .= view('web::configuration.settings.partials.packages.changelog.header', [
                        'version' => $release->{$tag_attribute},
                    ]);

                    $changelog .= view('web::configuration.settings.partials.packages.changelog.body', [
                        'body' => $parser->parse($release->{$body_attribute}),
                    ]);
                }

                // return a rendered release list
                return $changelog;
            });
        } catch (Exception $e) {
            logger()->error('An error occurred while fetching changelog from API.', [
                'code'       => $e->getCode(),
                'error'      => $e->getMessage(),
                'trace'      => $e->getTrace(),
                'uri'        => $uri,
                'attributes' => [
                    'body' => $body_attribute,
                    'tag'  => $tag_attribute,
                ],
            ]);
        }

        return '';
    }