Save Content Using the REST API - Documentation topics on: ajax,api,binary fields,building and using forms,categories,content,contentapi,contentlet,creating forms,custom forms,files on content forms,form building,forms,jquery,json,rest,rest api forms,sample form code,uploading files,using categories in web forms,.

Save Content Using the REST API

The Content REST API allows you to search and render dotCMS content, and allows you to save and update dotCMS content via JSON, XML and Form UrlEncoded data formats.

Usage

Base URL

The base URL for saving content is http[s]://[host]:[port]/api/content.

HTML Methods (PUT/POST)

You can submit content to dotCMS using either HTML PUT or POST methods. By convention, POST is used for inserting new content and PUT is used for updating existing content; however the API calling conventions for both are identical.


Important

When updating content using the REST API, you must submit all fields (including all relationships) for a piece of content each time you update the content.

  • If you wish to update only a single field value or relationship (while maintaining all other existing field values and relationships), you must first read all existing fields and find all existing relationships so that you can include them when updating the content.
  • Any field values and relationships which are not included when you update a content item via the REST API will be removed from that content item.

Header Fields

The following Request header fields are recognized. Which headers are required and which are optional depends on the operation being performed.

Content Type Identification

The header for every content submission must include a contentType field to identify the Content Type of the content to be added or modified. The contentType field must specify the variable name of the Content Type.

Content Type Fields

The data for each field of the Content Type is defined using the Velocity variable name of each field in the Content Type as the header field name/key, and the value of the field (as a string) as the header field value.

Field Value Formats

All field values are passed in the POST or PUT header as strings. Below is a list of field types in dotCMS and the supported formats for each type:

Field TypeSupported Formats
BinaryPlease see Binary Fields, below.
CategoryA string containing a comma separated list of Category ids, Category keys, or Category variable names.
(e.g. "investing,research,wealthManagement").
Please see Categories, below.
Checkbox,
Multi-Select
A string containing a comma separated list of selected values (the strings to the right of the pipe (\
Constant Field,
Hidden Field
Should not be submitted with the content item.
(These are filled in automatically by dotCMS).
Custom FieldA string containing the field value (as formatted by your Custom Field code).
Date,
Time,
Date and Time
yyyy-MM-dd HH:mm:ss, yyyy-MM-dd HH:mm, d-MMM-yy, MMM-yy, MMMM-yy, d-MMM, dd-MMM-yyyy, MM/dd/yyyy hh:mm:ss aa, MM/dd/yyyy hh:mm aa, MM/dd/yy HH:mm:ss, MM/dd/yy HH:mm:ss, MM/dd/yy HH:mm, MM/dd/yy hh:mm:ss aa, MM/dd/yy hh:mm:ss, MM/dd/yyyy HH:mm:ss, MM/dd/yyyy HH:mm, MMMM dd, yyyy, M/d/y, M/d, EEEE, MMMM dd, yyyy, MM/dd/yyyy, hh:mm:ss aa, hh:mm aa, HH:mm:ss, HH:mm, yyyy-MM-dd.
Note: You may use formats that only include the date or time for Date and Time fields, but you may not use a format which includes both the date and time for Date fields or Time fields.
File,
Image
The path to the related file, starting with the hostname (e.g. "//demo.dotcms.com/images/photos/The-Gherkin-London-England.jpg").
Key/ValuePlease see Key/Value Pair Fields, below.
Radio,
Select
A string containing the selected value for the field (the string to the right of the pipe (\
RelationshipPlease see Relationships, below.
Site or FolderA string representing the host (e.g. "demo.dotcms.com"), a folder (for the host the user is on) (e.g. "/images/photos"), or a combination of host and folder (e.g. "demo.dotcms.com:/images/photos/".
TagA comma separated list of tag values (e.g. "investment,banking,europe").
TextA string containing the field value.
TextareaA string containing the field value.
Non-printing characters should be escaped using HTML escape codes (e.g. %0D%0A for carriage-return line-feed).
WYSIWYGA string containing the field value, containing HTML formatting.
Non-printing characters should be escaped using HTML escape codes (e.g. %0D%0A for carriage-return line-feed).

Files / Multipart Form Data

Sending multipart/form-data is supported, and is required in order to send file content for Binary fields.

Language ID

You may specify the language version of the content item you wish to add or update by setting the languageId field in the header, with the value equal to the id number of the language for the content item (e.g. 1 for the default language, 2 for the first added language, 3 for the next configured language, etc.). If the language_id field is not set, the default language will be used.

Content Type Header

The format of the content should be specified in the Content-Type header. Supported Content-Types include:

  • application/json
  • application/xml
  • application/x-www-form-urlencoded

For more information on submitting content using these content types, please see Data Formats, below.

Operations

You may save and update content via the REST API in several different ways. The URL used to perform the operation specifies what operation you wish to perform. A URL which does not include an argument specifying the operation will throw an error (e.g. just /api/content/ without a save, publish, workflow action name, etc.).

Save or Publish (Working vs. Publishing Versions)

The URL you use to submit content must specify whether you wish save the content (submit a working version of the content without publishing) or publish it (which both saves the working version and then publishes it). To select save or publish, add /save/1 or /publish/1 to the URL after the /content/ portion of the base URL (e.g. /api/content/save/1 or /api/content/publish/1).

Execute a Workflow Action

You may execute a Workflow Action on a piece of content instead of directly saving or publishing it. If the argument following the /content portion of the URI matches a Workflow Action which is currently available for the content item (based on the Workflow Scheme attached to the Content Type and the current Workflow Step the content item is in), then the action is executed.

If the Workflow Action allows comments or allows the user to assign the Workflow Task, you may pass 'wfActionComments' and/or 'wfActionAssign' parameters in the URI.

Note: Since the Workflow Action Name and comments must be passed in the URI, you must use appropriate URL percent encoding in place of any characters which are not appropriate to be passed in a URL (e.g. use %20 in place of a space, %21 in place of an exclamation point, etc.).

Example

The following executes the “Assign for Review” Workflow Action with the comment “Hey, take a look”, and assigns it to the user with id “dotCMS.org.7575”:

PUT /api/content/Assign%20for%20Review/1/wfActionComments/Hey%2C%20take%20a%20look/wfActionAssign/dotCMS.org.7575

Other API Endpoints

For more information on addition endpoint methods available via the Content REST API, please see the REST API Endpoints documentation.

Response Headers

When the content item is successfully created or updated, 3 headers are returned:

HeaderDescription
LocationA pointer to where the content can be obtained using the Content REST API.
InodeThe inode of the content version just saved.
IdentifierThe identifier of the content object just saved.

Authentication

This API supports the same REST authentication methods as other REST APIs in dotCMS. Please read the REST API Authentication documentation for details on the different methods and how to use them when saving content using the REST API.

Note, however, that by default only authenticated users may save content via the REST API. You can configure dotCMS to enable saving of content by non-authenticated (front-end) users (for example to allow front-end users to submit forms which save content using the REST API).

Saving by Non-Authenticated Users

To allow non-authenticated users to save content via the REST API, you must perform all of the following configuration steps:

  1. Set REST_API_CONTENT_ALLOW_FRONT_END_SAVING=true in the dotmarketing-config.properties file.
    • Note: It is strongly recommended that all changes to the dotCMS configuration files be made through a properties extension file.
  2. Set permissions to allow the CMS Anonymous user to save content of the appropriate Content Types.
    • Grant Add to permissions to the CMS Anonymous role on the Site where the content will be saved using the REST API.
    • Grant Edit permissions to the CMS Anonymous role on each Content Type which will be added or updated via the REST API.

For more configuration on how access to the REST API can be controlled via configuration, please see the REST API Authentication documentation.

Data Formats

You may submit data via the Content REST API using several different data formats. The following examples demonstrate ways to submit content via the REST API using JSON, XML, and Form UrlEncoded formats, both to create new content and to update existing content.

Note: Examples Using curl

The following examples use the curl command, which is a command line utility (available for Linux, OS X, and Windows) which allows you to easily perform the HTTP PUT and POST methods required to create and update dotCMS content.

Note:

  • The curl command provides two different methods for submitting REST API calls using JSON format (using the curl -H option and using the curl -F option).
    • The examples below demonstrate both methods.
  • The format for submitting header names is different for each method.
    • See the below examples, and make sure to specify the header names appropriately for the method you use.

JSON

The following curl command creates content of the “Content (Generic)” Content Type (on the dotCMS starter site or demo site) using basic authentication:

curl -v -u admin@dotcms.com:admin -XPUT http://localhost:8080/api/content/publish/1 -H "Content-Type:application/json" -d '{
    contentType:"webPageContent",
    languageId:1,
    title:"test content",
    contentHost:"demo.dotcms.com",
    body:"test body"
}'

Creating and then Updating an EXISTING piece of content

Special Note: Updating content by identifier will not affect the contentlet's relationships to other content. Relationships are preserved when the content is updated by identifier thru the REST Api.

curl -v -u "admin@dotcms.com:admin" -XPUT http://localhost:8080/api/content/publish/1 -F 'json={
   "contentType":"webPageContent",
   "contentHost":"demo.dotcms.com",
   "title":"Test 001 - Created through curl",
   "body":"<b>Created through curl</b>"
};type=application/json'

< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Location: http://localhost:8080/api/content/inode/3227c025-4bb5-4947-843e-9dd2cb95a9dd
< inode: 3227c025-4bb5-4947-843e-9dd2cb95a9dd
< identifier: 699c969c-4be3-4f8d-9d80-da8ff0ab7c7d
< Content-Type: text/plain
< Content-Length: 0
< Date: Wed, 22 Jul 2015 20:42:24 GMT
<
* Connection #0 to host localhost left intact

(some of the output is omitted)

curl -v -u "admin@dotcms.com:admin" -XPUT http://localhost:8080/api/content/publish/1 -F 'json={
   "identifier":"699c969c-4be3-4f8d-9d80-da8ff0ab7c7d",
   "contentType":"webPageContent",
   "contentHost":"demo.dotcms.com",
   "title":"Test 001 - Created through curl",
   "body":"<b>Updated through curl</b>"
};type=application/json'

< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Location: http://localhost:8080/api/content/inode/644c5d16-e0b0-4d1e-a53d-16777197d73f
< inode: 644c5d16-e0b0-4d1e-a53d-16777197d73f
< identifier: 699c969c-4be3-4f8d-9d80-da8ff0ab7c7d
< Content-Type: text/plain
< Content-Length: 0
< Date: Wed, 22 Jul 2015 20:45:44 GMT
<
* Connection #0 to host localhost left intact

(some of the output is omitted)

XML

curl -v -u admin@dotcms.com:admin -XPUT http://localhost:8080/api/content/publish/1 -H "Content-Type:application/xml" -d '
<content>
    <contentType>webPageContent</contentType>
    <languageId>1</languageId>
    <title>test content</title>
    <contentHost>demo.dotcms.com</contentHost>
    <body>test body</body>
</content>'

< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=3806974B823401EEDCB1916FF0469719; Path=/; HttpOnly
< Location: http://localhost:8080/api/content/inode/534c547e-dba9-458b-aef0-b977c7fc2a7e
< inode: 534c547e-dba9-458b-aef0-b977c7fc2a7e
< identifier: 52c81804-e789-48b3-b5c1-0de73a8cacea
< Content-Type: text/plain
< Content-Length: 0

Form UrlEncoded

curl -v -u admin@dotcms.com:admin -XPUT http://localhost:8080/api/content/publish/1 -H "Content-Type:application/x-www-form-urlencoded" -d 'contentType=webPageContent&languageId=1&title=test%20content&contentHost=demo.dotcms.com&body=test%20body'

< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=9589AC9A470E506BC3ED3D779ABF9DF4; Path=/; HttpOnly
< Location: http://localhost:8080/api/content/inode/25942273-57c2-4aa3-bbad-710b7bf3b1bf
< inode: 25942273-57c2-4aa3-bbad-710b7bf3b1bf
< identifier: 11840c4a-57b7-4618-995d-dc935b2fe53b
< Content-Type: text/plain
< Content-Length: 0

Field Types

The following examples demonstrate how to send content for several additional types of Content Type fields.

Categories

Categories can be specified using a comma separated list. Each item in the list will be checked first to see if it matches a Category inode, then to see if it matches a Category key, and finally to see if it matches a Category variable name. If any of these are matched, the appropriate Category will be set for the content item.

The following example adds a News content item on the dotCMS demo site (uploading categories variable names):

curl -v -u admin@dotcms.com:admin -XPUT http://localhost:8080/api/content/publish/1 -H "Content-Type:application/json" -d '{
   contentType:"webPageContent",
   languageId:1,
   urlTitle:"a-new-news-item",
   hostfolder:"demo.dotcms.com",
   title:"A new news item",
   byline: "this is a new story",
   sysPublishDate: "2013-07-01 00:00:00",
   story: "this is a new story uploaded from cURL",
   topic: "investing,banking,research"
}'
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=350BB6A31730E2EC3EF5B0A963B38F5E; Path=/; HttpOnly
< Location: http://localhost:8080/api/content/inode/b5b468f8-f304-4312-a566-5a294786a5a6
< inode: b5b468f8-f304-4312-a566-5a294786a5a6
< identifier: f5a13b1a-d0fc-4934-a6a5-9dc80aaf768d
< Content-Type: text/plain
< Content-Length: 0

Binary Fields

Files can be uploaded into Binary fields using multipart/form-data.

  • Portions of the API call using JSON, XML or Form UrlEncoded data are interpreted as normal field values.
  • Portions of the API call using a Content-Disposition header are added as Binary field values.

Single or multiple binary files can be uploaded as part of a piece of content. Regardless of which method is used, all required binary fields on the Content Type must be submitted.

Uploading a Single Binary File

The following curl command submits a single binary image to a File Asset type of content using the REST API. Note the JSON portion of the API call to set the regular field values, and the file included using @ (which will submit the specified file to the first Binary field in the Content Type).

curl -v -u admin@dotcms.com:admin 
  -XPUT http://localhost:8080/api/content/publish/1 
  -F "json={
    contentType:'fileAsset',
    hostFolder:'demo.dotcms.com:/images',
    title:'nice.jpg',
    fileName:'nice.jpg'};
    type=application/json" 
  -F "file=@nice.jpg;
    type=application/jpg"


< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=1008EEB589168054CAF7C9E9C3D678A3; Path=/; HttpOnly
< Location: http://localhost:8080/api/content/inode/197c5b4c-417a-4ba5-98e6-12f5cda1889b
< inode: 197c5b4c-417a-4ba5-98e6-12f5cda1889b
< identifier: fc2816da-107a-4c01-b404-bd552503f0f4
< Content-Type: text/plain
< Content-Length: 0

Uploading Multiple Binary Fields

The following curl command submits a File Asset using the REST API with TWO binary fields. The names of the two fields are “fileAsset” and “newBinary”. Note the JSON portion of the API call to set the regular field values, and the file included using @ (which will submit the specified file to the Binary fields in the order expressed using in the binary_fields parameter that has been added to the curl command).

Important Note: Notice that the binary_fields parameter is ordering the submit of the files to the fields in the content. When using the binary_fields parameter:

1. The order of the fields submitted to the parameter determines which fields the binary files will be uploaded to
2. Non-required binary fields may be omitted e.g., if the Content type has 4 non-required binary fields, supplying the names of only the 2nd and 3rd fields to the binary_fields parameter will upload only two binary files to those specified fields and leave the other two binary fields empty.  
3. The number of fields supplied to the **binary_fields** parameter must match the number of files that are appended at the end of the REST API submit  
4. The names of each binary field will match the **fileName** specified in the REST API submit.  More flexibility on multiple binary field naming will added in a future dotCMS version.  

The curl command below uses the binary_fields parameter two upload two files to a new contentlet of type “File Asset”. The order of the fields supplied to the parameter, in the example provided below, determines which fields the appended files will be uploaded to respectively i.e., firstFile.jpg will be uploaded to the newBinary field, and secondFile.jpg will be uploaded to the fileAsset field.

curl -v -u admin@dotcms.com:admin 
  -XPUT http://localhost:8080/api/content/publish/1 
  -F "json={
    contentType:'fileAsset',
    hostFolder:'demo.dotcms.com:/images',
    title:'nice.jpg',
    binary_fields:'newBinary, fileAsset'
    fileName:'nice.jpg'};
    type=application/json" 
  -F "file=@firstFile.jpg;
    type=application/jpg"
  -F "file=@secondFile.jpg;
    type=application/jpg"


> PUT /api/content/publish/1 HTTP/1.1
> Host: localhost:8080
> Authorization: Basic YWRtaW5AZG90Y21zLmNvbTphZG1pbg==
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 613008
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------a634768f2b05b1dc
> 
< HTTP/1.1 100 
< HTTP/1.1 409 
< Set-Cookie: JSESSIONID=F3C14AEEEDAA1642CBB8A24874695BA8; Path=/; HttpOnly
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, OPTIONS
< Access-Control-Allow-Headers: Authorization, Accept, Content-Type, Cookies
< Content-Type: text/plain
< Content-Length: 46

Key/Value Pair Fields

In the following example, a Key/Value pair field on a Content Type called “Television” has the Velocity variable name of “productSpecifications”. As shown in the example below, keys and values can be sent via REST API using the following form: fieldVelocityVariableName:{"mykey1:"myValue1","mykey2:"myValue2",... etc.}. Note the handling of the “productSpecifications” key/value pair field.

curl -v -u admin@dotcms.com:admin -XPUT http://localhost:8080/api/content/publish/1 -H "Content-Type:application/json" -d '{
   contentType:"Television",
   languageId:1,
   contentHost:"demo.dotcms.com",
   brandAndModel:"Samsung UN65JS9500",
   resolution:"Ultra HD",
   screenSizeinches:"65",
   productSpecifications:{"Refresh Rate":"240 CMR (Effective)","Backlight":"LED","Smart Functionality":"Yes - Built in Wifi","Inputs":"2 HDMI, 2 USB"}
}'

Relationships

To specify that a piece of content is related to another piece of content, you must pass the Relationship name as the header field name/key and a Lucene query as the value.

Example: Blog-Comments Relationsip

For example the Content Types “Blog” and “Comments” found in the dotCMS starter site and demo site have a one to many relationship between them called “Blog-Comments”.

A new comment matching the parent News post can be added by:

  1. Adding a “Blog-Comments” field in the JSON data.
  2. Adding a Lucene query to the field to identify the Blog content item the comment will be linked with.

The header field would have a format similar to the following:

 "Blog-Comments", "+identifier:12321-123-123123"

Important Notes:

  • The Lucene query must return a single content item for the relationship to be saved properly.
    • To relate a piece of content to multiple pieces of content, you must add a relationship field/value header for each content item you wish to create a relationship to.
  • When updating content using the REST API, you must submit all relationships for a piece of content each time you update the content.
    • If you wish to add a new relationship but maintain all existing relationships, you must first find all existing relationships so that you can include them when updating the content.
    • Any relationships which are not included when you update a content item via the REST API will be removed from that content item.

The following curl command submits a new comment and relates it to a Blog content item:

curl -v -u admin@dotcms.com:admin -XPUT http://localhost:8080/api/content/publish/1 -H "Content-Type:application/json" -d '{
   contentType:"Comments",
   languageId:1,
   title:"test comment",
   email:"myemail@mydomain.com",
   comment:"this is my cool comment",
   Blog-Comments:"+contentType:Blog +title:picks"
}'

The comment should appear in the post “Bill Ackman's Top Stock Picks” that comes by default in the starter. Note that some fields will be left empty as this example only sends the fields required by the Content Type.

Please also see the Example Employee Profile form with Relationship and Binary field below.

Code Examples

The following examples demonstrate how to use the content REST API using scripting and code within dotCMS (such as to submit forms using the REST API).

Using jQuery

Ajax content can be sent to dotCMS, making it possible to create rich Ajax applications within dotCMS. The following example uses jQuery.ajax to create content in a custom Content Type.

Consider the following Blogpost Content Type:

Example Blogpost Content Type

The URL Map Pattern is configured as /Blogpost/{title}. (Note that in a real world application a custom “Url Title” field would be used instead, to convert the title to a URL-friendly string).

The below example page uses jquery to post data to dotCMS. This is the page in its entirety, and this code can be cut and pasted into a blank template, for example purposes. The form data is first captured as a JSON object, then that data is PUT to the dotCMS server via an $.ajax call. If the Blogpost Content Type has been configured as displayed above, this will create a new content item with the values that passed via the $.ajax call.

<html>
  <head>
    <title>dotCMS REST Content Save</title>
    <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script type="text/javascript" src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>

    <script type="text/javascript" >

      $(document).ready(function() {

        $("#newPost").submit(function(e) {
          e.preventDefault();

          var dataObj={'title': $('#title').val(),
          'publishDate': $('#publishDate').val(),
          'body': $('#body').val(),
          'categories': $('#categories').val().join(','),
          'tags': $('#tags').val(),
          'contentType':'Blogpost'};

          $.ajax({
            url: '/api/content/publish/1',
            type: 'PUT',
            cache:false,
            data: dataObj,          
            beforeSend: function (request){
              // This sends the user who authenticates against the dotCMS server
              // In a real world example, you could use session based authentication
              request.setRequestHeader("DOTAUTH", window.btoa("admin@dotcms.com:admin"));
            },

            success: function(data,status,xhr) {
              alert("Success: "   );
              window.location = "/Blogpost/"+$('#title').val();
            },
            error: function(data,status,xhr) {
              alert("fail: " + data );
            console.log(data );
            },
          });
        });
      });

    </script>
  </head>
  <body>
    <div class="container">
      <div class="row">
        <form id="newPost" action="">
          <label for="title">Title</label>
          <input type="text" name="title" id="title"/>

          <label for="publishDate">Publish Date</label>
          <input type="text" name="publishDate" value="2013-07-28 10:34" id="publishDate"/>

          <label for="categories">Categories</label>
          <select id="categories" name="categories" multiple="multiple">
            <option value="design">Design</option>
            <option value="development">Development</option>
            <option value="frontEndDevelopment">Front End Development</option>
            <option value="nosql">NoSQL</option>
            <option value="projectManagement">Project Management</option>
          </select>

          <label for="mainimg">Main Image</label>
          <input type="file" name="mainImage" id="mainImage"/>

          <label for="tags">Tags</label>
          <input type="text" name="tags" id="tags"/>

          <label for="body">Body</label>
          <textarea id="body" name="body"></textarea>
          <div>
          <input type="submit" class="btn" id="Post" name="Post" value="Post"/>
          </div>
        </form>
      </div>
    </div>
  </body>
</html>

Note that the option list for categories can be generated automatically using Velocity and the Categories viewtool.

This page creates the content and then redirects to the URL Map detail page to display the newly created content.

Note that we allow jquery to encode the data as application/x-www-form-urlencoded, which is the default jquery encoding.

Sending Binary Fields Using jquery

In order to send a file to the Binary field we need to construct a FormData object in javascript. This API can be found in all modern browsers and is generally safe to use.

$(document).ready(function() {
    $("#newPost").submit(function(e) {
        e.preventDefault();

        var dataform=new FormData();

        var json={
            'title': $('#title').val(),
            'publishDate': $('#publishDate').val(),
            'body': $('#body').val(),
            'categories': $('#categories').val().join(','),
            'tags': $('#tags').val(),
            'contentType':'Blogpost'
        };
        dataform.append('json',JSON.stringify(json))

        dataform.append('file', document.getElementById('mainImage').files[0]);


        $.ajax({
            url: '/api/content/publish/1',
            type: 'PUT',
            data: dataform,
            processData: false,
            contentType: false,
            success: function(data,status,xhr) {
                window.location = "/Blogpost/"+$('#title').val();
            }
        });
    });
});

Notes:

  • In order to ensure that a multipart/form-data request is sent to the server, processData and contentType must be disabled in the call to jquery.ajax.
  • The json data is added to the dataform with the name “json”.
    • This enables the dotCMS server to recognize that the value is JSON encoded data.
    • Due to limitations in the FormData interface the content-type of the body part can't be set to JSON, and it is instead set to text/plain by default.
    • However the dotCMS server will process it as JSON if either the content-type is set to JSON (application/json) or if the name of the body part is 'json'.
    • The same process is used for 'xml' and 'urlencoded' formats.
      • These formats must be added using the name “xml” and “urlencoded” to notify the dotCMS server of the format being used.

Important: When sending several Binary fields in the FormData object make sure to respect the Binary field order in the Content Type.

Employee Profile form with Relationship and Binary field

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<script type="text/javascript" >
    $(document).ready(function() {
        $("#submitEmployee").submit(function(e) {

            e.preventDefault();

            var dataObj={        
                'ipAddress': "$request.getRemoteAddr()",
                'contentType':'Employee',
                'Department-Employee': '+contentType:Department +identifier:' + id
            };

            if($('#department').val() != undefined && $('#department').val().length > 0 && $('#department').val() != 'Select your Department'){
                dataObj.identifier = $('#department').val();
            } else {
                alert("Please select a department");
                $( "button" ).removeClass( "disabled" ).addClass( "btn-primary" );
                return;
            }
            //How to use the FormData() - https://developer.mozilla.org/en/docs/Web/API/FormData    
            var dataform=new FormData();

            if($('#firstName').val() != undefined && $('#firstName').val().length > 0){
                dataObj.firstName = $('#firstName').val();
            }
            if($('#lastName').val() != undefined && $('#lastName').val().length > 0){
                dataObj.lastName = $('#lastName').val();
            }
            dataObj.gender = $('input[name=gender]:checked').val();

            if($('#jobTitle').val() != undefined && $('#jobTitle').val().length > 0){
                dataObj.jobTitle = $('#jobTitle').val();
            }
            if($('#phone').val() != undefined && $('#phone').val().length > 0){
                dataObj.phone = $('#phone').val();
            }
            if($('#email').val() != undefined && $('#email').val().length > 0){
                dataObj.email = $('#email').val();
            }
            if($('#mobile').val() != undefined && $('#mobile').val().length > 0){
                dataObj.mobile = $('#mobile').val();
            }
            if($('#fax').val() != undefined && $('#fax').val().length > 0){
                dataObj.fax = $('#fax').val();
            }
            if($('#userId').val() != undefined && $('#userId').val().length > 0){
                dataObj.userId = $('#userId').val();
            }
            dataObj.seniorManagement = $('#seniorManagement').is(':checked')

            //convert the dotObject map to a json object
            ##Create a json key using json as value map and something already expected
            dataform.append('json',JSON.stringify(dataObj))

            //append the binary file to the json object - If more than one binary field is present on the Content Type, files should be appended ***in order that the binary fields occur on the Content Type**
            ## Append files as photo, photo(1), photo(2), etc., in order
            dataform.append('file', document.getElementById('photo').files[0]);

            $('requestBtn').attr('disabled', true);
            $('requestBtn').prop('disabled', true);
            $( "button" ).removeClass( "btn-primary" ).addClass( "disabled" );
            $.ajax({
                url: '/api/content/publish/1',
                type: 'PUT',
                cache:false,
                data: dataform,
// see article here http://www.mattlunn.me.uk/blog/2012/05/sending-formdata-with-jquery-ajax - on avoiding non-strings being sent thru jQuery.param() by setting processData and contentType to false
                processData: false,
                contentType: false,

                beforeSend: function (request){
                    //This sends the user who authenticates against the dotCMS server
                    //In a real world example, you could use session based authentication
                    request.setRequestHeader("DOTAUTH", window.btoa("admin@dotcms.com:admin"));
                },       

                success: function(data,status,xhr) {
                    console.log("works!");
                    var a = xhr.getAllResponseHeaders();
                    var id = a.substring(a.indexOf('identifier: ') + 'identifier: '.length , a.indexOf('\n', a.indexOf('identifier: ') + 'identifier: '.length));
                            //redirect to thank you page, passing identifier of employee                    
                            window.location="/about-us/our-team/success?id="  + id;
                },

                error: function(data,status,xhr) {
                    $('requestBtn').attr('disabled', false);
                    $('requestBtn').prop('disabled', false);
                    $( "button" ).removeClass( "disabled" ).addClass( "btn-primary" );
                    console.log(data);
                    alert("Uh Oh, your request failed. Please check your entries and try again");
                }
            }); //End $.ajax
        }); // End $("#submitEmployee").submit
    }); // End $(document).ready

</script>

<div class="form-container">

    <!-- Form Name -->

    <hr>

    <form class="form-horizontal"  role="form"  id="submitEmployee">
        <input type="hidden" name="contentType" value="Employee">
        <input type="hidden" name="languageId" value="1">
        <input type="hidden" name="contentHost" value="demo.dotcms.com">

        <div class="form-group">
            <label class="col-sm-3 control-label" for="firstName" class="required">First Name: <span class="required">*</span></label>
            <div class="col-sm-8">
                #if($user)
                    <input id="firstName" class="form-control" type="text"  name="firstName"  value="$user.firstName">
                else
                    <input id="firstName" class="form-control" placeholder="Enter your first Name" type="text"  name="firstName"  value="">
                #end
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="lastName">Last Name: <span class="required">*</span></label>
            <div class="col-sm-8">
                #if($user)
                    <input id="lastName" class="col-sm-12" name="lastName" type="text" placeholder="$user.lastName" value="$user.lastName" required>
                #else
                    <input id="lastName" class="col-sm-12" name="lastName" type="text" placeholder="Enter your last name" value="" required>
                #end
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="gender">Gender: </label>
            <div class="col-sm-8">
                <input type=radio id="genderMale"  name="gender" value="male" checked="true"> <label for="genderMale">Male</label> &nbsp;&nbsp;
                <input type=radio id="genderFemale"  name="gender" value="female" > <label for="genderFemale">Female</label> &nbsp;&nbsp;
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="jobTitle">Job Title: </span></label>
            <div class="col-sm-8">
                <input id="jobTitle" class="col-sm-12" name="jobTitle" type="text" placeholder="Job Title" value="">
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="email">Email: </span></label>
            <div class="col-sm-8">
                #if($user)
                    <input id="email" class="col-sm-12" name="email" type="text" value="$user.emailAddress">
                #else
                    <input id="email" class="col-sm-12" name="email" type="text" placeholder="Email" value="">
                #end
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="phone">Phone: </span></label>
            <div class="col-sm-8">
                <input id="phone" class="col-sm-12" name="phone" type="text" placeholder="Phone Number" value="">
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="mobile">Mobile: </span></label>
            <div class="col-sm-8">
                <input id="mobile" class="col-sm-12" name="mobile" type="text" placeholder="Mobile" value="">
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="fax">Fax: </span></label>
            <div class="col-sm-8">
                <input id="fax" class="col-sm-12" name="fax" type="text" placeholder="Fax" value="">
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="seniorManagement">Management: </span></label>
            <div class="col-sm-8">
                <input type="checkbox" class="col-sm-12" name="seniorManagement" id="seniorManagement" type="text" value="">
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-3 control-label" for="photo">Photo: </span></label>
            <div class="col-sm-8">
                <input type="file" class="col-sm-12" name="photo" id="photo" type="text" placeholder="photo" value="">
            </div>
        </div>

        ## Select the related Department data
        <div class="form-group">
            <label class="col-sm-3 control-label" for="fund">Department: </label>
            <div class="col-sm-8">
                <select class="form-control col-sm-12" id="department" name="department" required>
                    <option>Select your Department</option>
                    #foreach($department in $dotcontent.pull("+contentType:Department +(conhost:48190c8c-42c4-46af-8d1a-0cd5db894797 conhost:SYSTEM_HOST)",0,"Department.departmentName"))
                        <option value="$department.identifier">$department.departmentName</option>
                    #end
                </select>
            </div>
        </div>

        #if($user)
            <input type="hidden" name="userId" id="userId" value="$user.userId">
        #end

        <hr>

        <!-- Button -->
        <div class="text-center">
            <button id="requestBtn" name="singlebutton" class="btn btn-primary btn-large">Submit Profile</button>
        </div>

    </form>
</div>  ##end <div class="form-container">