packages feed

avro-0.4.1.1: README.md

# Native Haskell implementation of Avro

This is a Haskell [Avro](https://avro.apache.org/) library useful for decoding
and encoding Avro data structures.  Avro can be thought of as a serialization
format and RPC specification which induces three separable tasks:

* *Serialization*/*Deserialization* - This library has been used "in anger" for:
  - Deserialization of avro container files
  - Serialization/deserialization Avro messages to/from Kafka topics
* *RPC* - There is currently no support for Avro RPC in this library.

This library also provides functionality for automatically generating Avro-related data types and instances from Avro schemas (using TemplateHaskell).

# Quickstart

This library provides the following conversions between Haskell types and Avro types:

| Haskell type      | Avro type                       |
|:------------------|:--------------------------------|
| ()                | "null"                          |
| Bool              | "boolean"                       |
| Int, Int64        | "long"                          |
| Int32             | "int"                           |
| Double            | "double"                        |
| Text              | "string"                        |
| ByteString        | "bytes"                         |
| Maybe a           | ["null", "a"]                   |
| Either a b        | ["a", "b"]                      |
| Map Text a        | {"type": "map", "value": "a"}   |
| Map String a      | {"type": "map", "value": "a"}   |
| HashMap Text a    | {"type": "map", "value": "a"}   |
| HashMap String a  | {"type": "map", "value": "a"}   |
| [a]               | {"type": "array", "value": "a"} |

User defined data types should provide `HasAvroSchema`/`ToAvro`/`FromAvro` instances to be encoded/decoded to/from Avro.

## Defining types and `HasAvroSchema` / `FromAvro` / `ToAvro` manually

Typically these imports are useful:
```
import           Data.Avro
import           Data.Avro.Schema as S
import qualified Data.Avro.Types  as AT
```

Assuming there is a data type to be encoded/decoded from/to Avro:
```
data Gender = Male | Female deriving (Eq, Ord, Show, Enum)
data Person = Person
     { fullName :: Text
     , age      :: Int32
     , gender   :: Gender
     , ssn      :: Maybe Text
     } deriving (Show, Eq)
```

Avro schema for this type can be defined as:
```
genderSchema :: Schema
genderSchema = mkEnum "Gender" [] Nothing Nothing ["Male", "Female"]

personSchema :: Schema
personSchema =
  Record "Person" Nothing [] Nothing Nothing
    [ fld "name"   String       Nothing
    , fld "age"    Int          Nothing
    , fld "gender" genderSchema Nothing
    , fld "ssn" (mkUnion $ Null :| [String]) Nothing
    ]
    where
     fld nm ty def = Field nm [] Nothing Nothing ty def

instance HasAvroSchema Person where
  schema = pure personSchema
```

`ToAvro` instance for `Person` can be defined as:
```
instance ToAvro Person where
  schema = pure personSchema
  toAvro p = record personSchema
             [ "name"   .= fullName p
             , "age"    .= age p
             , "gender" .= gender p
             , "ssn"    .= ssn p
             ]
```

`FromAvro` instance for `Person` can be defined as:
```
instance FromAvro Person where
  fromAvro (AT.Record _ r) =
    Person <$> r .: "name"
           <*> r .: "age"
           <*> r .: "gender"
           <*> r .: "ssn"
  fromAvro r = badValue r "Person"
```

## Defining types and `HasAvroSchema` / `FromAvro` / `ToAvro` "automatically"
This library provides functionality to derive Haskell data types and `HasAvroSchema`/`FromAvro`/`ToAvro` instances "automatically" from already existing Avro schemas (using TemplateHaskell).

### Examples

`deriveAvro` will derive data types, `FromAvro` and `ToAvro` instances from a provided Avro schema file:
```
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric   #-}
import Data.Avro.Deriving

deriveAvro "schemas/contract.avsc"
```

Similarly, `deriveFromAvro` can be used to only derive data types and `FromAvro`, but not `ToAvro` instances.

If you prefer defining Avro schema in Haskell and not in `avsc`, then `deriveAvro'` can be used instead of `deriveAvro`.

### Conventions
When Haskell data types are generated, these conventions are followed:

- Type and field names are "sanitized":
all the charachers except `[a-z,A-Z,',_]` are removed from names
- Field names are prefixed with the name of the record they are declared in.

For example, if Avro schema defines `Person` record as:
```
{ "type": "record",
  "name": "Person",
  "fields": [
    { "name": "name", "type": "string"}
  ]
}
```

then generated Haskell type will look like:
```
data Person = Person
     { personName :: Text
     } deriving (Show, Eq)
```

### Limitations
Two-parts unions like `["null", "MyType"]` or `["MyType", "YourType"]` are supported (as Haskell's `Maybe MyType` and `Either MyType YourType`), but multi-parts unions are currently _not_ supported.
It is not due to any fundamental problems but because it has not been done yet. PRs are welcomed! :)
# TODO
Please see the [TODO](TODO)