# `Waffle.Storage.Azure`
[🔗](https://github.com/phil-a/waffle_azure/blob/v0.2.0/lib/waffle/storage/azure.ex#L1)

A [Waffle](https://hexdocs.pm/waffle) storage adapter for Azure Blob Storage.

    config :waffle,
      storage: Waffle.Storage.Azure,
      bucket: "uploads"

    config :waffle_azure,
      account: System.get_env("AZURE_ACCOUNT"),
      access_key: System.get_env("AZURE_ACCESS_KEY")

`:account` and `:access_key` fall back to the `AZURE_ACCOUNT` and
`AZURE_ACCESS_KEY` environment variables when they are not configured.

## Containers

Waffle's `:bucket` is the name of the Azure container, which must already
exist. As with other Waffle storage adapters, it can be read from the
environment with `{:system, "VAR"}`, or set per uploader by overriding
`bucket/0` or `bucket/1` in the definition module.

## URLs

By default, URLs have the form
`https://<account>.blob.core.windows.net/<container>/<path>`. Reading from
such a URL needs a container with anonymous read access enabled.

For a private container, generate a read-only shared access signature with
`signed: true`. It expires after 5 minutes unless `:expires_in` (in seconds)
says otherwise:

    Avatar.url({"selfie.png", user}, :thumb, signed: true, expires_in: 3600)

To serve files from a CDN, set Waffle's `:asset_host`. It replaces both the
account endpoint and the container, so it should map to the container's root.
Signed URLs ignore it, because they are always served by the storage account.

    config :waffle,
      asset_host: "https://cdn.example.com"

## Blob properties

Blob properties are set through `s3_object_headers/2`, the hook Waffle provides
for object headers. It returns a keyword list or map, and supports these keys:

  * `:cache_control`
  * `:content_disposition`
  * `:content_encoding`
  * `:content_language`
  * `:content_md5`
  * `:content_type`

Lowercase string keys starting with `x-ms-`, such as `"x-ms-access-tier"` or
`"x-ms-meta-owner"`, are sent as they are. Any other key is ignored, so that a
definition can be shared with other storage adapters.

Azure stores blobs as `application/octet-stream` unless told otherwise, so
browsers will download rather than display them without a content type:

    def s3_object_headers(_version, {file, _scope}) do
      [content_type: MIME.from_path(file.file_name)]
    end

## Other options

  * `:endpoint` - the Blob service URL, for sovereign clouds or the
    [Azurite](https://github.com/Azure/Azurite) emulator
  * `:request_options` - options merged into `Req.new/1`, such as
    `:receive_timeout`

Files larger than 4 MiB and streams are uploaded in blocks of at least 4 MiB.
Waffle gives each version 15 seconds to upload by default, so raise its
`:version_timeout` if you expect to store large files.

# `delete`

Deletes a file from the container.

The file may be given by name, or by the full URL returned by `url/4`. Always
returns `:ok`, as Waffle ignores the result. Failures are logged instead.

# `put`

Uploads a file to the container.

Returns `{:ok, file_name}`, or `{:error, reason}` where `reason` is the
`Req.Response` or exception that made the upload fail.

# `url`

Builds the URL of an uploaded file.

Pass `signed: true` for a read-only URL that also works on a private container,
and `:expires_in` to set how many seconds it stays valid.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
