Skip to content

Conversation

@jopedroliveira
Copy link

@jopedroliveira jopedroliveira commented Oct 7, 2025

Add Azure Blob Storage Adapter

This PR adds an Azure Blob Storage adapter to Waffle, following the same structure and conventions as the existing Local and S3 adapters. The intention is to provide native Azure support without altering current behaviour.

Summary

  • Implements all Waffle.StorageBehavior callbacks (put/3, url/3, delete/3)
  • Direct uploads to Azure Blob Storage via REST API using Shared Key authentication
  • Optional SAS-signed URLs for private containers
  • Supports public/private containers, multiple containers per definition, and custom blob headers
  • Configuration can be fully environment-driven
  • Includes documentation and test coverage

New Modules

  • lib/waffle/storage/azure.ex — main adapter module
  • lib/waffle/storage/azure/uploader.ex — upload logic
  • lib/waffle/storage/azure/sas.ex — SAS token generation
  • documentation/examples/azure.md — usage guide
  • Tests for both the adapter and SAS generator

Updated Files

  • Waffle.Definition.Storage — added Azure-related lookups
  • mix.exs — optional dependencies (req, timex)
  • README.md — new Azure configuration section

Configuration

config :waffle,
  storage: Waffle.Storage.Azure,
  storage_account: {:system, "AZURE_STORAGE_ACCOUNT"},
  container: {:system, "AZURE_STORAGE_CONTAINER"},
  access_key: {:system, "AZURE_ACCESS_KEY"},
  public_access: false,
  expiry_in_minutes: 60

Usage example

defmodule MyApp.Avatar do
  use Waffle.Definition

  def storage_dir(_version, {_, user}) do
    "uploads/users/#{user.id}"
  end

  def azure_blob_headers(_, {file, _}) do
    [content_type: MIME.from_path(file.file_name)]
  end
end

Store

MyApp.Avatar.store({upload, user})

Signed URL

MyApp.Avatar.url({file, user}, signed: true)

Delete

MyApp.Avatar.delete({file, user})

Tests

The PR includes test coverage for:

  • Adapter behaviour
  • SAS token generation
  • Configuration parsing
  • Error conditions (missing credentials, unexpected responses, etc.)

Compatibility

  • No breaking changes
  • Existing adapters remain untouched
  • Optional dependencies do not affect users who don’t use Azure

How to Test

export AZURE_STORAGE_ACCOUNT="..."
export AZURE_STORAGE_CONTAINER="..."
export AZURE_ACCESS_KEY="..."

mix test --include azure:true

- Add Waffle.Storage.Azure implementing Waffle.StorageBehavior
- Add Azure uploader with Shared Key authentication
- Add SAS token generation for secure access
- Add comprehensive documentation and examples
- Add unit tests for Azure storage functionality
- Update README with Azure configuration
- Add Azure-specific configuration to storage definition
- Add optional dependencies: req and timex

Features:
- Public and private access modes
- SAS token generation for secure URLs
- Custom Azure blob headers support
- Multiple container support per definition
- Environment variable configuration
- Proper error handling and logging
- Fix pattern matching for Req.put/delete responses
- Update tests to use public SAS functions
- Ensure successful Azure Blob Storage uploads
@jopedroliveira jopedroliveira marked this pull request as ready for review November 27, 2025 10:23
@Ali-Doggaz
Copy link

Ali-Doggaz commented Feb 5, 2026

I am not a maintainer of this project, but just wanted to say that's great, thank you!

@jopedroliveira
Copy link
Author

@Ali-Doggaz I created a fork with this in case you need to use that! 💪

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants