action.skip

Updating Content Types

Existing Content Type can be updated either by sending a properly formatted PUT request to the /api/v1/internal/contenttype/{name} endpoint or through the Content Modeler tool provided with the platform.

Note

You will need to use your Application Read and write API KEY to perform this action. Read more about API keys and scoped API keys.

Warning

Changes made to the Content Type Definition may lead to problems with programs and pages already using this CTD if they break compatibility. We strongly suggest only apply non-breaking changes to existing CTDs.

Updating Content Types via API

Updating Content Type is simply a PUT call with a payload similar to:

{
    "name": "blogposts",
    "label": "Blog Posts",
    "schemaDefinition": {
        "type": "object",
        "allOf": [
            {
                "$ref": "#/components/schemas/AbstractContentTypeSchemaDefinition"
            },
            {
                "type": "object",
                "properties": {
                    "title": {
                        "type": "string",
                        "minLength": 1
                },
                    "postContent": {
                        "type": "string",
                        "minLength": 1
                    }
                }
            }
        ],
        "required": [
            "title",
            "postContent"
        ],
        "additionalProperties": false
    },
    "metaDefinition": {
        "propertiesConfig": {
            "title": {
                "label": "Title",
                "inputType": "text",
                "unique": true
            },
            "postContent": {
                "label": "Post content",
                "inputType": "richtext",
                "unique": false
            }
        },
        "order": [
            "title",
            "postContent"
        ]
    }
}

You can find description of the schema here

Tip

After every change in Content Definition Schema Flotiq automatically updates your API documentation and Elastic Search index attached to this type. This means your API docs will always stay up to date with your current schema, and so will the results of the full-text search feature.

What happens if you add a new property?

When you are adding new properties, objects already in the system will not have that property present until added by you.

What happens if you remove a property?

If you remove the property, all objects will be stripped of that property's value after schema would be saved.

What happens if you change a property?

When you change existing property, depending on the type of changes, Flotiq will:

  • Do nothing with your data if changes are made to label, isTitlePart, unique, required, pattern, options or default properties
  • Try to convert data if the changes are made to type or inputType properties if data will not be preserved, and the property is required, update of the CTD will not succeed (more in conversion table)
  • Remove data attached to old property name when name of the property was changed; objects will not have a property with the new name present as in adding a new property

Warning

When updating Content Definition Schema, you must remember that Flotiq will try to update objects of that type to reflect changes in the schema, which can result in data loss, if the old types and new types of the properties are not compatible.

Example

curl --location --request PUT "https://api.flotiq.com/api/v1/internal/contenttype/blogposts" \
--header 'X-AUTH-TOKEN: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--data-raw '{
    "name":"blogpost",
    "label":"Blog Posts",
    "schemaDefinition":{
        "type":"object",
        "allOf":[{
            "$ref":"#/components/schemas/AbstractContentTypeSchemaDefinition"
            },{
            "type":"object",
            "properties":{
                "title":{"type":"string"},
                "postContent":{"type":"string"}}}
        ],
        "required":["title","postContent"],
        "additionalProperties":false
    },
    "metaDefinition":{
        "propertiesConfig":{
            "title":{
                "label":"Title",
                "inputType":"text",
                "unique":true},
            "postContent":{
                "label":"Post content",
                "inputType":"richtext",
                "unique":false}},
        "order":["title","postContent"]}
}'

var client = new RestClient("https://api.flotiq.com/api/v1/internal/contenttype/blogposts");
var request = new RestRequest(Method.PUT);
request.AddHeader("content-type", "application/json");
request.AddHeader("X-AUTH-TOKEN", "YOUR_API_KEY");
request.AddParameter("application/json", "{\"name\":\"blogposts\",\"label\":\"Blog Posts\",\"schemaDefinition\":{\"type\":\"object\",\"allOf\":[{\"$ref\":\"#/components/schemas/AbstractContentTypeSchemaDefinition\"},{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"postContent\":{\"type\":\"string\"}}}],\"required\":[\"title\",\"postContent\"],\"additionalProperties\":false},\"metaDefinition\":{\"propertiesConfig\":{\"title\":{\"label\":\"Title\",\"inputType\":\"text\",\"unique\":true},\"postContent\":{\"label\":\"Post content\",\"inputType\":\"richtext\",\"unique\":false}},\"order\":[\"title\",\"postContent\"]}}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);

package main

import (
    "fmt"
    "strings"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://api.flotiq.com/api/v1/internal/contenttype/blogposts"

    payload := strings.NewReader("{\"name\":\"blogposts\",\"label\":\"Blog Posts\",\"schemaDefinition\":{\"type\":\"object\",\"allOf\":[{\"$ref\":\"#/components/schemas/AbstractContentTypeSchemaDefinition\"},{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"postContent\":{\"type\":\"string\"}}}],\"required\":[\"title\",\"postContent\"],\"additionalProperties\":false},\"metaDefinition\":{\"propertiesConfig\":{\"title\":{\"label\":\"Title\",\"inputType\":\"text\",\"unique\":true},\"postContent\":{\"label\":\"Post content\",\"inputType\":\"richtext\",\"unique\":false}},\"order\":[\"title\",\"postContent\"]}}")

    req, _ := http.NewRequest("PUT", url, payload)

    req.Header.Add("content-type", "application/json")
    req.Header.Add("X-AUTH-TOKEN", "YOUR_API_KEY")

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"name\":\"blogposts\",\"label\":\"Blog Posts\",\"schemaDefinition\":{\"type\":\"object\",\"allOf\":[{\"$ref\":\"#/components/schemas/AbstractContentTypeSchemaDefinition\"},{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"postContent\":{\"type\":\"string\"}}}],\"required\":[\"title\",\"postContent\"],\"additionalProperties\":false},\"metaDefinition\":{\"propertiesConfig\":{\"title\":{\"label\":\"Title\",\"inputType\":\"text\",\"unique\":true},\"postContent\":{\"label\":\"Post content\",\"inputType\":\"richtext\",\"unique\":false}},\"order\":[\"title\",\"postContent\"]}}");
Request request = new Request.Builder()
    .url("https://api.flotiq.com/api/v1/internal/contenttype/blogposts")
    .put(body)
    .addHeader("content-type", "application/json")
    .addHeader("X-AUTH-TOKEN", "YOUR_API_KEY")
    .build();

Response response = client.newCall(request).execute();

HttpResponse<String> response = Unirest.put("https://api.flotiq.com/api/v1/internal/contenttype/blogposts")
    .header("content-type", "application/json")
    .header("X-AUTH-TOKEN", "YOUR_API_KEY")
    .body("{\"name\":\"blogposts\",\"label\":\"Blog Posts\",\"schemaDefinition\":{\"type\":\"object\",\"allOf\":[{\"$ref\":\"#/components/schemas/AbstractContentTypeSchemaDefinition\"},{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"postContent\":{\"type\":\"string\"}}}],\"required\":[\"title\",\"postContent\"],\"additionalProperties\":false},\"metaDefinition\":{\"propertiesConfig\":{\"title\":{\"label\":\"Title\",\"inputType\":\"text\",\"unique\":true},\"postContent\":{\"label\":\"Post content\",\"inputType\":\"richtext\",\"unique\":false}},\"order\":[\"title\",\"postContent\"]}}")
    .asString();

const request = require('request');

const options = {
    method: 'PUT',
    url: 'https://api.flotiq.com/api/v1/internal/contenttype/blogposts',
    headers: {'content-type': 'application/json', 'X-AUTH-TOKEN': 'YOUR_API_KEY'},
    body: {
        "name": "blogposts",
        "label": "Blog Posts",
        "schemaDefinition": {
            "type": "object",
            "allOf": [
                {
                    "$ref": "#/components/schemas/AbstractContentTypeSchemaDefinition"
                },
                {
                    "type": "object",
                    "properties": {
                        "title": {
                            "type": "string",
                            "minLength": 1
                    },
                        "postContent": {
                            "type": "string",
                            "minLength": 1
                        }
                    }
                }
            ],
            "required": [
                "title",
                "postContent"
            ],
            "additionalProperties": false
        },
        "metaDefinition": {
            "propertiesConfig": {
                "title": {
                    "label": "Title",
                    "inputType": "text",
                    "unique": true
                },
                "postContent": {
                    "label": "Post content",
                    "inputType": "richtext",
                    "unique": false
                }
            },
            "order": [
                "title",
                "postContent"
            ]
        }
    },
    json: true
};

request(options, function (error, response, body) {
    if (error) throw new Error(error);

    console.log(body);
});

<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.flotiq.com/api/v1/internal/contenttype/blogposts",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "PUT",
    CURLOPT_POSTFIELDS => "{\"name\":\"blogposts\",\"label\":\"Blog Posts\",\"schemaDefinition\":{\"type\":\"object\",\"allOf\":[{\"$ref\":\"#/components/schemas/AbstractContentTypeSchemaDefinition\"},{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"postContent\":{\"type\":\"string\"}}}],\"required\":[\"title\",\"postContent\"],\"additionalProperties\":false},\"metaDefinition\":{\"propertiesConfig\":{\"title\":{\"label\":\"Title\",\"inputType\":\"text\",\"unique\":true},\"postContent\":{\"label\":\"Post content\",\"inputType\":\"richtext\",\"unique\":false}},\"order\":[\"title\",\"postContent\"]}}",
    CURLOPT_HTTPHEADER => [
            "X-AUTH-TOKEN: YOUR_API_KEY",
            "content-type: application/json"
        ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
    echo "cURL Error #:" . $err;
} else {
    echo $response;
}

Response

Returned when the schema has been correct and was saved

{
    "name": "blogposts",
    "label": "Blog Posts",
    "schemaDefinition": {
        "type": "object",
        "allOf": [
            {
                "$ref": "#/components/schemas/AbstractContentTypeSchemaDefinition"
            },
            {
                "type": "object",
                "properties": {
                    "title": {
                        "type": "string",
                        "minLength": 1
                },
                    "postContent": {
                        "type": "string",
                        "minLength": 1
                    }
                }
            }
        ],
        "required": [
            "title",
            "postContent"
        ],
        "additionalProperties": false
    },
    "metaDefinition": {
        "propertiesConfig": {
            "title": {
                "label": "Title",
                "inputType": "text",
                "unique": true
            },
            "postContent": {
                "label": "Post content",
                "inputType": "richtext",
                "unique": false
            }
        },
        "order": [
            "title",
            "postContent"
        ]
    }
}

Returned when the schema has not been correct and wasn't saved

{
    "name": [
        "This value is already used."
    ],
    "label": [
        "Must be at least 1 characters long"
    ],
    "schemaDefinition.allOf[1].properties.title.type": [
        "Does not have a value in the enumeration [\"array\",\"boolean\",\"integer\",\"null\",\"number\",\"object\",\"string\"]",
        "String value found, but an array is required",
        "Failed to match at least one schema"
    ],
    "metaDefinition.propertiesConfig.price.label": [
        "The property label is required"
    ],
    "metaDefinition.propertiesConfig.price.inputType": [
        "Does not have a value in the enumeration [\"text\",\"richtext\",\"textarea\",\"textMarkdown\",\"email\",\"number\",\"radio\",\"checkbox\",\"select\",\"datasource\",\"object\",\"geo\"]"
    ]
}

Returned when API key was missing or incorrect

{
    "code": 401,
    "massage": "Unauthorized"
}

Returned when the schema wasn't found

{
    "code": 404,
    "massage": "Not found"
}

Possible validation errors

Possible validation errors resemble those encountered when creating Content Types. You can find the list here.

Validation can also fail when updating the schema by modifying required fields or changing field types.

Updating Schema and Modifying Required Fields

When you modify a schema, any associated objects undergo a transformation process. This process ensures that the objects conform to the new schema's structure. However, there are certain considerations to keep in mind:

  1. Required Fields: If a field is marked as "required" in the schema, the system expects all existing objects to have a value for that field. The transformation will fail during the conversion process if an existing object lacks a value for a newly marked required field.
  2. Changing Field Types: If you change the data type of a field, particularly from one type to another, that cannot be automatically transformed (e.g., from "Text" to "Relationship"), updating existing objects automatically becomes challenging.

When encountering issues during schema conversion, you might receive error messages like the following:

Response

Returned when the schema has not been correct and wasn't saved

{
    "fieldName":["The property fieldName is required"],
    "co":{
        "coFieldName":["Object: /api/v1/content/_media/media doesn't exists "]
    }
    "ctd":["Existing objects do not conform to the new schema, and updating them automatically is impossible (e.g., Text -> Relationship). Ensure you're not changing a field type that is also required - if so, disable required for the field you're changing."]
}

How are fields converted from one type to another?

Old Type (type/inputType) New Type (type/inputType) Conversion
string/text string/textarea Data are preserved
string/text string/markdown Data are preserved
string/text string/richtext Data are preserved
string/text string/email Data are preserved
string/text number/number All objects gets 0 value
string/text string/radio Data are preserved
string/text boolean/checkbox All objects gets false value
string/text string/select Data are preserved
string/text array/object All objects gets empty array
string/text array/datasource All objects gets empty array
string/text object/geo All objects gets object with value: {lat: 0, lon: 0}
string/text array/select String is converted to array of strings if data are among available options
string/text array/simpleList String is converted to array of strings
string/textarea string/text Data are preserved
string/textarea string/markdown Data are preserved
string/textarea string/richtext Data are preserved
string/textarea string/email Data are preserved
string/textarea number/number All objects gets 0 value
string/textarea string/radio Data are preserved
string/textarea boolean/checkbox All objects gets false value
string/textarea string/select Data are preserved
string/textarea array/object All objects gets empty array
string/textarea array/datasource All objects gets empty array
string/textarea object/geo All objects gets object with value: {lat: 0, lon: 0}
string/textarea array/select String is converted to array of strings if data are among available options
string/textarea array/simpleList String is converted to array of strings
string/markdown string/text Data are preserved
string/markdown string/textarea Data are preserved
string/markdown string/richtext Data are preserved
string/markdown string/email Data are preserved
string/markdown number/number All objects gets 0 value
string/markdown string/radio Data are preserved
string/markdown boolean/checkbox All objects gets false value
string/markdown string/select Data are preserved
string/markdown array/object All objects gets empty array
string/markdown array/datasource All objects gets empty array
string/markdown object/geo All objects gets object with value: {lat: 0, lon: 0}
string/markdown array/select String is converted to array of strings if data are among available options
string/markdown array/simpleList String is converted to array of strings
string/richtext string/text Data are preserved
string/richtext string/textarea Data are preserved
string/richtext string/markdown Data are preserved
string/richtext string/email Data are preserved
string/richtext number/number All objects gets 0 value
string/richtext string/radio Data are preserved
string/richtext boolean/checkbox All objects gets false value
string/richtext string/select Data are preserved
string/richtext array/object All objects gets empty array
string/richtext array/datasource All objects gets empty array
string/richtext object/geo All objects gets object with value: {lat: 0, lon: 0}
string/richtext array/select String is converted to array of strings if data are among available options
string/richtext array/simpleList String is converted to array of strings
string/email string/textarea Data are preserved
string/email string/markdown Data are preserved
string/email string/richtext Data are preserved
string/email number/number All objects gets 0 value
string/email string/radio Data are preserved
string/email boolean/checkbox All objects gets false value
string/email string/select Data are preserved
string/email array/object All objects gets empty array
string/email array/datasource All objects gets empty array
string/email object/geo All objects gets object with value: {lat: 0, lon: 0}
string/email array/select String is converted to array of strings if data are among available options
string/email array/simpleList String is converted to array of strings
number/number string/text Numbers are converted to string counterparts
number/number string/textarea Numbers are converted to string counterparts
number/number string/markdown Numbers are converted to string counterparts
number/number string/richtext Numbers are converted to string counterparts
number/number string/email Numbers are converted to string counterparts
number/number string/radio Numbers are converted to string counterparts
number/number boolean/checkbox All objects gets false value
number/number string/select Numbers are converted to string counterparts
number/number array/object All objects gets empty array
number/number array/datasource All objects gets empty array
number/number object/geo All objects gets object with value: {lat: 0, lon: 0}
number/number array/select Numbers are converted to string counterparts and then converted to array of strings if data are among available options
number/number array/simpleList Numbers are converted to string counterparts and then converted to array of strings
string/radio string/text Data are preserved
string/radio string/textarea Data are preserved
string/radio string/markdown Data are preserved
string/radio string/richtext Data are preserved
string/radio string/email Data are preserved
string/radio number/number All objects gets 0 value
string/radio boolean/checkbox All objects gets false value
string/radio string/select Data are preserved
string/radio array/object All objects gets empty array
string/radio array/datasource All objects gets empty array
string/radio object/geo All objects gets object with value: {lat: 0, lon: 0}
string/radio array/select String is converted to array of strings if data are among available options
string/radio array/simpleList String is converted to array of strings
boolean/checkbox string/text Data are converted to the string counterparts
boolean/checkbox string/textarea Data are converted to the string counterparts
boolean/checkbox string/markdown Data are converted to the string counterparts
boolean/checkbox string/richtext Data are converted to the string counterparts
boolean/checkbox string/email Data are converted to the string counterparts
boolean/checkbox number/number All objects gets 0 value
boolean/checkbox string/radio Data are converted to the string counterparts
boolean/checkbox string/select Data are converted to the string counterparts
boolean/checkbox array/object All object gets empty array
boolean/checkbox array/datasource All object gets empty array
boolean/checkbox object/geo All object gets object with value: {lat: 0, lon: 0}
boolean/checkbox array/select Data are converted to string counterparts and then converted to array of strings if data are among available options
boolean/checkbox array/simpleList Data are converted to string counterparts and then converted to array of strings
string/select string/text Data are preserved
string/select string/textarea Data are preserved
string/select string/markdown Data are preserved
string/select string/richtext Data are preserved
string/select string/email Data are preserved
string/select number/number All objects gets 0 value
string/select string/radio Data are preserved
string/select boolean/checkbox All objects gets false value
string/select array/object All objects gets empty array
string/select array/datasource All objects gets empty array
string/select object/geo All objects gets object with value: {lat: 0, lon: 0}
string/select array/select All objects gets empty array
string/select array/simpleList All objects gets empty array
array/select string/text Data are joined to simple string using , as glue
array/select string/textarea Data are joined to simple string using , as glue
array/select string/markdown Data are joined to simple string using , as glue
array/select string/richtext Data are joined to simple string using , as glue
array/select string/email Data are joined to simple string using , as glue
array/select number/number All objects gets 0 value
array/select string/radio First element of data is preserved
array/select boolean/checkbox All objects gets false value
array/select array/object All objects gets empty array
array/select array/datasource All objects gets empty array
array/select object/geo All objects gets object with value: {lat: 0, lon: 0}
array/select string/select First element of data is preserved
array/select array/simpleList Data are preserved
array/object string/text All objects gets '' value
array/object string/textarea All objects gets '' value
array/object string/markdown All objects gets '' value
array/object string/richtext All objects gets '' value
array/object string/email All objects gets '' value
array/object number/number All objects gets 0 value
array/object string/radio All objects gets '' value
array/object boolean/checkbox All objects gets false value
array/object string/select All objects gets '' value
array/object array/datasource All objects gets empty array
array/object object/geo All objects gets object with value: {lat: 0, lon: 0}
array/object array/select String is converted to array of strings
array/object array/simpleList String is converted to array of strings
array/datasource string/text Data are converted to dataUrls joined with ', '
array/datasource string/textarea Data are converted to dataUrls joined with ', '
array/datasource string/markdown Data are converted to dataUrls joined with ', '
array/datasource string/richtext Data are converted to dataUrls joined with ', '
array/datasource string/email Data are converted to dataUrls joined with ', '
array/datasource number/number All objects gets 0 value
array/datasource string/radio Data are converted to dataUrls joined with ', '
array/datasource boolean/checkbox All objects gets false value
array/datasource string/select Data are converted to dataUrls joined with ', '
array/datasource array/object All objects gets empty array
array/datasource object/geo All objects gets object with value: {lat: 0, lon: 0}
array/datasource array/select All objects gets empty array
array/datasource array/simpleList All objects gets empty array
object/geo string/text Data are converted to 'lat: {lat value}, lon: {lon value}'
object/geo string/textarea Data are converted to 'lat: {lat value}, lon: {lon value}'
object/geo string/markdown Data are converted to 'lat: {lat value}, lon: {lon value}'
object/geo string/richtext Data are converted to 'lat: {lat value}, lon: {lon value}'
object/geo string/email Data are converted to 'lat: {lat value}, lon: {lon value}'
object/geo number/number All objects gets 0 value
object/geo string/radio Data are converted to 'lat: {lat value}, lon: {lon value}'
object/geo boolean/checkbox All objects gets false value
object/geo string/select Data are converted to 'lat: {lat value}, lon: {lon value}'
object/geo array/object All objects gets empty array
object/geo array/datasource All objects gets empty array
object/geo array/select All objects gets empty array
object/geo array/simpleList All objects gets empty array
array/simpleList string/text Data are joined to simple string using , as glue
array/simpleList string/textarea Data are joined to simple string using , as glue
array/simpleList string/markdown Data are joined to simple string using , as glue
array/simpleList string/richtext Data are joined to simple string using , as glue
array/simpleList string/email Data are joined to simple string using , as glue
array/simpleList number/number All objects gets 0 value
array/simpleList string/radio First element of data is preserved
array/simpleList boolean/checkbox All objects gets false value
array/simpleList array/object All objects gets empty array
array/simpleList array/datasource All objects gets empty array
array/simpleList object/geo All objects gets object with value: {lat: 0, lon: 0}
array/simpleList string/select First element of data is preserved
array/simpleList array/select Data are preserved

Updating Content Types through the Content modeller

If you'd rather use our graphical interface to update your Content Types - read the Content modeller documentation

Register to send all requests with your own API today