Amazon Links and Buttons
Tags: ai, oo, amazon, perl
Published: 2024-03-30 14:34:09

---
title: Amazon Links and Buttons
published: true
date: 2024-03-30 12:59:07 UTC
tags: ai,oo,amazon,perl
canonical_url: https://perlhacks.com/2024/03/amazon-links-and-buttons/
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z2h3j9zocwcxf3vp9sf0.png
---

I’ve spent more than a reasonable amount of time thinking about Amazon links over the last three or four years.

It started with the [Perl School](https://perlschool.com/) web site. Obviously, I knew that the [book page](https://perlschool.com/books/the-best-of-perl-hacks/) needed a link to Amazon – so people could buy the books if they wanted to – but that’s complicated by the fact that Amazon has so many different sites and I have no way of knowing which site is local to anyone who visits my web site. I had the same problem when I built a web site for [_George and the Smart Home_](https://george.davecross.co.uk/). And again when I created a site for [Will Sowman’s books](https://will.sowman.org/). At some point soon, I’ll also want to put book pages on the [Clapham Tech Press](https://claphamtechpress.com/) web site – and that will have exactly the same problem.

That’s the user-visible side of the equation. There are other reasons for wanting to know about all of the existing Amazon sites. One of the best ones is because I want to track royalties from the various sites and apportion them to the right authors.

On the Perl School site, I solved the problem by creating a database table which contains data about the sites that I knew about at the time. Then there’s a [DBIC result class](https://github.com/davorg/perlschool/blob/master/lib/PerlSchool/Schema/Result/AmazonSite.pm) and that result set is passed to the book page template, which [builds “buy” buttons](https://github.com/davorg/perlschool/blob/master/in/book.html.tt#L74) for each site found in the result set. That works, but it’s not very portable. When it came to the other sites, I found myself writing a “make\_buttons” program which used the Perl School database table to generate some HTML which I then copied into the relevant template.

But that never sat well with me. It made me uncomfortable that all of my book sites relied on a database table that existed in one of my repos that, really, has no connection to those other sites. I thought briefly about duplicating the table into the other repos, but that set off the [“Don’t Repeat Yourself”](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) alarm in my head, so I backed away from that idea pretty quickly.

It would be great if Amazon had an API for this information. But, unless I’m blind, it seems to be the only API that they don’t provide.

So, currently, what I’ve done is to encapsulate the data in a CPAN module. It’s called [Amazon::Sites](https://metacpan.org/pod/Amazon::Sites) and I’ve been releasing slowly-improving versions of it over the last week or so – and it’s finally complete enough that I can use it to replace my database table. It might even make the code for my various book sites easier to maintain.

Maybe it will be useful to you too.

Here’s how you use it:

```
use Amazon::Sites;
 
my $sites = Amazon::Sites->new;
my @sites = $sites->sites;
my %sites = $sites->sites_hash;
my @codes = $sites->codes;
 
my $site = $sites->site('UK');
say $site->currency; # GBP
say $site->tldr; # co.uk
# etc
 
my %urls = $sites->asin_urls('XXXXXXX');
say $urls{UK}; # https://amazon.co.uk/dp/XXXXXXX
```

Once you’ve created a class of the object, you have access to a few useful methods:

- **sites** – returns a list of all of the sites the object knows about. Each element in  the list is an [Amazon::Site](https://metacpan.org/pod/Amazon::Site) object
- **sites\_hash** – returns the same information, but as a hash. The key is a two-letter ISO country code and the value is an Amazon::Site object
- **codes** – returns a list of all of the country codes that the object knows about
- **site(country\_code)** – expects a two-letter ISO country code and returns the Amazon::Site object for that country’s Amazon site

The Amazon::Site object has a number of useful attributes:

- **code** – the country code
- **country** – the country’s name in English
- **currency** – the ISO code for the currency used on that site
- **tldn** – the top-level domain name that the Amazon site uses (e.g. .com or .co.uk)
- **domain** – the full domain that the Amazon site used (e.g. amazon.com or amazon.co.uk)

Amazon::Site also has a “asin\_url()” method. You pass it an ASIN (that’s the unique identifier that Amazon uses for every product on its site) and it returns the full URL of that product on that site. There’s a similar “asin\_urls()” (note the “s” at the end) on the Amazon::Sites object. That returns a hash of URLs for all of the sites the object knows about. The key is the country code and the value is the URL in that country.

You can also filter the list of Amazon sites that you’re interested in when creating your Amazon::Sites object. The constructor takes optional “include” and “exclude” arguments. Each of them is a reference to an array of ISO country codes. For reasons that are, I hope, obvious, you can only use one of those options at a time.

If you’re an Amazon Associate, you can make money by including your “associate code” in Amazon URLs that you share with people. Amazon::Sites deals with that too. An Amazon associate code is associated with one Amazon site. So the constructor method has an optional “assoc\_codes” argument which is a hash mapping country codes to associate codes. If you have set up associate codes in your Amazon::Sites object, then your associate code will be included in any URLs that are generated by the modules – as long as the URL is for one of the sites that you have an associate code for.

That’s all it does at the moment. It addresses most of my needs. There’s one more feature I might add soon. I’d like to have template processing built-in – so if I have a template and an Amazon::Sites object, I can easily process that template for every site that the object knows about.

So that’s the class. I hope someone out there finds it useful. If you think it’s almost useful, but there’s a feature missing then please [let me know](https://github.com/davorg-cpan/amazon-sites/issues) (or even send [a pull request](https://github.com/davorg-cpan/amazon-sites/pulls)).

But there are a couple of other things I’d like to mention about how I wrote this class.

Firstly, this is written using the new [perlclass OO syntax](https://perldoc.perl.org/perlclass). Specifically, it uses [Feature::Compat::Class](https://metacpan.org/pod/Feature::Compat::Class), so you can use it on versions of Perl back to 5.26. It’s true that the new syntax doesn’t have all the features that you’d get with something like Moose, but I love using it – and over the next few versions of Perl, it will only get better and better. If you haven’t tried the new syntax yet, then I recommend you have a look at it.

Secondly, this is the first new CPAN distribution I’ve written since I’ve had my subscription to [GitHub Copilot](https://github.com/features/copilot). And I’m really impressed at how much faster I was using Copilot. As I said, I was using experimental new Perl syntax, so I was impressed at how well Copilot understood what I was doing. I lost count of the number of times I typed the name of a new method and Copilot instantly wrote the code for me – an 95% of the time the code it wrote was spot on. AI programming support is here and it’s good. If you’re not using it yet, then you’re losing out.

I’m told a good blog post needs a “call to action”. This one has three:

1. Start using Perl’s new class syntax
2. Look at GitHub Copilot and similar tools
3. Please use my new module

The post [Amazon Links and Buttons](https://perlhacks.com/2024/03/amazon-links-and-buttons/) appeared first on [Perl Hacks](https://perlhacks.com).