README.md

# `argo`

[![Build Status](https://github.com/WhatsApp/erlang-argo/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/WhatsApp/erlang-argo/actions) [![Hex.pm](https://img.shields.io/hexpm/v/argo_graphql.svg)](https://hex.pm/packages/argo_graphql)

`argo` is a compact binary serialization format for [GraphQL](https://spec.graphql.org/).

This library provides support for [Erlang](https://www.erlang.org/) and [Elixir](https://elixir-lang.org/) following the [Argo 1.2.0 specifications](https://msolomon.github.io/argo/versions/1.2/spec#sec-v1-2-0).

See the [CONTRIBUTING](CONTRIBUTING.md) file for how to help out.

## Installation

Add `argo_graphql` to your project's dependencies in `mix.exs`

```elixir
defp deps() do
  [
    {:argo, "~> 1.0", hex: :argo_graphql}
  ]
end
```

Add `argo_graphql` to your project's dependencies in your `Makefile` for [`erlang.mk`](https://github.com/ninenines/erlang.mk) or the following to your `rebar.config`

```erlang
{deps, [
    {argo, "~> 1.0", {pkg, argo_graphql}}
]}.
```

## Usage

Using the ["Introduction to GraphQL" example](https://graphql.org/learn/):

```erlang
% Load the GraphQL Service Document.
SD = argo_graphql_service_document:from_string("
  type Query {
    me: User
  }

  type User {
    id: ID
    name: String
  }
"),
% Load the GraphQL Executable Document.
ED = argo_graphql_executable_document:from_string("
  query MyQuery {
    me {
      name
    }
  }
"),
% Derive the Argo Wire Type based on the GraphQL Service Document
% and the GraphQL Executable Document.
{{some, <<"MyQuery">>}, ArgoWireType} = argo_typer:derive_wire_type(SD, ED, none).

% Convert a JSON response to an Argo Value.
JsonValue = #{<<"data">> => #{<<"me">> => #{<<"name">> => <<"Luke Skywalker">>}}},
ArgoValue = argo_value:from_json(ArgoWireType, JsonValue),
% Encode Argo Value using default settings.
ArgoEncoded = argo_value:to_writer(ArgoValue),
% Compare output size to the JSON encoding.
JsonEncoded = jsone:encode(JsonValue),
41 = byte_size(JsonEncoded),
22 = byte_size(ArgoEncoded),
% Argo encoding is roughly 46% smaller than JSON encoding in this case.
46 = trunc((1 - (byte_size(ArgoEncoded) / byte_size(JsonEncoded))) * 100).

% For decoding, use the Argo Wire Type and the Argo encoding bytes.
{<<>>, ArgoValue} = argo_value:from_reader(ArgoWireType, ArgoEncoded).

% Optionally convert back to JSON representation.
JsonResponse = argo_value:to_json(ArgoValue).
```

Use `argo:display/1` or `argo:display_with_lines/1` to inspect Argo Wire Types, Argo Values, and GraphQL related data structures:

```erlang
argo:display(ArgoWireType).
% {
%   data: {
%     me: {
%       name: STRING<String>?
%     }?
%   }?
%   errors?: ERROR[]
%   extensions?: EXTENSIONS
% }

argo:display(ArgoValue).
% {
%   data: NON_NULL({
%     me: NON_NULL({
%       name: NON_NULL(STRING(<<"Luke Skywalker">>)<String>)
%     })
%   })
%   errors?: ABSENT
%   extensions?: ABSENT
% }
```

## License

`argo` is MIT licensed, as found in the [LICENSE](LICENSE.md) file.