NASA Astronomy Picture of the Day

Here is my first attempt of building a single HTML page, using the RSS feed taken from NASA Astronomy Picture of the Day (APOD)

The application written in Go carries out the following.

  • makes a HTTP request for the RSS feed

  • process the XML feed data

  • display feed data on a single HTML page

RSS Feed

Here’s what the feed data looks like.

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
   <channel>
      <title>APOD</title>
      <link>https://apod.nasa.gov/</link>
      <description>Astronomy Picture of the Day</description>
      <language>en-us</language>
      <image>
         <title>APOD</title>
         <url>https://apod.nasa.gov/favicon.ico</url>
         <link>https://apod.nasa.gov/</link>
      </image>
      <item>
         <title>Eclipse under the ISS</title>
         <link>https://apod.nasa.gov/apod/astropix.html</link>
         <description>&lt;p&gt;&lt;a href="https://apod.nasa.gov/apod/astropix.html"&gt;&lt;img src="https://apod.nasa.gov/apod/calendar/S_200627.jpg" align="left" alt="The dark shadow of the New Moon reached out and touched planet Earth on" border="0" /&gt;&lt;/a&gt; The dark shadow of the New Moon reached out and touched planet Earth on&lt;/p&gt;&lt;br clear="all"/&gt;</description>
      </item>
      <item>
         <title>Eclipse under the Bamboo</title>
         <link>https://apod.nasa.gov/apod/ap200626.html</link>
         <description>&lt;p&gt;&lt;a href="https://apod.nasa.gov/apod/ap200626.html"&gt;&lt;img src="https://apod.nasa.gov/apod/calendar/S_200626.jpg" align="left" alt="Want to watch a solar eclipse safely?" border="0" /&gt;&lt;/a&gt; Want to watch a solar eclipse safely?&lt;/p&gt;&lt;br clear="all"/&gt;</description>
      </item>
      <item>
         <title>Eclipse Street, Hong Kong</title>
         <link>https://apod.nasa.gov/apod/ap200625.html</link>
         <description>&lt;p&gt;&lt;a href="https://apod.nasa.gov/apod/ap200625.html"&gt;&lt;img src="https://apod.nasa.gov/apod/calendar/S_200625.jpg" align="left" alt="Eclipse Street, Hong Kong" border="0" /&gt;&lt;/a&gt; Eclipse Street, Hong Kong&lt;/p&gt;&lt;br clear="all"/&gt;</description>
      </item>
      <item>
         <title>Inverted City Beneath Clouds</title>
         <link>https://apod.nasa.gov/apod/ap200624.html</link>
         <description>&lt;p&gt;&lt;a href="https://apod.nasa.gov/apod/ap200624.html"&gt;&lt;img src="https://apod.nasa.gov/apod/calendar/S_200624.jpg" align="left" alt="How could that city be upside-down?" border="0" /&gt;&lt;/a&gt; How could that city be upside-down?&lt;/p&gt;&lt;br clear="all"/&gt;</description>
      </item>
      <item>
         <title>The X Ray Sky from eROSITA</title>
         <link>https://apod.nasa.gov/apod/ap200623.html</link>
         <description>&lt;p&gt;&lt;a href="https://apod.nasa.gov/apod/ap200623.html"&gt;&lt;img src="https://apod.nasa.gov/apod/calendar/S_200623.jpg" align="left" alt="What if you could see X-rays? " border="0" /&gt;&lt;/a&gt; What if you could see X-rays? &lt;/p&gt;&lt;br clear="all"/&gt;</description>
      </item>
      <item>
         <title>Moon Mountains Magnified during Ring of Fire Eclipse</title>
         <link>https://apod.nasa.gov/apod/ap200622.html</link>
         <description>&lt;p&gt;&lt;a href="https://apod.nasa.gov/apod/ap200622.html"&gt;&lt;img src="https://apod.nasa.gov/apod/calendar/S_200622.jpg" align="left" alt="What are those dark streaks in this composite image of yesterday's solar eclipse?" border="0" /&gt;&lt;/a&gt; What are those dark streaks in this composite image of yesterday's solar eclipse?&lt;/p&gt;&lt;br clear="all"/&gt;</description>
      </item>
      <item>
         <title>Moon Occults Venus</title>
         <link>https://apod.nasa.gov/apod/ap200621.html</link>
         <description>&lt;p&gt;&lt;a href="https://apod.nasa.gov/apod/ap200621.html"&gt;&lt;img src="https://apod.nasa.gov/apod/calendar/S_200621.jpg" align="left" alt="It may look like " border="0" /&gt;&lt;/a&gt; It may look like &lt;/p&gt;&lt;br clear="all"/&gt;</description>
      </item>
      <textInput>
         <title>Search APOD</title>
         <description>Search APOD</description>
         <name>query</name>
         <link>https://apod.nasa.gov/cgi-bin/apod/apod_search</link>
      </textInput>
   </channel>
</rss>

Making a HTTP request

func makeRequest(done chan<- nasaRSS) {
    client := httpClient()

    req, err := http.NewRequest("GET", requestURL, nil)

    checkError(err)

    resp, err := client.Do(req)

    if resp.StatusCode != 200 {
            body, _ := ioutil.ReadAll(resp.Body)
            fmt.Println(string(body))
            log.Fatal("Request status = ", resp.StatusCode)

    }

    defer resp.Body.Close()

    var responseBody nasaRSS

    body, err := ioutil.ReadAll(resp.Body)

    checkError(err)

    xml.Unmarshal(body, &responseBody)

    done <- responseBody
}

Unmarshal

Parses the XML-encoded data and stores the result in the value responseBody which is of a new type created nasaRss

Processing the feed data

A struct was created to encapsulate the data.

Notice the fields map to each element within the RSS XML feed.

The purpose of this struct was to ensure

// nasaRSS declaring struct
type nasaRSS struct {
    XMLName xml.Name `xml:"rss"`
    Text    string   `xml:",chardata"`
    Version string   `xml:"version,attr"`
    Channel struct {
            Text        string `xml:",chardata"`
            Title       string `xml:"title"`
            Link        string `xml:"link"`
            Description string `xml:"description"`
            Language    string `xml:"language"`
            Image       struct {
                    Text  string `xml:",chardata"`
                    Title string `xml:"title"`
                    URL   string `xml:"url"`
                    Link  string `xml:"link"`
            } `xml:"image"`
            Item []struct {
                    Text        string `xml:",chardata"`
                    Title       string `xml:"title"`
                    Link        string `xml:"link"`
                    Description string `xml:"description"`
            } `xml:"item"`
            TextInput struct {
                    Text        string `xml:",chardata"`
                    Title       string `xml:"title"`
                    Description string `xml:"description"`
                    Name        string `xml:"name"`
                    Link        string `xml:"link"`
            } `xml:"textInput"`
    } `xml:"channel"`
}

Description

<description>&lt;p&gt;&lt;a href="https://apod.nasa.gov/apod/ap200621.html"
&gt;&lt;img src="https://apod.nasa.gov/apod/calendar/S_200621.jpg" 
align="left" alt="It may look like " border="0" /&gt;&lt;/a&gt; It may look like &lt;/p&gt;&lt;br clear="all"/&gt;
</description>

The text inside the <description> tag contains escaped HTML since it’s XML encoded.

This also contains an <img> tag.

In order to extract the information out of the description tag.

A regex was used to pull the img src (thumbnail) and description out.

func parseDescription(str string, opt string) string {

        switch opt {
        case "img":
                r, _ := regexp.Compile(`<img src\s*=\s*"(.+?)"`)
                return r.FindStringSubmatch(str)[1]

        case "desc":
                r, _ := regexp.Compile(`alt\s*=\s*"(.+?)"`)
                return r.FindStringSubmatch(str)[1]
        default:
                panic("Invalid option for parsing description.")
        }

}

In the end the extracted values look like.

Description = “It may look like”

Img src = https://apod.nasa.gov/apod/calendar/S_200621.jpg

Template

In order to generate the dynamic content inside an HTML page, the go package html/template was used.

This package allowed dynamic injection of data to be inserted at runtime.

Struct

Another struct was used to help with the rendering of the HTML page.

type htmlRender struct {
    Title       string
    Link        string
    ImgSrc      string
    Description string
}

From the below HTML code example.

Field Template notation Description
N/A {{range $items := .}} Loop a list of items, in this case these are the entries taken from the XML feed
Title {{.Title}} Display the title of the individual item taken from the RSS feed
Description {{.Description}} Display the description content
ImgSrc {{.ImgSrc}} Used to display the image
<!DOCTYPE html>
<html>

<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
        integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
        integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
        crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"
        integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI"
        crossorigin="anonymous"></script>
    <title>APOD</title>
</head>

<body>
    <div class="container">
        <p class="text-center"><a href="https://apod.nasa.gov/apod/" target="_blank"> Astronomy Picture of the Day</a></p>
      
        <div class="row">
            <div class="col-sm" style="width: 40rem;">
                {{range $items := .}}
                <div class="card">
                    <div class="card-header">
                        <b>{{.Title}}</b>
                    </div>
                    <div class="card-body">
                        
                        <img src="{{.ImgSrc}}" class="rounded float-right"/>
                        <p class="card-text">{{.Description}}</p>
                        
                         <a href="{{.Link}}" target="_blank" class="btn btn-primary btn-sm">{{.Title}}</a>
                    </div>
                </div>
                <p></p>
                {{end}}
            </div>
        </div>
    </div>
</body>
</html>

The HTML code also includes references to Bootstrap a library to enhance the UI.

HTML page

Last updated on 25 Jun 2020
Published on 25 Jun 2020