One document matched: draft-snell-merge-patch-07.xml


<?xml version="1.0"?> 
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
  <!ENTITY rfc5789 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.5789.xml'>  
  <!ENTITY rfc2119 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml'>
  <!ENTITY rfc4627 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4627.xml'>
]>
<?rfc toc="yes"?> 
<?rfc strict="yes"?> 
<?rfc symrefs="yes" ?> 
<?rfc sortrefs="yes"?> 
<?rfc compact="yes"?> 
<rfc category="info" ipr="trust200811" docName="draft-snell-merge-patch-07"> 
  <front> 
    <title abbrev="application/merge-patch"> 
      The application/json-merge-patch Media Type
    </title> 
 
    <author initials="J.M." surname="Snell" fullname="James M Snell"> 
      <address> 
        <email>jasnell@gmail.com</email> 
      </address> 
    </author> 
    
    <date month="November" year="2012" /> 
 
    <area>Applications</area> 
    <!-- workgroup>Individual Submission</workgroup--> 
    <keyword>I-D</keyword> 
    <keyword>http</keyword>
    <keyword>json</keyword> 
    <keyword>patch</keyword> 
    <keyword>merge</keyword>
 
    <abstract> 
      <t>This specification defines the application/json-merge-patch media 
      type and it's intended use with the HTTP PATCH method defined 
      by RFC 5789.</t> 
    </abstract> 
 
  </front> 
  
  <middle> 
    <section anchor="intro" title="Introduction"> 
 
      <t>This specification defines the JSON "Merge Patch" document 
      format, processing rules, and associated MIME media type identifier.
      The Merge Patch format is primarily intended for use with the 
      HTTP PATCH method <xref target="RFC5789"/> as a means of describing
      a set of modifications to a subset of target resource's content.</t>
      
      <t>For example, given the following original JSON document:</t>
      
      <figure><artwork>
  {
    "a": "b",
    "c": {
      "d": "e"
    }
  }
      </artwork></figure>
      
      <t>A change to the value of the "a" member can be described simply as:</t>
      
      <figure><artwork>
  PATCH /target HTTP/1.1
  Host: example.org
  Content-Type: application/json-merge-patch
  
  {"a": "z"}
      </artwork></figure>
      
      <t>When applied to the target resource, only the value of the "a" member 
      will be modified, leaving the remaining content untouched.</t>
      
      <t>The Merge Patch format generally supports two types of changes: removing 
      and setting JSON object members. JSON arrays are treated the same as 
      JSON primitives: the whole value can be replaced, but not partially modified. 
      The JSON null value is given a special meaning to indicate the removal of an
      existing value. These constraints allow Merge Patch to use a format that closely 
      mimics the document being modified. The constraints mean Merge Patch is suitable 
      for patching JSON documents that primarily use objects for their structure, 
      and do not make use of explicit null values. The Merge Patch format is not 
      appropriate for all JSON syntaxes.</t>
 
      <t>In this document, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", 
      "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" 
      are to be  interpreted as described in <xref target="RFC2119" />.</t> 
 
    </section> 
        
    <section title="The "application/json-merge-patch" Media Type" anchor="json-merge-patch">
    
      <t>The "application/json-merge-patch" Media Type is used to identify 
      JSON documents that describe, by example, a set of changes that 
      are to be made to a target resource. When used within an HTTP 
      PATCH request, it is the responsibility of the server receiving
      and processing the request to inspect the payload entity and 
      determine the specific set of operations that are to be performed
      to modify the target resource.</t>
      
      <figure><preamble>For example, given the following example JSON document:</preamble>
      <artwork>
  {
    "title": "Goodbye!",
    "author" : {
      "givenName" : "John",
      "familyName" : "Doe"
    },
    "tags":["example","sample"],
    "content": "This will be unchanged"
  }
      </artwork></figure>
      
      <t>If the intent is to change the value of the "title" member to 
      from "Goodbye!" to the value "Hello!", add a new "phoneNumber" 
      member, remove the "familyName" member from the "author" object,
      and remove the word sample from the "tags" Array, the user-agent would
      send the following request:</t>
      
      <figure><artwork>
  PATCH /my/resource HTTP/1.1
  Host: example.org
  Content-Type: application/json-merge-patch; charset="UTF-8"
  
  {
    "title": "Hello!",
    "phoneNumber": "+01-123-456-7890",
    "author": {
      "familyName": null
    },
    "tags": ["example"]
  }
      </artwork></figure>
      
      <t>Upon receiving the request, the server is responsible for inspecting
      the payload and determining, based on it's own understanding of the 
      target resource media type and the underlying data model of the target 
      resource, what specific operations will be applied to modify the resource.</t>
                 
      <t>A server receiving this patch request MUST apply the following rules
      to determine the specific set of change operations to be performed:
        <list style="numbers">
        <t>If either the root of the JSON data provided in the payload or 
        the root of the target resource are JSON Arrays, the target resource 
        is to be replaced, in whole, by the provided data. Any object 
        member contained in the provided data whose value is explicitly 
        null is to be treated as if the member was undefined.</t>
        <t>If the root of the JSON data provided in the payload is an 
        Object, for each distinct member specified within that object:
          <list style="symbols">
            <t>If the member is currently undefined within the target resource,
            and the given value is not null, the member and the value are to be 
            added to the target.</t>
            <t>If the value is explicitly set to null and that member is currently 
            defined within the target resource, the existing member is removed.</t>
            <t>If the value is either a non-null JSON primitive or an Array and
            that member is currently defined within the target resource, the
            existing value for that member is to be replaced with that provided.</t>
            <t>If the value is a JSON object and that member is currently 
            defined for the target resource and the existing value is a 
            JSON primitive or Array, the existing value is to be replaced
            in whole by the object provided.  Any object 
            member contained in the provided data whose value is explicitly 
            null is to be treated as if the member was undefined.</t>
            <t>If the value is a JSON object and that member is currently
            defined within the target resource and the existing value is also
            a JSON object, then recursively apply Rule #2 to each object.</t>
            <t>Any member currently defined within the target resource that 
            does not explicitly appear within the patch is to remain untouched
            and unmodified.</t>
          </list>
        </t>
        </list>
      </t>
      
      <t>Applying these rules to the previous example, the set of specific 
      change operations derived from the request are:
        <list style="symbols">
          <t>Change the existing value of the "title" member from "Goodbye!"
          to "Hello!",</t>
          <t>Add the "phoneNumber" member with a value of "+01-123-456-7890",</t>
          <t>Remove the "familyName" member from the current object value 
          associated with the "author" member, and </t>
          <t>Change the existing value of the "tags" member from 
          ["example","sample"] to ["example"].</t>
        </list>
      </t>
      
      <figure><preamble>The resulting JSON document would be similar to the following 
      (the specific ordering of members within JSON documents is insigificant):</preamble>
          <artwork>
      {
        "title": "Hello!",
        "author" : {
          "givenName" : "John"
        },
        "tags":["example"],
        "content": "This will be unchanged",
        "phoneNumber": "+01-123-456-7890"
      }
      </artwork></figure>
      
      <t>Once the set of intended modifications is derived from the 
      request, the server is free to determine the appropriateness of the 
      modification based on it's own understanding of the target resource.
      For instance, in the previous example, it is possible that the 
      "familyName" member might be required within the target resource and cannot
      be removed. Note that in such cases, per <xref target="RFC5789"/>, Section 2, 
      the server is REQUIRED to reject the entire PATCH request using an HTTP error 
      response code appropriate to the error condition.</t>
      
      <t>If the request attempts to remove a member from the target resource
      that does not currently exist, the server SHOULD NOT consider the 
      request to be in error. The requested removal operation is simply to
      be ignored by the server as the final modified state of the target 
      resource will still accurately reflect the user-agent's original 
      intent.</t>
    
    </section>
             
    <section title="IANA Considerations"> 
      <t>This specification registers the following additional 
      MIME Media Types:</t>

      <t><list>
      <t>Type name: application</t>
      <t>Subtype name: json-merge-patch</t>
      <t>Required parameters: None</t>
      <t>Optional parameters: "charset" : Specifies the character set encoding.
      If not specified, a default of "UTF-8" is assumed.</t>
      <t>Encoding considerations: Resources that use the "application/json-merge-patch"
      media type are required to conform to the "application/json" Media Type
      and are therefore subject to the same encoding considerations
      specified in <xref target="RFC4627">Section 6</xref>.</t>
      <t>Security considerations: As defined in this specification</t>
      <t>Published specification: This specification.</t>
      <t>Applications that use this media type: None currently known.</t>
      <t>Additional information:
      <list>
      <t>Magic number(s): N/A</t>
      <t>File extension(s): N/A</t>
      <t>Macintosh file type code(s): TEXT</t>
      </list></t>
      <t>Person & email address to contact for further information: James M Snell <jasnell@gmail.com></t>
      <t>Intended usage: COMMON</t>
      <t>Restrictions on usage: None.</t>
      <t>Author: James M Snell <jasnell@gmail.com></t>
      <t>Change controller: IESG</t>
      </list></t>
      
    </section> 
      
    <section title="Security Considerations"> 
      <t>The "application/json-merge-patch" Media Type allows user agents to 
      indicate their intention that the server determine the specific set of 
      change operations to be applied to a target resource. As such, 
      it is the server's responsibility to determine the appropriateness 
      of any given change as well as the user agent's authorization to 
      request such changes. How such determinations are made is considered
      out of the scope of this specification.</t>
      
      <t>All of the the security considerations discussed in 
      <xref target="RFC5789">Section 5</xref> apply to all uses of the 
      HTTP PATCH method with the "application/json-merge-patch" Media Type.</t>     
    </section>
     
  </middle> 
  <back>
    <references title="Normative References"> 
      &rfc2119;
      &rfc5789;
      &rfc4627;
    </references>
    
    <section title="Example JavaScript Implementation">
      
      <t>The following example implementation is provided as is, without warranty. 
      It is provided in the public domain.</t>
      
      <figure><artwork><![CDATA[
  // Apply the patch to the original, return the 
  // modified object... this will mutate the 
  // passed in object in place as well...
  function apply(orig, patch) {
    if (patch == null) 
      return orig;
    else if (patch instanceof Array)
      orig = purge_nulls(patch);
    else if (is_primitive(patch))
      orig = patch;
    else if (patch instanceof Object) {
      for (m in patch) {
        if (orig.hasOwnProperty(m)) {
          if (patch[m] == null)
            delete orig[m];
          else {
            if (is_primitive(patch[m])) 
              orig[m] = patch[m];
            else {
              if (orig[m] instanceof Array)
                orig[m] = purge_nulls(patch[m]);
              else 
                orig[m] = apply(orig[m],patch[m]);
            }
          }
        } else if (patch[m] != null)
          orig[m] = purge_nulls(patch[m]);
      }
    }
    return orig;
  }


  function is_primitive(val) {
    var m = typeof val;
    return m == 'string'  || 
           m == 'number'  ||
           m == 'boolean';
  }

  function purge_nulls(obj) {
    for (m in obj) {
      if (obj[m] == null) {
        if (obj instanceof Array)
          obj.splice(m,1);
        else
          delete(obj[m]);
      } else if (obj[m] instanceof Object)
        purge_nulls(obj[m]);
    }  
    return obj;
  }

  // Define the original object...
  var orig = {
    "a": "b",
    "c": {
      "d": [1,2,3],
      "e": {
        "f": 1
      }
    }
  }

  // Define the patch...
  var patch = {
    "c": {
      "d": [1,2],
      "e": {
        "f": null
      }
    }
  }

  // Apply the patch...
  var modified = apply(orig,patch);
      ]]></artwork></figure>
      
    </section>
    
  </back>  
</rfc> 
 

PAFTECH AB 2003-20262026-04-24 05:23:12