README.md

# BridgeEx

A library to build bridges to other services (actually only graphql ones are supported).

## Usage

### A GraphQL bridge

Define a behaviour with the queries/mutations you're going to need for the bridge:

```elixir
defmodule MyApp.SomeService do
  @moduledoc """
  Bridge definition for SomeService
  """

  @callback my_cool_query(any()) :: {:ok, map()} | {:error, any()}
end
```

Implement the behaviour:

```elixir
defmodule MyApp.SomeServiceBridge do
  @moduledoc """
  Bridge implementation for SomeService behaviour.
  """

  @behaviour MyApp.SomeService

  use BridgeEx.Graphql, [
    # mandatory settings
    endpoint: "http://some_service.example.com",

    # optional settings (with defaults)
    http_headers: %{
      "User-Agent" => "microservice-myapp/myapp-version",
      "Content-type" => "application/json",
      "X-Client-Id" => "myapp",
      "X-Client-Secret" => "myapp_secret"
    },
    http_options: [timeout: 1_000, recv_timeout: 16_000],
    max_attempts: 1,
    encode_variables: false,
    format_response: true, # formats keys from CamelCase to snake_case
    log_options: [log_query_on_error: true, log_response_on_error: false]
  ]

  def my_cool_query(%{} = variables) do
    call("a graphql query or mutation", variables)

    # or, if you need more granularity (ex: different endpoint or options):

    # BridgeEx.Graphql.Client.call(
    #   "https://another-url.com/graphql",
    #   "graphql query or mutation",
    #   variables,
    #   encode_variables: false,
    #   [timeout: 1_000, recv_timeout: 16_000],
    #   %{
    #     "Some-Header" => "some-value",
    #   },
    #   1
    # )

  end
end
```

You can now use your bridge module:

```elixir
MyApp.SomeServiceBridge.my_cool_query(%{var: 1})
```

As a good practice, if you want to mock your bridge for testing, you _should_ implement another module:

```elixir
defmodule MyApp.SomeServiceBridgeMock do
  @behaviour MyApp.SomeService

  alias BridgeEx.Graphql.Utils


  def my_cool_query(%{} = variables) do
    File.read!("some_mock_file.json")
    |> Json.decode!(keys: :atoms)
    |> Utils.parse_response() # required to parse data
    # |> BridgeEx.Graphql.Client.format_response() # optional, if you want to format response
  end
end
```

You can now set the right module in your `config/*` directory:

```elixir
config :my_app, :some_service_bridge, MyApp.SomeServiceBridge

# or

config :my_app, :some_service_bridge, MyApp.SomeServiceBridgeMock
```

And use it in your app from configuration:

```elixir
@some_service Application.compile_env!(:my_app, :some_service_bridge)

# ...

@some_service.my_cool_query(%{var: 2})
```

See [example](example) directory for an implementation, it also works in `dev` and `test` environments.

### Authenticating calls via Auth0

`bridge_ex` supports authentication of machine-to-machine calls via Auth0, through the [prima_auth0_ex](https://github.com/primait/auth0_ex) library.

To use this feature, simply configure your bridge with the audience of the target service:

```elixir
  use BridgeEx.Graphql, [endpoint: "...", auth0: [enabled: true, audience: "target_audience"]]
```

For this feature to work, your `config.exs` must be updated with the configuration for the `prima_auth0_ex` library.
You can refer to [the library's README](https://github.com/primait/auth0_ex/blob/master/README.md#configuration) for more information on the supported configuration.

## Development

`mix deps.get && mix test`

## Installation

The package can be installed by adding `bridge_ex` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:bridge_ex, "~> 0.4.0"}
  ]
end
```

## Copyright and License

Copyright (c) 2020 Prima.it

This work is free. You can redistribute it and/or modify it under the
terms of the MIT License. See the [LICENSE.md](./LICENSE.md) file for more details.