REST API

Hazelcast provides a REST API that allows you to access your data structures and cluster using the HTTP/HTTPS protocols.

You can interact with the API using various tools and platforms such as cURL, REST clients (like Postman and Insomnia), or programming languages with HTTP request libraries or built-in support. The REST API also comes with a Swagger UI that offers an easy navigation and testing the API calls. See Accessing the Swagger UI.

In this section, we use cURL to provide the request examples.

REST API is only available in the Enterprise Edition. Hazelcast also offered a Community Edition REST API, but this has been deprecated and will be removed as of Hazelcast version 7.0. For more info, see Community Edition REST API.

Enabling REST API

REST service is disabled in the configuration by default; enable it as shown in the following configuration.

If you are using Hazelcast’s slim distribution, you must add hazelcast-enterprise-rest-5.5.0-SNAPSHOT.jar to your member’s classpath to use the REST API. If you are working with the full distribution, this additional step is not needed.
  • XML

  • YAML

<hazelcast>
    <rest enabled="true">
        ...
    </rest>
</hazelcast>
hazelcast:
  rest:
    enabled: true

Changing Default Port

8443 is the default port for REST API. To change it to another port, update the rest configuration as shown in the following example.

  • XML

  • YAML

<hazelcast>
    <rest enabled="true">
        <port>8080</port>
    </rest>
</hazelcast>
hazelcast:
  rest:
    enabled: true
    port: 8080

Authentication

You must secure the communication with REST API by configuring its authentication and access control.

Configuring Authentication

REST supports simple authentication based on username, password and user roles; see Simple Authentication. To configure the simple authentication in the REST API, complete the following steps:

  • Enable REST API: You need to enable the REST API.

  • Define A Security Realm: You need to define the security realm within the rest configuration.

  • Enable Security: You need to enable the security to use REST API.

  • Configure Rest Realm: You need to introduce a REST realm as the authentication mechanism. This realm will handle user authentication using a simple method based on username and password.

  • Setup Users and Roles: You should identify users and their roles within the REST realm.

  • Configure AccessControlService: To configure AccessControlService, you should provide a factory class that creates an instance of the service. AccessControlService delegates authentication to the configured security realm. You can either create a custom factory class, or use the default implementation. For the default implementation, you can use DefaultAccessControlServiceFactory, to produce DefaultAccessControlService. Authorization decisions in this service are based on three predefined roles: reader, who can make requests via GET endpoints only; writer, who can make requests including GET, POST, and DELETE; and admin, who can make all requests and access admin-specific endpoints.

The following configuration example includes all the steps listed above.

  • XML

  • YAML

<hazelcast>
    <rest enabled="true">
        <security-realm>restRealm</security-realm>
    </rest>
    <security enabled="true">
        <realms>
            <realm name="restRealm">
                <authentication>
                    <simple>
                        <user username="restuser" password="restsecret">
                            <role>admin</role>
                        </user>
                    </simple>
                </authentication>
                <access-control-service> (1)
                    <factory-class-name>com.hazelcast.internal.rest.access.DefaultAccessControlServiceFactory</factory-class-name>
                </access-control-service>
            </realm>
        </realms>
    </security>
</hazelcast>
hazelcast:
  rest:
    enabled: true
    security-realm: restRealm
  security:
    enabled: true
    realms:
      - name: restRealm
        authentication:
          simple:
            users:
              - username: 'restuser'
                password: 'restpassword'
                roles:
                  - admin
        access-control-service: (1)
          factory-class-name: com.hazelcast.internal.rest.access.DefaultAccessControlServiceFactory
1 To configure AccessControlService, you should provide a factory class that creates an instance of the service. AccessControlService delegates authentication to the configured security realm. You can either create a custom factory class, or use the default implementation. For the default implementation, you can use DefaultAccessControlServiceFactory, to produce DefaultAccessControlService. Authorization decisions in this service are based on three predefined roles: reader, who can make requests via GET endpoints only; writer, who can make requests including GET, POST, and DELETE; and admin, who can make all requests and access admin-specific endpoints.
Besides the simple authentication, you can also use other authentication types such as LDAP. See Authentication Configuration on how to configure different types within a security realm.

Authentication Process

To authenticate to the REST API, the REST client must obtain a token. See the Obtaining a Token section for details. The token request requires a username and password and the role(s) assigned to the user are included in the token as claims. You can use the token until it expires. You use the token at the Authorization header for each subsequent REST API call so that the call is authorized appropriately. If a valid token is not included in the header, the API will respond with a 401 Unauthorized error.

HTTPS Support

You can configure TLS/SSL in the REST API. We use Spring Boot underneath to enable Spring web services, and all the TLS/SSL related options correspond to the underlying Spring Boot TLS/SSL support capabilities.

The TLS/SSL configuration of the REST server is completely different from Hazelcast TLS/SSL configuration which has different configuration settings. The configuration settings are available to set up TLS/SSL as shown in the below declarative example:

  • XML

  • YAML

<hazelcast>
    <rest enabled="true">
        <ssl enabled="true">
            <client-auth>NEED</client-auth>
            <ciphers>TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256</ciphers>
            <key-alias>myKeyAlias</key-alias>
            <key-password>myKeyPassword</key-password>
            <key-store>/path/to/keystore</key-store>
            <key-store-password>myKeyStorePassword</key-store-password>
            <key-store-type>JKS</key-store-type>
            <key-store-provider>SUN</key-store-provider>
            <trust-store>/path/to/truststore</trust-store>
            <trust-store-password>myTrustStorePassword</trust-store-password>
            <trust-store-type>JKS</trust-store-type>
            <trust-store-provider>SUN</trust-store-provider>
            <enabled-protocols>TLSv1.2, TLSv1.3</enabled-protocols>
            <protocol>TLS</protocol>
            <certificate>/path/to/certificate</certificate>
            <certificate-key>/path/to/certificate-key</certificate-key>
            <trust-certificate>/path/to/trust-certificate</trust-certificate>
            <trust-certificate-key>/path/to/trust-certificate-key</trust-certificate-key>
        </ssl>
    </rest>
</hazelcast>
hazelcast:
  rest:
    enabled: true
    ssl:
      enabled: true
      client-auth: NEED
      ciphers: TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256
      enabled-protocols: TLSv1.2, TLSv1.3
      key-alias: myKeyAlias
      key-password: myKeyPassword
      key-store: /path/to/keystore
      key-store-password: myKeyStorePassword
      key-store-type: JKS
      key-store-provider: SUN
      trust-store: /path/to/truststore
      trust-store-password: myTrustStorePassword
      trust-store-type: JKS
      trust-store-provider: SUN
      protocol: TLS
      certificate: /path/to/certificate
      certificate-key: /path/to/certificate-key
      trust-certificate: /path/to/trust-certificate
      trust-certificate-key: /path/to/trust-certificate-key

JWT Based Authorization

After a successful authentication by making request to the token endpoint (see Obtaining a Token section), you will receive a short-living JWT token with assigned role names as a claim for authorization checks in subsequent REST calls.

Token issued by one member is not trusted by other members.

Tokens are valid for 15 minutes by default. You can update the expiry duration using the token-validity-seconds configuration element as shown in the following example.

  • XML

  • YAML

<hazelcast>
    <rest enabled="true">
        <token-validity-seconds>300</token-validity-seconds>
    </rest>
</hazelcast>
hazelcast:
  rest:
    enabled: true
    token-validity-seconds: 300

Obtaining a Token

To obtain a token, you send a POST request to the token endpoint at /hazelcast/rest/api/v1/token. The request must include JSON-formatted username and password which you already configured. If the authentication is successful, you get a response which contains a valid token for the expiry duration.

Example request using cURL:

curl -X 'POST' \
  'http://localhost:8443/hazelcast/rest/api/v1/token' \
  -H 'Content-Type: application/json' \
  -d '{
  "username": "restuser",
  "password": "restpassword"
}'

It returns the following response if successful:

{
  "token": "<JWT Token>"
}

It returns the following response if the provided credentials are incorrect:

{
  "statusCode": 401,
  "message": "Username/password provided don't match the expected values."
}

Accessing the Swagger UI

Hazelcast REST API’s Swagger UI provides information about each endpoint, including required parameters, request and response structures and types, potential response codes, and example responses. You can use this UI to easily navigate and test different API calls directly from the interface. To access it:

  1. Enable the REST API.

  2. Start a Hazelcast member.

  3. Go to http://<host>:<port>/swagger-ui/index.html where <host> and <port> are the running member’s IP address/hostname and port, respectively.

The following is an example view:

rest api swagger listed endpoints

On the Swagger page, each endpoint is listed with a caret icon on the right side. Click the caret icon to expand the details for an endpoint. For this example, let’s expand the GET /hazelcast/rest/api/v1/cluster endpoint.

rest api swagger expanding an endpoint

After expanding the endpoint, let’s proceed to send a request. Click the Try it out button, enter the parameters (if any). There are no parameters for this example.

rest api swagger clicking execute button

Click the Execute button to send the request. You can see the response in the Server response section as shown below. You can also see the executed cURL command in the Curl section.

rest api swagger clicking try it out button

GET/POST/DELETE HTTP Request Examples

All the requests in the REST API can return one of the following response types.

  • Successful void/boolean response which does not have a body.

  • Successful response which returns data in JSON format. For example:

{
  "nodeState": "ACTIVE",
  "clusterState": "ACTIVE",
  "numberOfMembers": 1
}
  • Error response in JSON format. For example:

{
  "statusCode": 400,
  "message": "Please provide a valid value."
}

Retrieving Cluster Status

You can send a GET request to the endpoint at /hazelcast/rest/api/v1/cluster to retrieve the status of your cluster.

Example request using cURL:

curl -X 'GET' \
  'http://localhost:8443/hazelcast/rest/api/v1/cluster' \
  -H 'Authorization: Bearer <JWT Token>'

It returns the following response if successful:

{
  "members": [
    {
      "address": "[192.168.0.24]:5701",
      "liteMember": false,
      "localMember": true,
      "uuid": "3d8b9c35-a35f-461a-9e7f-d64e3f1f0f03",
      "memberVersion": "5.5.0"
    }
  ],
  "clientCount": 0,
  "allConnectionCount": 0,
  "state": "ACTIVE",
  "version": "5.5"
}

Retrieving Cluster State

You can send a GET request to the endpoint at /hazelcast/rest/api/v1/cluster/state to retrieve the state of your cluster.

Example request using cURL:

curl -X 'GET' \
  'http://localhost:8443/hazelcast/rest/api/v1/cluster/state' \
  -H 'Authorization: Bearer <JWT Token>'

It returns the following response if successful:

{
  "state": "ACTIVE"
}

Changing Cluster State

You can send a POST request to the endpoint at /hazelcast/rest/api/v1/cluster/state to change the state of your cluster. You must provide the new state within the request body in the JSON format. Valid states are ACTIVE, NO_MIGRATION, FROZEN, PASSIVE.

Example request using cURL:

curl -X 'POST' \
  'http://localhost:8443/hazelcast/rest/api/v1/cluster/state' \
  -H 'Authorization: Bearer Bearer <JWT Token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "state": "PASSIVE"
}'
  • It returns 200 response without body if successful.

  • It returns 400 response if provided state is not a valid cluster state. For example:

{
  "statusCode": 400,
  "message": "FOOBAR is not a valid ClusterState. Please provide one of the valid values: [ACTIVE, NO_MIGRATION, FROZEN, PASSIVE]"
}

Destroying a CP Group

You can send a DELETE request to the endpoint at /hazelcast/rest/api/v1/cp/groups/{group-name} to unconditionally destroy the given active CP group.

Example request using cURL:

curl -X 'DELETE' \
  'http://localhost:8443/hazelcast/rest/api/v1/cp/groups/my-group' \
  -H 'Authorization: Bearer Bearer <JWT Token>'
  • It returns 200 response without body if successful.

  • It returns 400 response if you try to destroy METADATA group. For example:

{
  "statusCode": 400,
  "message": "Meta data CP group [METADATA] cannot be destroyed!"
}
  • It returns 500 response if CP subsystem is not enabled:

{
  "statusCode": 500,
  "message": "CP Subsystem is not enabled!"
}

Dynamic Configuration Update REST Endpoint

You can use the /hazelcast/rest/api/v1/config/update REST endpoint to change dynamic server configurations (for more info, see Dynamic Configuration for Members). With dynamic configuration you can change existing configurations dynamically, as well as add new configurations for Hazelcast data structures.

The endpoint requires that you send a XML/YAML server configuration file with the changes required. The response will be two lists in JSON format. The first list includes the newly added configuration among the configurations sent to the server. The second list includes ignored configurations which were in the sent configuration list but could not be applied at the server (examples of these could include static rather than dynamic configurations, which can not therefore be applied dynamically, or duplicate configurations already added).

Whether a dynamic configuration can be applied or not depends on the request. For some updates, it is allowed to change configuration parameters of an existing configuration while for some others you are not allowed to change the configuration. Please see the Dynamic Configuration for Members section on details about which configuration parameters can be changed dynamically and which can not be changed.

Let’s walk through some example requests and responses.

Add New MapConfig Using XML Configuration

Here is an example POST request for adding a new MapConfig for my-map:

curl -X 'POST' \
  'http://localhost:8443/hazelcast/rest/api/v1/config/update' \
  -H 'Content-Type: text/plain' \
  -d '
        <hazelcast xmlns="http://www.hazelcast.com/schema/config">
                       <map name="my-map">
                           <in-memory-format>BINARY</in-memory-format>
                           <statistics-enabled>true</statistics-enabled>
                           <backup-count>2</backup-count>
                       </map>
        </hazelcast>
        '

This request creates a configuration for a new map named my-map. The in-memory format is set to BINARY, while statistics are enabled and the backup count is set to 2.

In response to this request we should receive a response body such as:

{
  "addedConfigs": [
    {
      "sectionName": "map",
      "configName": "my-map"
    }
  ],
  "ignoredConfigs": []
}

As the response indicates, a new map config is added to the map section with the name my-map and the requested dynamic configurations are applied.

Add New MapConfig Using YAML Configuration

Here is an example POST request for adding a new MapConfig for my-map-yaml using the YAML configuration:

curl -X 'POST' \
  'http://localhost:49567/hazelcast/rest/api/v1/cluster/config/update' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6IltcImFkbWluXCJdIiwiaWF0IjoxNzE3NTk3MDM1LCJleHAiOjE3MTc1OTc5MzV9.pYtBEvBy2KxrRfFOMSK3k9kS37SayEPCSEcYJlMpHMc' \
  -H 'Content-Type: application/json' \
  -d 'hazelcast:
  map:
    my-map-yaml:
      in-memory-format: BINARY
      statistics-enabled: true
      backup-count: 2'

We send a request to create a new config for the new map to be created named my-map-yaml. The in-memory format is set to BINARY while the statistics is enabled and the backup count is set to 2.

When we send this request we receive the response body similar to this:

{
  "addedConfigs": [
    {
      "sectionName": "map",
      "configName": "my-map-yaml"
    }
  ],
  "ignoredConfigs": []
}

As you can observe from the response, a new map config is added for map with name my-map-yaml and all the requested dynamic configurations are applied.

Add New Conflicting MapConfig For An Existing Map

If you like to add the config with the same map name and a different configuration, then you get response code 400 meaning an invalid configuration is provided since you can not change an existing map configuration. Let’s try this:

curl -X 'POST' \
  'http://localhost:8443/hazelcast/rest/api/v1/config/update' \
  -H 'Content-Type: text/plain' \
  -d '
        <hazelcast xmlns="http://www.hazelcast.com/schema/config">
                       <map name="my-map">
                           <statistics-enabled>false</statistics-enabled>
                       </map>
        </hazelcast>
        '

The response has a statusCode of 400, and the error message adds further detail:

{
  "statusCode": 400,
  "message": "Cannot add a dynamic configuration 'MapConfig{name='my-map', inMemoryFormat='BINARY', metadataPolicy=CREATE_ON_UPDATE, backupCount=1, asyncBackupCount=0, timeToLiveSeconds=0, maxIdleSeconds=0, readBackupData=false, evictionConfig=EvictionConfig{size=2147483647, maxSizePolicy=PER_NODE, evictionPolicy=NONE, comparatorClassName=null, comparator=null}, merkleTree=MerkleTreeConfig{enabled=null, depth=10}, eventJournal=EventJournalConfig{enabled=false, capacity=10000, timeToLiveSeconds=0}, hotRestart=HotRestartConfig{enabled=false, fsync=false}, dataPersistenceConfig=DataPersistenceConfig{enabled=false, fsync=false}, nearCacheConfig=null, mapStoreConfig=MapStoreConfig{enabled=false, className='null', factoryClassName='null', writeDelaySeconds=0, writeBatchSize=1, implementation=null, factoryImplementation=null, properties={}, initialLoadMode=LAZY, writeCoalescing=true, offload=true}, mergePolicyConfig=MergePolicyConfig{policy='com.hazelcast.spi.merge.PutIfAbsentMergePolicy', batchSize=100}, wanReplicationRef=null, entryListenerConfigs=null, indexConfigs=null, attributeConfigs=null, splitBrainProtectionName=null, queryCacheConfigs=null, cacheDeserializedValues=INDEX_ONLY, statisticsEnabled=false, entryStatsEnabled=false, tieredStoreConfig=TieredStoreConfig{enabled=false, memoryTierConfig=MemoryTierConfig{capacity=256 MEGABYTES}, diskTierConfig=DiskTierConfig{enabled=false, deviceName='default-tiered-store-device'}}, partitioningAttributeConfigs=null, userCodeNamespace=null}' as there is already a conflicting configuration 'MapConfig{name='my-map', inMemoryFormat='BINARY', metadataPolicy=CREATE_ON_UPDATE, backupCount=2, asyncBackupCount=0, timeToLiveSeconds=0, maxIdleSeconds=0, readBackupData=false, evictionConfig=EvictionConfig{size=2147483647, maxSizePolicy=PER_NODE, evictionPolicy=NONE, comparatorClassName=null, comparator=null}, merkleTree=MerkleTreeConfig{enabled=null, depth=10}, eventJournal=EventJournalConfig{enabled=false, capacity=10000, timeToLiveSeconds=0}, hotRestart=HotRestartConfig{enabled=false, fsync=false}, dataPersistenceConfig=DataPersistenceConfig{enabled=false, fsync=false}, nearCacheConfig=null, mapStoreConfig=MapStoreConfig{enabled=false, className='null', factoryClassName='null', writeDelaySeconds=0, writeBatchSize=1, implementation=null, factoryImplementation=null, properties={}, initialLoadMode=LAZY, writeCoalescing=true, offload=true}, mergePolicyConfig=MergePolicyConfig{policy='com.hazelcast.spi.merge.PutIfAbsentMergePolicy', batchSize=100}, wanReplicationRef=null, entryListenerConfigs=null, indexConfigs=null, attributeConfigs=null, splitBrainProtectionName=null, queryCacheConfigs=null, cacheDeserializedValues=INDEX_ONLY, statisticsEnabled=true, entryStatsEnabled=false, tieredStoreConfig=TieredStoreConfig{enabled=false, memoryTierConfig=MemoryTierConfig{capacity=256 MEGABYTES}, diskTierConfig=DiskTierConfig{enabled=false, deviceName='default-tiered-store-device'}}, partitioningAttributeConfigs=null, userCodeNamespace=null}'"
}

Within the response body you can see the explanation "as there is already a conflicting configuration 'MapConfig{name='my-map'".

Add New MapConfig For An Existing Map But With No Configuration Change

As detailed above, you cannot add a map configuration with the same map name. If you send an update request with the same configuration and map name, this request will be ignored as there is no change. Let’s look at this as an example:

curl -X 'POST' \
  'http://localhost:8443/hazelcast/rest/api/v1/config/update' \
  -H 'Content-Type: text/plain' \
  -d '
        <hazelcast xmlns="http://www.hazelcast.com/schema/config">
                       <map name="my-map">
                           <in-memory-format>BINARY</in-memory-format>
                           <statistics-enabled>true</statistics-enabled>
                           <backup-count>2</backup-count>
                       </map>
        </hazelcast>
        '

This request receives an OK (200) response code and the following body:

{
  "addedConfigs": [],
  "ignoredConfigs": [
    {
      "sectionName": "map",
      "configName": "my-map"
    }
  ]
}

As the response confirms, no configs are added and the provided config is ignored.

Add New MapConfig With Duplicate Configs

As you can see, you can not try adding a map config with the same map name. You can send an update request with the same configuration and map name, and you will observe that this update will be ignored since there is no change. Let’s try the request again:

curl -X 'POST' \
  'http://localhost:8443/hazelcast/rest/api/v1/config/update' \
  -H 'Content-Type: text/plain' \
  -d '
        <hazelcast xmlns="http://www.hazelcast.com/schema/config">
                       <map name="my-duplicate-map">
                           <statistics-enabled>true</statistics-enabled>
                       </map>
                       <map name="my-duplicate-map">
                           <statistics-enabled>true</statistics-enabled>
                       </map>
        </hazelcast>
        '

We receive a response code OK (200) and the following body:

{
  "addedConfigs": [
    {
      "sectionName": "map",
      "configName": "my-duplicate-map"
    }
  ],
  "ignoredConfigs": []
}

As you see from the response, only one MapConfig is added since the duplicate one has exactly the same configuration.

Try Adding Non-dynamic Static Configuration

You can try to change a static config, for example the cluster-name and observe that it is ignored silently. Since it is not a dynamic configuration, it is neither in ignored nor in the added configs list. An example request:

curl -X 'POST' \
  'http://localhost:8443/hazelcast/rest/api/v1/config/update' \
  -H 'Content-Type: text/plain' \
  -d '
        <hazelcast xmlns="http://www.hazelcast.com/schema/config">
                       <instance-name>newInstanceName</instance-name>
        </hazelcast>
        '

We receive a response code OK (200) and the following body:

{
  "addedConfigs": [],
  "ignoredConfigs": []
}

As you can see from the response, the static configuration is ignored but not listed in the ignored configurations list.