# `StaticMaps.Source`
[🔗](https://gitlab.com/tristanperalta/staticmaps/blob/v0.1.0/lib/static_maps/source.ex#L1)

A source of map tiles.

A source turns a tile into image bytes with `c:fetch/2` and describes its tiles with
`c:info/1`. Both receive the options given alongside the module, as in
`source: {MyApp.Tiles, api_key: "…"}`, or `[]` when the source is a bare module.

## `c:info/1`

  * `:attribution` — the credit the tiles' licence requires, drawn on every image
  * `:tile_size` — 256 or 512, the pixel size of a tile at scale 1
  * `:zoom` — the range of tile zooms the source serves
  * `:scales` — the pixel densities it has tiles for; always includes 1
  * `:max_concurrency` — optional; how many fetches from this source may run at once
    across every render in the node, default 8
  * `:cache` — optional; `false` keeps this source's tiles out of the
    `StaticMaps.TileCache` entirely, including as stale copies when the server fails.
    Defaults to `true`. Several commercial providers forbid server-side caching.

`:zoom` is in the source's own terms. A 512-pixel source's tile zoom `z` serves render
zoom `z + 1`, so its render zooms are its range shifted up by one.

# `cache_meta`

```elixir
@type cache_meta() :: %{
  max_age: non_neg_integer() | :no_store | nil,
  etag: String.t() | nil,
  last_modified: String.t() | nil
}
```

How long a response may be cached: `:max_age` in seconds, `:no_store`, or `nil` when
the response does not say, and the validators to revalidate it with once it expires.

With `nil`, a new tile is kept for 7 days, and a `304` keeps the lifetime of the tile
it renews.

# `info`

```elixir
@type info() :: %{
  :attribution =&gt; String.t(),
  :tile_size =&gt; 256 | 512,
  :zoom =&gt; Range.t(),
  :scales =&gt; [1 | 2],
  optional(:max_concurrency) =&gt; pos_integer(),
  optional(:cache) =&gt; boolean()
}
```

# `tile`

```elixir
@type tile() :: %{
  z: non_neg_integer(),
  x: non_neg_integer(),
  y: non_neg_integer(),
  scale: 1 | 2
}
```

The tile to fetch. `:scale` is 2 only for a source that lists it in `:scales`.

# `validators`

```elixir
@type validators() :: %{etag: String.t() | nil, last_modified: String.t() | nil}
```

Validators from an earlier response, for a conditional request.

# `fetch`

```elixir
@callback fetch(tile(), opts :: keyword()) :: {:ok, binary()} | {:error, term()}
```

Returns the encoded image for `tile`, `tile_size * scale` pixels on a side.

# `fetch_cacheable`
*optional* 

```elixir
@callback fetch_cacheable(tile(), opts :: keyword(), validators()) ::
  {:ok, binary(), cache_meta()}
  | {:not_modified, cache_meta()}
  | {:error, term()}
```

Fetches `tile` conditionally, saying how long the result may be cached.

Optional. A source that implements it has its tiles kept in the `StaticMaps.TileCache`;
every `StaticMaps.Source.HTTP` source does. `validators` come from the cached copy, if
there is one; `{:not_modified, meta}` means that copy is still good.

# `info`

```elixir
@callback info(opts :: keyword()) :: info()
```

Describes the source's tiles.

---

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