Skip to content

Commit 32fcfb7

Browse files
committed
Bunnyx blogpost
1 parent fba49ad commit 32fcfb7

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
%{
2+
title: "bunnyx: a bunny.net elixir client library",
3+
author: "Johanna Larsson",
4+
tags: ~w(elixir bunny bunnynet opensource),
5+
description: "A best-practice Elixir library for interacting with the bunny.net API"
6+
}
7+
---
8+
9+
[bunny.net](https://bunny.net?ref=f0l8865b7g) is a CDN service provider with lots of extra bells and whistles, most similar to Cloudflare in feature set, but maintained by a European company. Unlike Cloudflare, they’re not free, but they are cheap enough that it doesn’t really matter. Unless you’re making very heavy use of their service, you won’t be paying more than the minimum €1 each month. And as a paying customer, your relationship is a lot different than it is as a non-paying user of Cloudflare.
10+
11+
I’ve been using bunny.net for a lot of things I’ve been building recently, including the landing page and status page feature for [Larm](https://larm.dev), the uptime monitoring project I’ve been working on. As part of that work, I wanted a feature rich client library for interacting with the extensive bunny.net API.
12+
13+
# Introducing: [bunnyx](https://github.com/joladev/bunnyx)
14+
15+
This is not the first Elixir library for interacting with the bunny API. I ended up rolling my own because I wanted something that was flexible enough to fit into my system design. The version that I built into Larm wasn’t as feature rich as what I’ve ended up open sourcing here, but once I had something going, I just got into the flow of testing through the API endpoints end to end, and documenting and verifying each one. And suddenly I had a whole feature complete library.
16+
17+
[bunnyx](https://github.com/joladev/bunnyx) is built with a special focus on [the Elixir library guidelines.](https://hexdocs.pm/elixir/1.20.0-rc.4/design-anti-patterns.html#using-application-configuration-for-libraries) This means that it avoids certain things: there’s no application config and there’s no application supervisor starting automatically. Instead, it follows the design of the excellent `Req` library by Wojtek Mach. Not to mention that it internally makes heavy use of it!
18+
19+
Additionally I invested a lot of time and energy into the test suite. Apart from extensive unit test coverage, I built a series of Livebook runbooks that you can feed an API key into and execute each and every request scenario, even running through the whole book to automatically create, read, update, and delete, resources. This means you can easily verify the behavior of `bunnyx` against the actual bunny API.
20+
21+
# Quickstart
22+
23+
```elixir
24+
# Before running this, you'll need:
25+
# - A bunny.net account and API key (from the Account API section of the dashboard)
26+
# - A storage region code — DE, NY, LA, or SG. See:
27+
# https://docs.bunny.net/reference/storagezonepublic_add
28+
# - A globally unique storage zone name
29+
# - A globally unique pull zone name
30+
# - The file you want to upload
31+
32+
client = Bunnyx.new(api_key: "sk-...")
33+
34+
# 1. Create a storage zone to hold the files
35+
{:ok, storage_zone} = Bunnyx.StorageZone.create(client, name: "my-assets", region: "DE")
36+
37+
# 2. Point a pull zone at the storage zone so the files are served from the CDN
38+
{:ok, pull_zone} = Bunnyx.PullZone.create(client,
39+
name: "my-assets-cdn",
40+
storage_zone_id: storage_zone.id
41+
)
42+
43+
# 3. Upload a file via the separate storage client (its own auth and base URL)
44+
storage = Bunnyx.Storage.new(storage_key: storage_zone.password, zone: storage_zone.name)
45+
{:ok, nil} = Bunnyx.Storage.put(storage, "/images/logo.png", File.read!("logo.png"))
46+
47+
cdn_url = "https://#{pull_zone.name}.b-cdn.net/images/logo.png"
48+
# Your file is now live at cdn_url
49+
50+
# 4. Replace the file, then purge so the new version is served immediately
51+
{:ok, nil} = Bunnyx.Storage.put(storage, "/images/logo.png", File.read!("new-logo.png"))
52+
{:ok, nil} = Bunnyx.Purge.url(client, cdn_url)
53+
```
54+
55+
If you want to wrap things up for convenience, create your own wrapper module.
56+
57+
```elixir
58+
defmodule MyApp.Bunny do
59+
def create_pullzone(name, origin_url) do
60+
client = Bunnyx.new(api_key: api_key!())
61+
62+
Bunnyx.PullZone.create(client, name: name, origin_url: origin_url)
63+
end
64+
65+
def api_key! do
66+
Application.fetch_env!(:my_app, :bunny_api_key)
67+
end
68+
end
69+
```
70+
71+
# Feature set
72+
73+
**Main API (`Bunnyx.new/1`)**
74+
75+
- **CDN**`PullZone` (CRUD, hostnames, SSL, edge rules, referrers, IP blocking, statistics)
76+
- **DNS**`DnsZone` (CRUD, DNSSEC, export/import, statistics), `DnsRecord` (add, update, delete)
77+
- **Storage management**`StorageZone` (CRUD, statistics, password reset)
78+
- **Video libraries**`VideoLibrary` (CRUD, API keys, watermarks, referrers, DRM stats)
79+
- **Cache**`Purge` (URL and pull zone purging)
80+
- **Security**`Shield` (zones, WAF rules, rate limiting, access lists, bot detection, metrics, API Guardian)
81+
- **Compute**`EdgeScript` (scripts, code, releases, secrets, variables), `MagicContainers` (apps, registries, containers, endpoints, volumes)
82+
- **Account**`Billing` (details, summary, invoices), `Account` (affiliate, audit log, search), `ApiKey``Logging` (CDN + origin logs)
83+
- **Reference**`Statistics` (global), `Country``Region`
84+
85+
**Separate clients**
86+
87+
- **Edge storage** (`Bunnyx.Storage`): upload, download, delete, list files
88+
- **S3** (`Bunnyx.S3`): PUT, GET, DELETE, HEAD, COPY, ListObjectsV2, multipart uploads
89+
- **Stream** (`Bunnyx.Stream`): video CRUD, upload, fetch, collections, captions, thumbnails, re-encode, transcription, smart actions, analytics, oEmbed
90+
91+
# What next
92+
93+
First of all I want to give a huge shoutout to Wojtek Mach for setting an incredible example for the Elixir community on how to design libraries. Req is one of my favorite reference repos and I keep coming back to it and discovering new gems.
94+
95+
Secondly, I want to say that [Bunny CDN](https://bunny.net?ref=f0l8865b7g) is a great service and I appreciate having a genuinely powerful alternative to Cloudflare, provided by a European company.
96+
97+
[Check out the repo, try out the library, and let me know how you get on!](https://github.com/joladev/bunnyx)

0 commit comments

Comments
 (0)