#+TITLE: do-spaces

* About
  ~do-spaces~ is a Haskell library providing complete bindings to DigitalOcean's Spaces API, an Amazon s3-compatible object storage service. It offers bindings for:
   - object CRUD
   - bucket CRUD
   - bucket and object ACLs
   - bucket lifecycles
   - bucket CORS configuration

* Usage
~Network.DO.Spaces~ exposes the types and actions requires to make transactions through the Spaces API. The first step is to configure a client:
#+begin_src haskell
someTransaction = do
    mySpaces <- newSpaces $ FromFile "~/.spaces-secrets" Nothing
    runSpaces mySpaces $ ...
#+end_src
There are a few options for supplying your credentials and region. See ~newSpaces~ in ~Network.DO.Spaces~ for more details.

~Network.DO.Spaces~ exposes several convenience actions for common transactions. These are simple wrappers around instances of the ~Action~ typeclass. Each of the actions must be run via ~runSpaces~ with a ~Spaces~ client configuration. If more granular control is required, especially in the case of actions which take several optional parameters (e.g., ~ListBucket~), you can directly import the ~Action~ instance, construct it, and run it with ~runAction~. These are available from the ~Network.DO.Spaces.Actions~ module.

Each action returns a ~SpacesResponse~ record with two fields. The optional ~metadata~ field contains information about the response. The data returned from the transaction can be accessed through the polymorphic ~result~ field. Retention of metadata and response information can be configured in ~runAction~, but all of the convenience actions exported from ~Network.DO.Spaces~ keep metadata.

A small example:

#+begin_src haskell
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE TypeApplications #-}

import Control.Monad.IO.Class
import Data.Sequence            ( Seq )
import Data.Generics.Labels     ()
import Lens.Micro -- or whatever compatible lens library you fancy
import Network.DO.Spaces

myObjects :: MonadIO m => m (Seq ObjectInfo)
myObjects = do
    -- Load your region and credentials by first trying to read from
    -- $XDG_CONFIG_HOME/do-spaces/credentials or ~/.aws/credentials,
    -- falling back on environment variables if neither exist
    spaces <- newSpaces Discover
    -- List the contents of your bucket. @listBucket@ will list all entries until the
    -- Spaces limit of 1,000. There are several variants of this action in
    -- "Network.DO.Spaces" with different options
    response <- runSpaces spaces $ listBucket =<< mkBucket "my-real-bucket"
    -- See the note about accessing record fields below
    pure $ response ^. #result . #objects

#+end_src

** A note about records
Many transactions available through the Spaces API feature the same parameters. This necessitates dealing with duplicate fields in records that represent these transactions. For example, nearly every ~Action~ instance has a ~bucket~ field. I have used ~DuplicateRecordFields~ throughout this library and have chosen not to export field selectors by default. Record selectors can be accessed by importing the relevant module directly, as they are not exported from ~Network.DO.Spaces~. You might want to import different types qualified, due to the aforementioned proliferation of record field duplication. My personal preference is to use the ~generic-lens~ package.

* But why?
Spaces is nominally compatible with existing Amazon S3 SDKs and clients, so it might seem redundant to create a dedicated client library for the service. DigitalOcean's endpoints and regions are different from Amazon's, however, requiring a stringly-typed region when configuring clients. True to form, Amazon client libraries written in Haskell (e.g., ~Amazonka~) tend to use an ADT to represent regions, precluding their use with Spaces. Furthermore, using an entire Amazon client might be overkill for an application that only requires the s3 functionality, unnecessarily requiring a heavyweight dependency.

* Testing
There are two test suites: a suite that tests pure functionality as well as one that runs actual IO transactions against DigitalOcean's Spaces API. *Run the latter suite at your own risk*. See ~Main.hs~ for a full disclaimer, but in short: running the full IO tests can cause irretrievable harm to the data in your Spaces account and may incur charges on your DigitalOcean account. Caveat emptor!

* License
  This library is distributed under the BSD three-clause license
