I have a couple of ideas/projects that require getting details from a URL and displaying them with a nice UI "component". One of such ideas is having better links in the References section of each post. A native list is currently being used, but it would be nice to have the title of each link displayed without compromising on my writing experiencing.
Requirements
- Build a simple service to power the References on articles
- The frontend sends links
- The service makes a request to each link and returns the following:
- Title
- SEO image
- Short description
- Favicon URL
The title
will be the only parameter used in the first iteration of this feature.
Thought process
I'll be trying a different approach this time around. Rather than spending time doing a lot of research, I'll come up with a quick solution first, then research on areas of improvements. Here's a breakdown of a quick solution:
- Make a request to the specified endpoint
- Check for
2xx
status code - Parse HTML document
- Return the parsed content to the client
Implementation
I need an endpoint to make a request to the specified URL and return the parsed content. For a start, I need these functions:
FetchPageDetails()
: A HTTP handler that initiates a request to the specified URLparseHTML()
: An internal function that processes the result of the HTTP requestparseFaviconURL()
: Builds the full URL for the favicon if only the path is providedisFullURL()
: Check if a URL contains the host/domain name
With the project in place, I created the main.go
,bookmark_test.go
and bookmark.go
in the root directory.
Fetching the HTML
To validate my thought process, I wrote the test to fetch a page given a URL, checking to see if a 200
response is returned. Then I'm able to implement the feature to make the test pass:
Parsing the HTML
With the page now being fetched, I need to get the necessary details for the frontend. From the requirements, the necessary details can be found in the <head>
tag. This makes parsing slightly easier. Over to the test:
The test gives an insight into the implementation of the feature. I'll need a HTML parser that allows me walk through the HTML tree with ease. I found GoQuery, a library built on top of the net/html
library, to handle the HTML parsing:
With GoQuery
installed, I can now implement the parsing logic:
Handling favicons
I considered using the favicon for the frontend component, so I decided to extend the response. Favicons can be specified with a fully qualified URL or a resource path. It would be easier to have a single representation for it. To do this, I need to check if the URL is a resource path or not. For a resource path, I simply append it to the main URL:
Refactoring
With the parsing logic in place, I can now refactor the fetch test and finalise the function implementation:
Router
A router can now be created to provide access to the client. In the main()
function of the main.go
file, I created and configured the server multiplexer:
Usage
This site is built with Astro and Markdoc is used to manage content. Without going out of scope of this article, using the API is a three step process:
- I built a
Bookmark
component in Astro - I added the
.astro
component to the Markdoc configured - In the References section, I wrapped the native list with the Markdoc/Astro component:
The References section below is the outcome of the first phase of this feature.
Going forward
- How do I handle pages that have anti-bot?
- How should I handle missing
og:image
? - Where should I deploy? Coolify? Or a general cloud provider?
- How should storage be handled? DB or Cache or both?
- I should use Goroutines to manage simultaneous requests from the client