Jsonpatch

Elixir CI Coverage Status Generic badge Maintenance Hex.pm Version

A implementation of RFC 6902 in pure Elixir.

Features:

  1. Creating a patch by comparing to maps and structs
  2. Apply patches to maps and structs - supports operations:
    • add
    • replace
    • remove
    • copy
    • move
    • test
  3. De/Encoding and mapping
  4. Escaping of "/" (by "~1") and "~" (by "~0")
  5. Allow usage of - for appending things to list (Add and Copy operation)

Getting started

Installation

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

def deps do
  [
    {:jsonpatch, "~> 0.12.1"}
  ]
end

The docs can be found at https://hexdocs.pm/jsonpatch.

Create a diff

iex> source = %{"name" => "Bob", "married" => false, "hobbies" => ["Sport", "Elixir", "Football"]}
iex> destination = %{"name" => "Bob", "married" => true, "hobbies" => ["Elixir!"], "age" => 33}
iex> Jsonpatch.diff(source, destination)
{:ok, [
  %Jsonpatch.Operation.Add{path: "/age", value: 33},
  %Jsonpatch.Operation.Replace{path: "/hobbies/0", value: "Elixir!"},
  %Jsonpatch.Operation.Replace{path: "/married", value: true},
  %Jsonpatch.Operation.Remove{path: "/hobbies/1"},
  %Jsonpatch.Operation.Remove{path: "/hobbies/2"}
]}

Mapping for de- and encoding

Map a JSON patch struct to a regular map.

iex> add_patch_map = %Jsonpatch.Operation.Add{path: "/name", value: "Alice"}
iex> Jsonpatch.Mapper.to_map(add_patch_map)
%{op: "add", path: "/name", value: "Alice"}

Map a regular map to a JSON patch struct.

iex> add_patch_map = %{"op" => "add", "path" => "/name", "value" => "Alice"}
iex> Jsonpatch.Mapper.from_map(add_patch_map)
%Jsonpatch.Operation.Add{path: "/name", value: "Alice"}

Apply patches

iex> patch = [
  %Jsonpatch.Operation.Add{path: "/age", value: 33},
  %Jsonpatch.Operation.Replace{path: "/hobbies/0", value: "Elixir!"},
  %Jsonpatch.Operation.Replace{path: "/married", value: true},
  %Jsonpatch.Operation.Remove{path: "/hobbies/1"},
  %Jsonpatch.Operation.Remove{path: "/hobbies/2"}
]
iex> target = %{"name" => "Bob", "married" => false, "hobbies" => ["Sport", "Elixir", "Football"]}
iex> Jsonpatch.apply_patch(patch, target)
{:ok, %{"name" => "Bob", "married" => true, "hobbies" => ["Elixir!"], "age" => 33}}

In an exs script

With Mix.install small scripts can be written to create JSON patches.

Mix.install([:jsonpatch, :poison])

source =
  File.read!("foo.json")
  |> Poison.Parser.parse!(%{})

destination =
  File.read!("bar.json")
  |> Poison.Parser.parse!(%{})

patch =
  source
  |> Jsonpatch.diff(destination)
  |> Jsonpatch.Mapper.to_map()

IO.inspect(patch, label: :patch)

Important sources