{"id":13713851,"url":"https://github.com/snorwin/jsonpatch","last_synced_at":"2025-09-07T09:12:29.093Z","repository":{"id":42694707,"uuid":"334451884","full_name":"snorwin/jsonpatch","owner":"snorwin","description":"jsonpatch is a Go library to create JSON patches (RFC6902) directly from arbitrary Go objects and facilitates the implementation of sophisticated custom (e.g. filtered, validated) patch creation.","archived":false,"fork":false,"pushed_at":"2025-04-28T12:00:24.000Z","size":139,"stargazers_count":17,"open_issues_count":5,"forks_count":9,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-02T18:56:08.011Z","etag":null,"topics":["go","jsonpatch","rfc-6901","rfc-6902"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/snorwin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-01-30T15:58:11.000Z","updated_at":"2025-04-28T12:00:21.000Z","dependencies_parsed_at":"2024-01-22T11:28:37.970Z","dependency_job_id":"657db60e-751f-4dfa-badd-0aae8ee2972e","html_url":"https://github.com/snorwin/jsonpatch","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snorwin%2Fjsonpatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snorwin%2Fjsonpatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snorwin%2Fjsonpatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snorwin%2Fjsonpatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snorwin","download_url":"https://codeload.github.com/snorwin/jsonpatch/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252792134,"owners_count":21804907,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","jsonpatch","rfc-6901","rfc-6902"],"created_at":"2024-08-02T23:01:45.980Z","updated_at":"2025-05-07T00:32:41.574Z","avatar_url":"https://github.com/snorwin.png","language":"Go","readme":"# jsonpatch\n[![GitHub Action](https://img.shields.io/badge/GitHub-Action-blue)](https://github.com/features/actions)\n[![Documentation](https://img.shields.io/badge/godoc-reference-5272B4.svg)](https://pkg.go.dev/github.com/snorwin/jsonpatch)\n[![Test](https://img.shields.io/github/actions/workflow/status/snorwin/jsonpatch/test.yaml?label=tests\u0026logo=github)](https://github.com/snorwin/sonpatch/actions)\n[![Go Report Card](https://goreportcard.com/badge/github.com/snorwin/jsonpatch)](https://goreportcard.com/report/github.com/snorwin/jsonpatch)\n[![Coverage Status](https://coveralls.io/repos/github/snorwin/jsonpatch/badge.svg?branch=main)](https://coveralls.io/github/snorwin/jsonpatch?branch=main)\n[![Releases](https://img.shields.io/github/v/release/snorwin/jsonpatch)](https://github.com/snorwin/jsonpatch/releases)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n`jsonpatch` is a Go library to create JSON patches ([RFC6902](http://tools.ietf.org/html/rfc6902)) directly from arbitrary Go objects and facilitates the implementation of sophisticated custom (e.g. filtered, validated) patch creation.\n\n## Basic Example\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/snorwin/jsonpatch\"\n)\n\ntype Person struct {\n\tName string `json:\"name\"`\n\tAge  int    `json:\"age\"`\n}\n\nfunc main() {\n\toriginal := \u0026Person{\n\t\tName: \"John Doe\",\n\t\tAge:  42,\n\t}\n\tupdated := \u0026Person{\n\t\tName: \"Jane Doe\",\n\t\tAge:  21,\n\t}\n\n\tpatch, _ := jsonpatch.CreateJSONPatch(updated, original)\n\tfmt.Println(patch.String())\n}\n```\n```json\n[{\"op\":\"replace\",\"path\":\"/name\",\"value\":\"Jane Doe\"},{\"op\":\"replace\",\"path\":\"/age\",\"value\":21}]\n```\n\n## Options\n### Filter patches using Predicates\nThe option `WithPredicate` sets a patch `Predicate` which can be used to filter or validate the patch creation.\nFor each kind of patch (`add`, `remove` and `replace`) a dedicated filter function can be configured. The \npredicate will be checked before a patch is created, or the JSON object is processed further.\n\n#### Example\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/snorwin/jsonpatch\"\n)\n\ntype Job struct {\n\tPosition  string `json:\"position\"`\n\tCompany   string `json:\"company\"`\n\tVolunteer bool   `json:\"volunteer\"`\n}\n\nfunc main() {\n\toriginal := []Job{\n\t\t{Position: \"IT Trainer\", Company: \"Powercoders\", Volunteer: true},\n\t\t{Position: \"Software Engineer\", Company: \"Github\"},\n\t}\n\tupdated := []Job{\n\t\t{Position: \"Senior IT Trainer\", Company: \"Powercoders\", Volunteer: true},\n\t\t{Position: \"Senior Software Engineer\", Company: \"Github\"},\n\t}\n\n\tpatch, _ := jsonpatch.CreateJSONPatch(updated, original, jsonpatch.WithPredicate(jsonpatch.Funcs{\n\t\tReplaceFunc: func(pointer jsonpatch.JSONPointer, value, _ interface{}) bool {\n\t\t\t// only update volunteering jobs\n\t\t\tif job, ok := value.(Job); ok {\n\t\t\t\treturn job.Volunteer\n\t\t\t}\n\t\t\treturn true\n\t\t},\n\t}))\n\tfmt.Println(patch.String())\n}\n```\n\n```json\n[{\"op\":\"replace\",\"path\":\"/0/position\",\"value\":\"Senior IT Trainer\"}]\n```\n\n\n### Create partial patches\nThe option `WithPrefix` is used to specify a JSON pointer prefix if only a sub part of JSON structure needs to be patched,\nbut the patch still need to be applied on the entire JSON object.\n\n#### Example\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/snorwin/jsonpatch\"\n)\n\ntype Person struct {\n\tName string `json:\"name\"`\n\tAge  int    `json:\"age\"`\n\tJobs []Job  `json:\"jobs\"`\n}\n\ntype Job struct {\n\tPosition  string `json:\"position\"`\n\tCompany   string `json:\"company\"`\n\tVolunteer bool   `json:\"volunteer\"`\n}\n\nfunc main() {\n\toriginal := \u0026Person{\n\t\tName: \"John Doe\",\n\t\tAge:  42,\n\t\tJobs: []Job{{Position: \"IT Trainer\", Company: \"Powercoders\"}},\n\t}\n\tupdated := []Job{\n\t\t{Position: \"Senior IT Trainer\", Company: \"Powercoders\", Volunteer: true},\n\t\t{Position: \"Software Engineer\", Company: \"Github\"},\n\t}\n\t\n\tpatch, _ := jsonpatch.CreateJSONPatch(updated, original.Jobs, jsonpatch.WithPrefix(jsonpatch.ParseJSONPointer(\"/jobs\")))\n\tfmt.Println(patch.String())\n}\n```\n```json\n[{\"op\":\"replace\",\"path\":\"/jobs/0/position\",\"value\":\"Senior IT Trainer\"},{\"op\":\"replace\",\"path\":\"/jobs/0/volunteer\",\"value\":true},{\"op\":\"add\",\"path\":\"/jobs/1\",\"value\":{\"position\":\"Software Engineer\",\"company\":\"Github\",\"volunteer\":false}}]\n```\n\n### Ignore slice order\nThere are two options to ignore the slice order:\n- `IgnoreSliceOrder` will ignore the order of all slices of built-in types (e.g. `int`, `string`) during the patch creation\n  and will instead use the value itself in order to match and compare the current and modified JSON.\n- `IgnoreSliceOrderWithPattern` allows to specify for which slices the order should be ignored using JSONPointer patterns (e.g. `/jobs`, `/jobs/*`).\n  Furthermore, the slice order of structs (and pointer of structs) slices can be ignored by specifying a JSON field which should be used \n  to match the struct values. \n\n\u003e NOTE: Ignoring the slice order only works if the elements (or the values used to match structs) are unique\n\n#### Example\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/snorwin/jsonpatch\"\n)\n\ntype Person struct {\n\tName       string   `json:\"name\"`\n\tPseudonyms []string `json:\"pseudonyms\"`\n\tJobs       []Job    `json:\"jobs\"`\n}\n\ntype Job struct {\n\tPosition  string `json:\"position\"`\n\tCompany   string `json:\"company\"`\n\tVolunteer bool   `json:\"volunteer\"`\n}\n\nfunc main() {\n\toriginal := Person{\n\t\tName:       \"John Doe\",\n\t\tPseudonyms: []string{\"Jo\", \"JayD\"},\n\t\tJobs: []Job{\n\t\t\t{Position: \"Software Engineer\", Company: \"Github\"},\n\t\t\t{Position: \"IT Trainer\", Company: \"Powercoders\"},\n\t\t},\n\t}\n\tupdated := Person{\n\t\tName:       \"John Doe\",\n\t\tPseudonyms: []string{\"Jonny\", \"Jo\"},\n\t\tJobs: []Job{\n\t\t\t{Position: \"IT Trainer\", Company: \"Powercoders\", Volunteer: true},\n\t\t\t{Position: \"Senior Software Engineer\", Company: \"Github\"},\n\t\t},\n\t}\n\n\tpatch, _ := jsonpatch.CreateJSONPatch(updated, original,\n\t\tjsonpatch.IgnoreSliceOrderWithPattern([]jsonpatch.IgnorePattern{{Pattern: \"/*\", JSONField: \"company\"}}),\n\t\tjsonpatch.IgnoreSliceOrder(),\n\t)\n\tfmt.Println(patch.String())\n}\n```\n```json\n[{\"op\":\"add\",\"path\":\"/pseudonyms/2\",\"value\":\"Jonny\"},{\"op\":\"remove\",\"path\":\"/pseudonyms/1\"},{\"op\":\"replace\",\"path\":\"/jobs/1/volunteer\",\"value\":true},{\"op\":\"replace\",\"path\":\"/jobs/0/position\",\"value\":\"Senior Software Engineer\"}]\n```","funding_links":[],"categories":["Repositories"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnorwin%2Fjsonpatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnorwin%2Fjsonpatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnorwin%2Fjsonpatch/lists"}