# Serializers

You can tell Betamax how you would like it to serialize the cassettes when saving them to a file. By default Betamax will serialize your cassettes to JSON. The only default serializer is the JSON serializer, but writing your own is very easy.

## Creating Your Own Serializer

Betamax handles the structuring of the cassette and writing to a file, your serializer simply takes a dictionary and returns a string.

Every Serializer has to inherit from `betamax.BaseSerializer` and implement three methods:

- `betamax.BaseSerializer.generate_cassette_name` which is a static method. This will take the directory the user (you) wants to store the cassettes in and the name of the cassette and generate the file name.

- `betamax.BaseSerializer.serialize()` is a method that takes the dictionary and returns the dictionary serialized as a string

- `betamax.BaseSerializer.deserialize()` is a method that takes a string and returns the data serialized in it as a dictionary.

Added in version 0.9.0: Allow Serializers to indicate their format is a binary format via `stored_as_binary`.

Additionally, if your Serializer is utilizing a binary format, you will want to set the `stored_as_binary` attribute to `True` on your class.

class betamax.BaseSerializer

  Base Serializer class that provides an interface for other serializers.

  Usage:

      from betamax import Betamax, BaseSerializer

      class MySerializer(BaseSerializer):
          name = 'my'

          @staticmethod
          def generate_cassette_name(cassette_library_dir, cassette_name):
              # Generate a string that will give the relative path of a
              # cassette

          def serialize(self, cassette_data):
              # Take a dictionary and convert it to whatever

          def deserialize(self, cassette_data):
              # Uses a cassette file to return a dictionary with the
              # cassette information

      Betamax.register_serializer(MySerializer)

  The last line is absolutely necessary.

  deserialize(cassette_data)

    A method that must be implemented by the Serializer author.

    The return value is extremely important. If it is not empty, the dictionary returned must have the following structure:

        {
            'http_interactions': [{
                # Interaction
            },
            {
                # Interaction
            }],
            'recorded_with': 'name of recorder'
        }

    Params str cassette_data:

      The data serialized as a string which needs to be deserialized.

    Returns:

      dictionary

  on_init()

    Method to implement if you wish something to happen in `__init__`.

    The return value is not checked and this is called at the end of `__init__`. It is meant to provide the matcher author a way to perform things during initialization of the instance that would otherwise require them to override `BaseSerializer.__init__`.

  serialize(cassette_data)

    A method that must be implemented by the Serializer author.

    Parameters:

      cassette_data (dict) – A dictionary with two keys: `http_interactions`, `recorded_with`.

    Returns:

      Serialized data as a string.

Here’s the default (JSON) serializer as an example:

    from .base import BaseSerializer

    import json
    import os

    class JSONSerializer(BaseSerializer):
        # Serializes and deserializes a cassette to JSON
        name = 'json'
        stored_as_binary = False

        @staticmethod
        def generate_cassette_name(cassette_library_dir, cassette_name):
            return os.path.join(cassette_library_dir,
                                '{0}.{1}'.format(cassette_name, 'json'))

        def serialize(self, cassette_data):
            return json.dumps(cassette_data)

        def deserialize(self, cassette_data):
            try:
                deserialized_data = json.loads(cassette_data)
            except ValueError:
                deserialized_data = {}

            return deserialized_data

This is incredibly simple. We take advantage of the `os.path` to properly join the directory name and the file name. Betamax uses this method to find an existing cassette or create a new one.

Next we have the `betamax.serializers.JSONSerializer.serialize()` which takes the cassette dictionary and turns it into a string for us. Here we are just leveraging the `json` module and its ability to dump any valid dictionary to a string.

Finally, there is the `betamax.serializers.JSONSerializer.deserialize()` method which takes a string and turns it into the dictionary that betamax needs to function.