Add integration tests #2388
diff --git a/integration-tests/digitalocean/README.adoc b/integration-tests/digitalocean/README.adoc
index bad96cf..cf474c9 100644
--- a/integration-tests/digitalocean/README.adoc
+++ b/integration-tests/digitalocean/README.adoc
@@ -4,10 +4,11 @@
 
 To run `camel-quarkus-digitalocean` integration tests using Digitalocean API interactions, you will need a Digitalocean Token. Create a Digitalocean https://www.digitalocean.com/docs/apis-clis/api/create-personal-access-token/[Access Token].
 
-Then set the following environment variable:
+Then set the following environment variables:
 
 [source,shell]
 ----
 DIGITALOCEAN_AUTH_TOKEN=your-api-token
+DIGITALOCEAN_PUBLIC_KEY=your-public-key-to-run-key-tests
 ----
 
diff --git a/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanResource.java b/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanResource.java
index 6ba0357..246c57c 100644
--- a/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanResource.java
+++ b/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanResource.java
@@ -23,25 +23,40 @@
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
+import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import com.myjeeva.digitalocean.pojo.Account;
 import com.myjeeva.digitalocean.pojo.Action;
 import com.myjeeva.digitalocean.pojo.Backup;
+import com.myjeeva.digitalocean.pojo.Delete;
 import com.myjeeva.digitalocean.pojo.Droplet;
+import com.myjeeva.digitalocean.pojo.FloatingIP;
+import com.myjeeva.digitalocean.pojo.Image;
+import com.myjeeva.digitalocean.pojo.Key;
+import com.myjeeva.digitalocean.pojo.Region;
+import com.myjeeva.digitalocean.pojo.Size;
 import com.myjeeva.digitalocean.pojo.Snapshot;
+import com.myjeeva.digitalocean.pojo.Tag;
+import com.myjeeva.digitalocean.pojo.Volume;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.component.digitalocean.constants.DigitalOceanHeaders;
 import org.apache.camel.component.digitalocean.constants.DigitalOceanOperations;
 import org.jboss.logging.Logger;
 
-@Path("digitalocean/droplet")
+@SuppressWarnings("unchecked")
+@Path("digitalocean")
 @ApplicationScoped
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
 public class DigitaloceanResource {
 
     private static final Logger LOG = Logger.getLogger(DigitaloceanResource.class);
@@ -49,12 +64,13 @@
     private static final String DROPLET_SIZE_1_GB = "s-1vcpu-1gb";
     private static final String DROPLET_IMAGE = "ubuntu-20-04-x64";
     private static final List<String> DROPLET_TAGS = Arrays.asList("tag1", "tag2");
+    private static final int VOLUME_SIZE_5_GB = 5;
 
     @Inject
     ProducerTemplate producerTemplate;
 
     @PUT
-    @Path("{name}")
+    @Path("droplet/{name}")
     public int createDroplet(@PathParam("name") String name) {
         LOG.infof("creating a droplet with name %s", name);
         Map<String, Object> headers = createHeaders(name);
@@ -64,9 +80,6 @@
 
     /**
      * Creates the headers for operation `Create a Droplet`
-     * 
-     * @param  name
-     * @return
      */
     private Map<String, Object> createHeaders(String name) {
         Map<String, Object> headers = new HashMap<>();
@@ -80,7 +93,7 @@
     }
 
     @DELETE
-    @Path("{id}")
+    @Path("droplet/{id}")
     public Response deleteDroplet(@PathParam("id") int id) {
         LOG.infof("deleting a droplet with id %s", id);
         Map<String, Object> headers = new HashMap<>();
@@ -91,29 +104,27 @@
     }
 
     @GET
-    @Path("{id}")
+    @Path("droplet/{id}")
     public Droplet getDroplet(@PathParam("id") int id) {
         LOG.infof("getting droplet with id %s", id);
         Map<String, Object> headers = new HashMap<>();
         headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
         headers.put(DigitalOceanHeaders.ID, id);
-        Droplet droplet = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, Droplet.class);
-        return droplet;
+        return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, Droplet.class);
     }
 
     @GET
-    @Path("actions/{id}")
+    @Path("droplet/actions/{id}")
     public List<Action> getActions(@PathParam("id") int id) {
-        LOG.infof("getting actions's droplet with id %s", id);
+        LOG.infof("getting action's droplet with id %s", id);
         Map<String, Object> headers = new HashMap<>();
         headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listActions);
         headers.put(DigitalOceanHeaders.ID, id);
-        List<Action> actions = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
-        return actions;
+        return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
     }
 
     @POST
-    @Path("snapshot/{id}")
+    @Path("droplet/snapshot/{id}")
     public Action snapshotDroplet(@PathParam("id") int id, String snapshotName) {
         LOG.infof("snapshot droplet %s with name %s", id, snapshotName);
         Map<String, Object> headers = new HashMap<>();
@@ -124,53 +135,52 @@
     }
 
     @GET
-    @Path("snapshots/{id}")
+    @Path("droplet/snapshots/{id}")
     public List<Snapshot> getSnapshots(@PathParam("id") int id) {
         LOG.infof("getting snapshot's droplet with id %s", id);
         Map<String, Object> headers = new HashMap<>();
         headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listSnapshots);
         headers.put(DigitalOceanHeaders.ID, id);
-        List<Snapshot> snapshots = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
-        return snapshots;
+        return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
     }
 
     @GET
-    @Path("backups/enable/{id}")
+    @Path("droplet/backups/enable/{id}")
     public Action enableBackups(@PathParam("id") int id) {
         LOG.infof("Enable backups for droplet %s", id);
         return doAction(id, DigitalOceanOperations.enableBackups);
     }
 
     @GET
-    @Path("backups/disable/{id}")
+    @Path("droplet/backups/disable/{id}")
     public Action disableBackups(@PathParam("id") int id) {
         LOG.infof("disable backups for droplet %s", id);
         return doAction(id, DigitalOceanOperations.disableBackups);
     }
 
     @GET
-    @Path("on/{id}")
+    @Path("droplet/on/{id}")
     public Action turnOn(@PathParam("id") int id) {
         LOG.infof("Turn on droplet %s", id);
         return doAction(id, DigitalOceanOperations.powerOn);
     }
 
     @GET
-    @Path("off/{id}")
+    @Path("droplet/off/{id}")
     public Action turnOff(@PathParam("id") int id) {
         LOG.infof("Turn off droplet %s", id);
         return doAction(id, DigitalOceanOperations.powerOff);
     }
 
     @GET
-    @Path("reboot/{id}")
+    @Path("droplet/reboot/{id}")
     public Action rebootDroplet(@PathParam("id") int id) {
         LOG.infof("Reboot droplet %s", id);
         return doAction(id, DigitalOceanOperations.reboot);
     }
 
     @GET
-    @Path("ipv6/{id}")
+    @Path("droplet/ipv6/{id}")
     public Action enableIpv6(@PathParam("id") int id) {
         LOG.infof("Enable Ipv6 for droplet %s", id);
         return doAction(id, DigitalOceanOperations.enableIpv6);
@@ -184,35 +194,362 @@
     }
 
     @GET
-    @Path("backups/{id}")
+    @Path("droplet/backups/{id}")
     public List<Backup> getBackups(@PathParam("id") int id) {
-        LOG.infof("getting backups's droplet with id %s", id);
+        LOG.infof("getting backup's droplet with id %s", id);
         Map<String, Object> headers = new HashMap<>();
         headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listBackups);
         headers.put(DigitalOceanHeaders.ID, id);
-        List<Backup> backups = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
-        return backups;
+        return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
     }
 
     @GET
-    @Path("neighbors/{id}")
+    @Path("droplet/neighbors/{id}")
     public List<Droplet> getNeighbors(@PathParam("id") int id) {
-        LOG.infof("getting neighbors's droplet with id %s", id);
+        LOG.infof("getting neighbor's droplet with id %s", id);
         Map<String, Object> headers = new HashMap<>();
         headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listNeighbors);
         headers.put(DigitalOceanHeaders.ID, id);
-        List<Droplet> neighbors = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
-        return neighbors;
+        return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
     }
 
     @GET
-    @Path("neighbors")
+    @Path("droplet/neighbors")
     public List<Droplet> getAllNeighbors() {
         LOG.infof("getting all neighbors");
         Map<String, Object> headers = new HashMap<>();
         headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listAllNeighbors);
-        List<Droplet> neighbors = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
-        return neighbors;
+        return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
     }
 
+    @GET
+    @Path("account")
+    public Account getAccount() {
+        LOG.infof("getting the account");
+        return producerTemplate.requestBody("direct:account", null, Account.class);
+    }
+
+    @GET
+    @Path("action/{id}")
+    public Action getAction(@PathParam("id") Integer id) {
+        LOG.infof("getting the action %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.ID, id);
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+        return producerTemplate.requestBodyAndHeaders("direct:actions", null, headers, Action.class);
+    }
+
+    @GET
+    @Path("actions")
+    public List<Action> getActions() {
+        LOG.infof("getting all account's actions");
+        return producerTemplate.requestBodyAndHeader("direct:actions", null, DigitalOceanHeaders.OPERATION,
+                DigitalOceanOperations.list, List.class);
+    }
+
+    @GET
+    @Path("images")
+    public List<Image> getImages() {
+        LOG.infof("getting all account's images");
+        return producerTemplate.requestBodyAndHeader("direct:images", null, DigitalOceanHeaders.OPERATION,
+                DigitalOceanOperations.list, List.class);
+    }
+
+    @GET
+    @Path("images/{id}")
+    public Image getImageById(@PathParam("id") Integer id) {
+        LOG.infof("getting an image by id %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.ID, id);
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+        return producerTemplate.requestBodyAndHeaders("direct:images", null, headers, Image.class);
+    }
+
+    @GET
+    @Path("images/user")
+    public List<Image> getUserImages() {
+        LOG.infof("getting user's images");
+        return producerTemplate.requestBodyAndHeader("direct:images", null, DigitalOceanHeaders.OPERATION,
+                DigitalOceanOperations.ownList, List.class);
+    }
+
+    @GET
+    @Path("snapshots")
+    public List<Snapshot> getSnapshots() {
+        LOG.infof("getting all account's snapshots");
+        return producerTemplate.requestBodyAndHeader("direct:snapshots", null, DigitalOceanHeaders.OPERATION,
+                DigitalOceanOperations.list, List.class);
+    }
+
+    @GET
+    @Path("snapshots/{id}")
+    public Snapshot getSnapshotById(@PathParam("id") Integer id) {
+        LOG.infof("getting an snapshot by id %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.ID, id);
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+        return producerTemplate.requestBodyAndHeaders("direct:snapshots", null, headers, Snapshot.class);
+    }
+
+    @DELETE
+    @Path("snapshots/{id}")
+    public Response deleteSnapshot(@PathParam("id") Integer id) {
+        LOG.infof("delete snapshot %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+        headers.put(DigitalOceanHeaders.ID, id);
+        producerTemplate.sendBodyAndHeaders("direct:snapshots", null, headers);
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("sizes")
+    public List<Size> getSizes() {
+        LOG.infof("getting all available sizes");
+        return producerTemplate.requestBody("direct:sizes", null, List.class);
+    }
+
+    @GET
+    @Path("regions")
+    public List<Region> getRegions() {
+        LOG.infof("getting all available regions");
+        return producerTemplate.requestBody("direct:regions", null, List.class);
+    }
+
+    @PUT
+    @Path("floatingIP")
+    public String createFloatingIP(Integer dropletId) {
+        LOG.infof("create floating IP for droplet %s", dropletId);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.create);
+        headers.put(DigitalOceanHeaders.DROPLET_ID, dropletId);
+        // if pending task on droplet : API returns an exception. There should be a retry later
+        try {
+            FloatingIP floatingIP = producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers,
+                    FloatingIP.class);
+            return floatingIP.getIp();
+        } catch (Exception e) {
+            LOG.errorf("Enable to create and assign Floating IP - Please retry - error message : %s" + e.getMessage());
+        }
+        return "";
+    }
+
+    @GET
+    @Path("floatingIP/{id}")
+    public FloatingIP getFloatingIpById(@PathParam("id") String id) {
+        LOG.infof("get floating IP %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+        headers.put(DigitalOceanHeaders.FLOATING_IP_ADDRESS, id);
+        return producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers, FloatingIP.class);
+    }
+
+    @GET
+    @Path("floatingIP")
+    public List<FloatingIP> getAllFloatingIps() {
+        LOG.infof("get all floating IPs");
+        return producerTemplate.requestBodyAndHeader("direct:floatingIPs", null,
+                DigitalOceanHeaders.OPERATION, DigitalOceanOperations.list, List.class);
+    }
+
+    @GET
+    @Path("floatingIP/unassign/{id}")
+    public Action unassignFloatingIp(@PathParam("id") String id) {
+        LOG.infof("unassign floating IP %s");
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.unassign);
+        headers.put(DigitalOceanHeaders.FLOATING_IP_ADDRESS, id);
+        // if pending task on droplet : API returns an exception. There should be a retry later
+        try {
+            return producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers, Action.class);
+        } catch (Exception e) {
+            LOG.errorf("Enable to unassign Floating IP - Please retry - error message : %s" + e.getMessage());
+        }
+        return new Action();
+    }
+
+    @DELETE
+    @Path("floatingIP/{id}")
+    public Delete deleteFloatingIp(@PathParam("id") String id) {
+        LOG.infof("delete floating IP %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+        headers.put(DigitalOceanHeaders.FLOATING_IP_ADDRESS, id);
+        // if pending task on droplet : API returns an exception. There should be a retry later
+        try {
+            return producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers, Delete.class);
+        } catch (Exception e) {
+            LOG.errorf("Enable to delete Floating IP - Please retry - error message : %s" + e.getMessage());
+        }
+        return new Delete(false);
+
+    }
+
+    @GET
+    @Path("floatingIP/actions/{id}")
+    public List<Action> getFloatingIpsActions(@PathParam("id") String id) {
+        LOG.infof("get all floating IPs actions %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listActions);
+        headers.put(DigitalOceanHeaders.FLOATING_IP_ADDRESS, id);
+        return (List<Action>) producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers, List.class);
+    }
+
+    @PUT
+    @Path("blockStorages")
+    public String createVolume(String name) {
+        LOG.infof("create volume for region %s with size %s named %s", REGION_FRANKFURT, VOLUME_SIZE_5_GB, name);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.create);
+        headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+        headers.put(DigitalOceanHeaders.VOLUME_SIZE_GIGABYTES, VOLUME_SIZE_5_GB);
+        headers.put(DigitalOceanHeaders.NAME, name);
+        headers.put(DigitalOceanHeaders.DESCRIPTION, "volume_" + name);
+        Volume volume = producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Volume.class);
+        return volume.getId();
+    }
+
+    @GET
+    @Path("blockStorages/{id}")
+    public Volume getVolumeById(@PathParam("id") String volumeId) {
+        LOG.infof("getting volume %s", volumeId);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+        headers.put(DigitalOceanHeaders.ID, volumeId);
+        headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+        return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Volume.class);
+    }
+
+    @POST
+    @Path("blockStorages/attach/{name}")
+    public Action attachVolumeToDroplet(@PathParam("name") String volumeName, String dropletId) {
+        LOG.infof("attach volume %s to droplet %s in region %s", volumeName, dropletId, REGION_FRANKFURT);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.attach);
+        headers.put(DigitalOceanHeaders.VOLUME_NAME, volumeName);
+        headers.put(DigitalOceanHeaders.DROPLET_ID, dropletId);
+        headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+        return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Action.class);
+    }
+
+    @POST
+    @Path("blockStorages/detach/{name}")
+    public Action detachVolumeToDroplet(@PathParam("name") String volumeName, String dropletId) {
+        LOG.infof("detach volume %s to droplet %s in region %s", volumeName, dropletId, REGION_FRANKFURT);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.detach);
+        headers.put(DigitalOceanHeaders.VOLUME_NAME, volumeName);
+        headers.put(DigitalOceanHeaders.DROPLET_ID, dropletId);
+        headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+        return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Action.class);
+    }
+
+    @GET
+    @Path("blockStorages")
+    public List<Volume> getAvailableVolumes() {
+        LOG.infof("get all avalaible volumes for region %s", REGION_FRANKFURT);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.list);
+        headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+        return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, List.class);
+    }
+
+    @DELETE
+    @Path("blockStorages")
+    public Delete deleteVolume(String volumeId) {
+        LOG.infof("delete volume %s", volumeId);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+        headers.put(DigitalOceanHeaders.ID, volumeId);
+        return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Delete.class);
+    }
+
+    @PUT
+    @Path("keys/{name}")
+    public Integer createKey(@PathParam("name") String name, String publicKey) {
+        LOG.infof("create key %s", name);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.create);
+        headers.put(DigitalOceanHeaders.NAME, name);
+        headers.put(DigitalOceanHeaders.KEY_PUBLIC_KEY, publicKey);
+        Key key = producerTemplate.requestBodyAndHeaders("direct:keys", null, headers, Key.class);
+        return key.getId();
+    }
+
+    @GET
+    @Path("keys/{id}")
+    public Key getKeyById(@PathParam("id") Integer id) {
+        LOG.infof("get key %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+        headers.put(DigitalOceanHeaders.ID, id);
+        return producerTemplate.requestBodyAndHeaders("direct:keys", null, headers, Key.class);
+    }
+
+    @GET
+    @Path("keys")
+    public List<Key> getKeys() {
+        LOG.infof("get keys");
+        return producerTemplate.requestBodyAndHeader("direct:keys", null, DigitalOceanHeaders.OPERATION,
+                DigitalOceanOperations.list, List.class);
+    }
+
+    @POST
+    @Path("keys/{id}")
+    public Key updateKey(@PathParam("id") Integer id, String name) {
+        LOG.infof("update key %s with name %s", id, name);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.update);
+        headers.put(DigitalOceanHeaders.ID, id);
+        headers.put(DigitalOceanHeaders.NAME, name);
+        return producerTemplate.requestBodyAndHeaders("direct:keys", null, headers, Key.class);
+    }
+
+    @DELETE
+    @Path("keys/{id}")
+    public Delete deleteKey(@PathParam("id") Integer id) {
+        LOG.infof("delete key %s", id);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+        headers.put(DigitalOceanHeaders.ID, id);
+        return producerTemplate.requestBodyAndHeaders("direct:keys", null, headers, Delete.class);
+    }
+
+    @POST
+    @Path("tags/{name}")
+    public Tag createTag(@PathParam("name") String name) {
+        LOG.infof("create tag %s", name);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.create);
+        headers.put(DigitalOceanHeaders.NAME, name);
+        return producerTemplate.requestBodyAndHeaders("direct:tags", null, headers, Tag.class);
+    }
+
+    @GET
+    @Path("tags/{name}")
+    public Tag getTag(@PathParam("name") String name) {
+        LOG.infof("get tag %s", name);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+        headers.put(DigitalOceanHeaders.NAME, name);
+        return producerTemplate.requestBodyAndHeaders("direct:tags", null, headers, Tag.class);
+    }
+
+    @GET
+    @Path("tags")
+    public List<Tag> getAllTags() {
+        LOG.infof("get tags");
+        return producerTemplate.requestBodyAndHeader("direct:tags", null, DigitalOceanHeaders.OPERATION,
+                DigitalOceanOperations.list, List.class);
+    }
+
+    @DELETE
+    @Path("tags/{name}")
+    public Delete deleteTag(@PathParam("name") String name) {
+        LOG.infof("delete tag %s", name);
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+        headers.put(DigitalOceanHeaders.NAME, name);
+        return producerTemplate.requestBodyAndHeaders("direct:tags", null, headers, Delete.class);
+    }
 }
diff --git a/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanRoute.java b/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanRoute.java
index 29b1fa3..243ad0a 100644
--- a/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanRoute.java
+++ b/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanRoute.java
@@ -53,5 +53,34 @@
         from("direct:droplet")
                 .toF("digitalocean:droplets?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
 
+        from("direct:account")
+                .toF("digitalocean:account?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:actions")
+                .toF("digitalocean:actions?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:images")
+                .toF("digitalocean:images?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:snapshots")
+                .toF("digitalocean:snapshots?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:sizes")
+                .toF("digitalocean:sizes?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:regions")
+                .toF("digitalocean:regions?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:floatingIPs")
+                .toF("digitalocean:floatingIPs?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:blockStorages")
+                .toF("digitalocean:blockStorages?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:keys")
+                .toF("digitalocean:keys?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+        from("direct:tags")
+                .toF("digitalocean:tags?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
     }
 }
diff --git a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletIT.java b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletIT.java
new file mode 100644
index 0000000..a371fa8
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletIT.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.digitalocean.it;
+
+import io.quarkus.test.junit.NativeImageTest;
+
+@NativeImageTest
+public class DigitaloceanDropletIT extends DigitaloceanDropletTest {
+}
diff --git a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletTest.java b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletTest.java
new file mode 100644
index 0000000..5f00d2e
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletTest.java
@@ -0,0 +1,451 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.digitalocean.it;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.apache.camel.quarkus.test.wiremock.MockServer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.given;
+import static org.awaitility.Awaitility.await;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SuppressWarnings("unchecked")
+@QuarkusTest
+@QuarkusTestResource(DigitaloceanTestResource.class)
+public class DigitaloceanDropletTest {
+    static final long timeout = 5;
+    static TimeUnit timeoutUnit = TimeUnit.SECONDS;
+    static boolean waitBlockStorageAction = false;
+
+    @MockServer
+    WireMockServer server;
+
+    @BeforeAll
+    public static void initTimeoutUnit() {
+        // add timeout if not using MockServer
+        // when using a Digitalocean Key, it takes at least 2 minutes to create a droplet or snapshot
+        String key = System.getenv("DIGITALOCEAN_AUTH_TOKEN");
+        if (key != null) {
+            timeoutUnit = TimeUnit.MINUTES;
+            waitBlockStorageAction = true;
+        }
+    }
+
+    /**
+     * Testing droplet producer and all tests of producers related to an existing droplet
+     *
+     */
+    @Test
+    void testDroplets() throws InterruptedException {
+        // insert multiple droplets
+        Integer dropletId = RestAssured.given().contentType(ContentType.JSON).put("/digitalocean/droplet/droplet1")
+                .then().extract().body().as(Integer.class);
+        assertNotNull(dropletId);
+
+        // get the droplet by dropletId1 until its status is active and ready
+        // it takes time only if using a oAuthToken from Digitalocean
+        waitActiveDroplet(dropletId);
+
+        // test actions on droplet
+        performActions(dropletId);
+
+        // test actions
+        testResultActions(dropletId);
+
+        // test neighbors
+        testNeighbors(dropletId);
+
+        // test floating IP
+        testFloatingIP(dropletId);
+
+        // test images
+        testImages();
+
+        // test snapshots
+        testSnapshots();
+
+        // test block storages
+        testBlockStorages(dropletId);
+
+        // delete the droplet with id droplet 1
+        given()
+                .when()
+                .delete("/digitalocean/droplet/" + dropletId)
+                .then()
+                .statusCode(202);
+    }
+
+    private void performActions(Integer dropletId) {
+        // action : enable backups
+        given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/droplet/backups/enable/" + dropletId)
+                .then()
+                .body("resourceId", equalTo(dropletId))
+                .body("type", equalTo("ENABLE_BACKUPS"));
+
+        // action : power off, before taking a snapshot
+        given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/droplet/off/" + dropletId)
+                .then()
+                .body("resourceId", equalTo(dropletId));
+
+        // take a snapshot
+        given()
+                .contentType(ContentType.JSON)
+                .body("snapshot1")
+                .post("/digitalocean/droplet/snapshot/" + dropletId)
+                .then()
+                .body("resourceId", equalTo(dropletId));
+
+        waitForSnapshot(dropletId);
+
+        // action : disable backups
+        given()
+                .when()
+                .get("/digitalocean/droplet/backups/disable/" + dropletId)
+                .then()
+                .body("resourceId", equalTo(dropletId));
+
+        // action : power on
+        given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/droplet/on/" + dropletId)
+                .then()
+                .body("resourceId", equalTo(dropletId));
+
+        // Reboot droplet
+        given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/droplet/reboot/" + dropletId)
+                .then()
+                .body("resourceId", equalTo(dropletId));
+
+        // enable Ipv6
+        given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/droplet/ipv6/" + dropletId)
+                .then()
+                .body("resourceId", equalTo(dropletId));
+    }
+
+    /**
+     * Test the result of actions performed
+     *
+     */
+    private void testResultActions(Integer dropletId) {
+        // getting the droplet actions
+        List<Map<String, Object>> actions = RestAssured.given().contentType(ContentType.JSON)
+                .get("/digitalocean/droplet/actions/" + dropletId)
+                .then().extract().body().as(List.class);
+        List<String> types = Arrays.asList("ENABLE_BACKUPS", "DISABLE_BACKUPS", "SNAPSHOT", "POWER_ON", "POWER_OFF", "REBOOT",
+                "ENABLE_IPV6");
+        assertActions(actions, types);
+
+        // getting the snapshot action id
+        Integer snapshotActionId = getSnapshotActionId(actions);
+
+        // getting one action
+        given()
+                .get("/digitalocean/action/" + snapshotActionId)
+                .then()
+                .body("id", equalTo(snapshotActionId));
+
+        // getting all actions on the account
+        actions = RestAssured.given().contentType(ContentType.JSON)
+                .get("/digitalocean/actions/")
+                .then().extract().body().as(List.class);
+        types = Arrays.asList("ENABLE_BACKUPS", "DISABLE_BACKUPS", "SNAPSHOT", "POWER_ON", "POWER_OFF", "REBOOT");
+        assertActions(actions, types);
+    }
+
+    /**
+     * Gets the snapshots and waits until the snapshot is created in Digitalocean.
+     *
+     */
+    private void waitForSnapshot(Integer dropletId) {
+        await().atMost(timeout, timeoutUnit).until(() -> {
+            String path = "/digitalocean/droplet/snapshots/" + dropletId;
+            List<Map<String, Object>> result = given().when().get(path).then().extract().as(List.class);
+            // Look for the snapshot
+            Optional<Map<String, Object>> optional = result.stream()
+                    .filter(s -> "snapshot1".equals(s.get("name")))
+                    .findAny();
+            return optional.isPresent();
+        });
+    }
+
+    /**
+     * Gets the droplet and waits until the droplet is Active in Digitalocean.
+     *
+     */
+    private void waitActiveDroplet(Integer dropletId) {
+        await().atMost(timeout, timeoutUnit).until(() -> {
+            String path = "/digitalocean/droplet/" + dropletId;
+            Map<String, Object> droplet = given()
+                    .contentType(ContentType.JSON).get(path).then().extract().as(Map.class);
+            return droplet != null && dropletId.equals(droplet.get("id")) && "ACTIVE".equals(droplet.get("status"));
+        });
+    }
+
+    /**
+     * Assert all the actions
+     *
+     */
+    private void assertActions(List<Map<String, Object>> actions, List<String> types) {
+        // verify there are actions
+        assertNotNull(actions);
+        // verify there are at least the 7 created actions in the test
+        assertTrue(actions.size() >= types.size());
+        types.forEach(type -> assertAction(actions, type));
+    }
+
+    /**
+     * assert a single action
+     *
+     */
+    private void assertAction(List<Map<String, Object>> actions, String actionType) {
+        Optional<Map<String, Object>> optional = actions.stream()
+                .filter(a -> actionType.equals(a.get("type")))
+                .findAny();
+        assertTrue(optional.isPresent());
+    }
+
+    /**
+     * Get action of type SNAPSHOT
+     *
+     */
+    private Integer getSnapshotActionId(List<Map<String, Object>> actions) {
+        return actions.stream()
+                .filter(a -> "SNAPSHOT".equals(a.get("type")))
+                .findAny()
+                .map(b -> (Integer) b.get("id"))
+                .orElse(null);
+    }
+
+    private void testNeighbors(int dropletId) {
+        given()
+                .when()
+                .get("/digitalocean/droplet/neighbors/" + dropletId)
+                .then()
+                .statusCode(200);
+    }
+
+    private void testImages() {
+        // getting all images
+        List<Map<String, Object>> images = RestAssured.given().contentType(ContentType.JSON)
+                .get("/digitalocean/images")
+                .then().extract().body().as(List.class);
+        // there's at least the image created for the backup
+        assertNotNull(images);
+
+        // get one image id
+        Integer imageId = images.stream().findAny().map(image -> (Integer) image.get("id")).orElse(null);
+        assertNotNull(imageId);
+
+        // get the image with id
+        given().contentType(ContentType.JSON)
+                .get("/digitalocean/images/" + imageId)
+                .then()
+                .body("id", equalTo(imageId));
+
+        // test user's images
+        images = RestAssured.given().contentType(ContentType.JSON)
+                .get("/digitalocean/images/user")
+                .then().extract().body().as(List.class);
+        assertNotNull(images);
+    }
+
+    private void testSnapshots() {
+        // getting all snapshots
+        List<Map<String, Object>> images = RestAssured.given().contentType(ContentType.JSON)
+                .get("/digitalocean/snapshots")
+                .then().extract().body().as(List.class);
+        // there's at least the image created for the backup
+        assertNotNull(images);
+
+        // get one snapshot id
+        Integer snapshotId = images.stream().findAny().map(snapshot -> (Integer) snapshot.get("id")).orElse(null);
+        assertNotNull(snapshotId);
+
+        // get the snapshot with id
+        given().contentType(ContentType.JSON)
+                .get("/digitalocean/snapshots/" + snapshotId)
+                .then()
+                .body("id", equalTo(snapshotId));
+
+        // delete snapshot
+        given().contentType(ContentType.JSON)
+                .delete("/digitalocean/snapshots/" + snapshotId)
+                .then()
+                .statusCode(200);
+    }
+
+    private void testFloatingIP(Integer dropletId) {
+        AtomicReference<String> floatingIp = new AtomicReference<>();
+        // create a floating IP for the droplet
+        await().atMost(timeout, timeoutUnit).until(() -> {
+            floatingIp.set(given().contentType(ContentType.JSON)
+                    .body(dropletId)
+                    .put("/digitalocean/floatingIP")
+                    .then().extract().body().asString());
+            return !floatingIp.get().equals("");
+        });
+
+        // gets the floating IP
+        given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/floatingIP/" + floatingIp)
+                .then()
+                .body("ip", equalTo(floatingIp.get()));
+
+        // gets all the floating IP
+        List<Map<String, Object>> floatingIps = given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/floatingIP")
+                .then().extract().body().as(List.class);
+        Optional<Map<String, Object>> floatingIpResult = floatingIps.stream()
+                .filter(f -> floatingIp.get().equals(f.get("ip")))
+                .findAny();
+        assertTrue(floatingIpResult.isPresent());
+
+        // unassign a floating IP
+        final Map<String, Object>[] action = new Map[1];
+        await().atMost(timeout, timeoutUnit).until(() -> {
+            action[0] = given()
+                    .contentType(ContentType.JSON)
+                    .get("/digitalocean/floatingIP/unassign/" + floatingIp)
+                    .then().extract().body().as(Map.class);
+            return action[0] != null && "UNASSIGN_FLOATING_IP".equals(action[0].get("type"));
+        });
+        Integer actionId = (Integer) action[0].get("id");
+
+        // get all action of a floating IP
+        List<Map<String, Object>> actions = given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/floatingIP/actions/" + floatingIp)
+                .then().extract().body().as(List.class);
+        assertNotNull(actions);
+        Optional<Map<String, Object>> actionUnassign = actions.stream()
+                .filter(a -> actionId.equals(a.get("id")))
+                .findAny();
+        assertTrue(actionUnassign.isPresent());
+
+        // delete a floating ip
+        await().atMost(timeout, timeoutUnit).until(() -> {
+            Map<String, Object> delete = given()
+                    .contentType(ContentType.JSON)
+                    .delete("/digitalocean/floatingIP/" + floatingIp)
+                    .then().extract().body().as(Map.class);
+            return delete != null && (Boolean) delete.get("isRequestSuccess");
+        });
+    }
+
+    private void testBlockStorages(Integer dropletId) throws InterruptedException {
+        // create a volume
+        String volumeId = given()
+                .contentType(ContentType.JSON)
+                .body("volume1")
+                .when()
+                .put("/digitalocean/blockStorages")
+                .then().extract().body().asString();
+        assertNotNull(volumeId);
+
+        // get the volume
+        given()
+                .get("/digitalocean/blockStorages/" + volumeId)
+                .then()
+                .body("name", equalTo("volume1"));
+
+        // get all volumes in the region FRA1
+        List<Map<String, Object>> volumes = given()
+                .get("/digitalocean/blockStorages")
+                .then()
+                .extract().body().as(List.class);
+        assertNotNull(volumes);
+        Map<String, Object> expectedResult = volumes.stream()
+                .filter(v -> "volume1".equals(v.get("name")))
+                .findAny().orElse(null);
+        assertNotNull(expectedResult);
+
+        // attach to droplet
+        given()
+                .contentType(ContentType.JSON)
+                .body(dropletId)
+                .when()
+                .post("/digitalocean/blockStorages/attach/volume1")
+                .then()
+                .body("type", equalTo("ATTACH"));
+
+        // wait until the volume is attached : or else it's impossible to detach
+        waitAttachedVolume(dropletId, volumeId);
+
+        // detach from droplet
+        given()
+                .contentType(ContentType.JSON)
+                .body(dropletId)
+                .when()
+                .post("/digitalocean/blockStorages/detach/volume1")
+                .then()
+                .statusCode(200);
+
+        // wait until detach action is performed :: only when using digitalocean
+        // if the volume is droped before being detached, there's an error in delete action, and it will be impossible to get the drop result
+        if (waitBlockStorageAction) {
+            Thread.sleep(10000);
+        }
+
+        // drop the volume
+        given()
+                .contentType(ContentType.JSON)
+                .body(volumeId)
+                .when()
+                .delete("/digitalocean/blockStorages")
+                .then()
+                .body("isRequestSuccess", equalTo(true));
+
+    }
+
+    /**
+     * Gets the droplet and waits until the volume is attached to the droplet
+     *
+     */
+    private void waitAttachedVolume(Integer dropletId, String volumeId) {
+        await().atMost(timeout, timeoutUnit).until(() -> {
+            String path = "/digitalocean/droplet/" + dropletId;
+            Map<String, Object> droplet = given()
+                    .contentType(ContentType.JSON).get(path).then().extract().as(Map.class);
+            return droplet.get("volumeIds") != null && ((List<String>) droplet.get("volumeIds")).contains(volumeId);
+        });
+    }
+}
diff --git a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTest.java b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTest.java
index c401351..0578458 100644
--- a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTest.java
+++ b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTest.java
@@ -16,11 +16,9 @@
  */
 package org.apache.camel.quarkus.component.digitalocean.it;
 
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.concurrent.TimeUnit;
 
 import com.github.tomakehurst.wiremock.WireMockServer;
 import io.quarkus.test.common.QuarkusTestResource;
@@ -28,182 +26,144 @@
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
 import org.apache.camel.quarkus.test.wiremock.MockServer;
+import org.hamcrest.CoreMatchers;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
 import static io.restassured.RestAssured.given;
-import static org.awaitility.Awaitility.await;
-import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+@SuppressWarnings("unchecked")
 @QuarkusTest
 @QuarkusTestResource(DigitaloceanTestResource.class)
 class DigitaloceanTest {
-
+    static String publicKey;
     @MockServer
     WireMockServer server;
 
-    static long timeout = 5;
-    static TimeUnit timeoutUnit = TimeUnit.SECONDS;
-
     @BeforeAll
-    public static void initTimeoutUnit() {
-        // add timeout if not using MockServer
-        // when using a Digitalocean Key, it takes at least 2 minutes to create a droplet or snapshot
-        String key = System.getenv("DIGITALOCEAN_AUTH_TOKEN");
+    public static void initPublicKey() {
+        String key = System.getenv("DIGITALOCEAN_PUBLIC_KEY");
         if (key != null) {
-            timeoutUnit = TimeUnit.MINUTES;
+            publicKey = key;
+        } else {
+            publicKey = "ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example";
         }
     }
 
     @Test
-    void testDroplets() {
-        // insert multiple droplets
-        Integer dropletId = RestAssured.given().contentType(ContentType.JSON).put("/digitalocean/droplet/droplet1")
-                .then().extract().body().as(Integer.class);
-        assertNotNull(dropletId);
-
-        // get the droplet by dropletId1 until its status is active and ready
-        // it takes time only if using a oAuthToken from Digitalocean
-        waitActiveDroplet(dropletId);
-
-        // action : enable backups
-        given()
-                .contentType(ContentType.JSON)
-                .get("/digitalocean/droplet/backups/enable/" + dropletId)
-                .then()
-                .body("resourceId", equalTo(dropletId))
-                .body("type", equalTo("ENABLE_BACKUPS"));
-
-        // action : power off, before taking a snapshot
-        given()
-                .contentType(ContentType.JSON)
-                .get("/digitalocean/droplet/off/" + dropletId)
-                .then()
-                .body("resourceId", equalTo(dropletId));
-
-        // take a snapshot
-        given()
-                .contentType(ContentType.JSON)
-                .body("snapshot1")
-                .post("/digitalocean/droplet/snapshot/" + dropletId)
-                .then()
-                .body("resourceId", equalTo(dropletId));
-
-        // action : disable backups
+    void testAccount() {
         given()
                 .when()
-                .get("/digitalocean/droplet/backups/disable/" + dropletId)
+                .get("/digitalocean/account/")
                 .then()
-                .body("resourceId", equalTo(dropletId));
+                .body("uuid", notNullValue());
+    }
 
-        // wait for Droplet to be active
-        waitActiveDroplet(dropletId);
-
-        // action : power on
-        given()
-                .contentType(ContentType.JSON)
-                .get("/digitalocean/droplet/on/" + dropletId)
-                .then()
-                .body("resourceId", equalTo(dropletId));
-
-        // Reboot droplet
-        given()
-                .contentType(ContentType.JSON)
-                .get("/digitalocean/droplet/reboot/" + dropletId)
-                .then()
-                .body("resourceId", equalTo(dropletId));
-
-        // enable Ipv6
-        given()
-                .contentType(ContentType.JSON)
-                .get("/digitalocean/droplet/ipv6/" + dropletId)
-                .then()
-                .body("resourceId", equalTo(dropletId));
-
-        // getting the droplet actions
-        List<Map> actions = RestAssured.given().contentType(ContentType.JSON)
-                .get("/digitalocean/droplet/actions/" + dropletId)
+    @Test
+    void testSizes() {
+        List<Map<String, Object>> sizes = RestAssured.given().contentType(ContentType.JSON)
+                .get("/digitalocean/sizes")
                 .then().extract().body().as(List.class);
-        assertActions(actions);
+        assertNotNull(sizes);
+        Optional<Map<String, Object>> size_1Gb = sizes.stream()
+                .filter(s -> "s-1vcpu-1gb".equals(s.get("slug")))
+                .findFirst();
+        assertTrue(size_1Gb.isPresent());
+    }
 
-        // test neigbors
-        testNeighbors(dropletId);
+    @Test
+    void testRegions() {
+        List<Map<String, Object>> regions = RestAssured.given().contentType(ContentType.JSON)
+                .get("/digitalocean/regions")
+                .then().extract().body().as(List.class);
+        assertNotNull(regions);
+        Optional<Map<String, Object>> nyc1Region = regions.stream()
+                .filter(r -> "nyc1".equals(r.get("slug")))
+                .findFirst();
+        assertTrue(nyc1Region.isPresent());
+    }
 
-        // delete the droplet with id droplet 1
+    @Test
+    void testKeys() {
+        // create a key
+        String name = "TestKey1";
+
+        Integer publicKeyId = given()
+                .contentType(ContentType.JSON)
+                .body(publicKey)
+                .put("/digitalocean/keys/" + name)
+                .then().extract().body().as(Integer.class);
+
+        // get the key
         given()
-                .when()
-                .delete("/digitalocean/droplet/" + dropletId)
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/keys/" + publicKeyId)
                 .then()
-                .statusCode(202);
+                .body("id", equalTo(publicKeyId))
+                .body("name", equalTo(name));
 
-    }
+        // update key
+        name = "updated_TestKey1";
+        given()
+                .contentType(ContentType.JSON)
+                .body(name)
+                .post("/digitalocean/keys/" + publicKeyId)
+                .then()
+                .body("id", equalTo(publicKeyId))
+                .body("name", equalTo(name));
 
-    /**
-     * Gets the snapshots and waits until the snapshot is created in Digitalocean.
-     *
-     * @param dropletId
-     */
-    private void waitForSnapshot(Integer dropletId) {
-        await().atMost(this.timeout, this.timeoutUnit).until(() -> {
-            String path = "/digitalocean/droplet/snapshots/" + dropletId;
-            List<Map> result = given().when().get(path).then().extract().as(List.class);
-            // Look for the snapshot
-            Optional optional = result.stream()
-                    .filter(s -> "snapshot1".equals(s.get("name")))
-                    .findAny();
-            return optional.isPresent();
-        });
-    }
-
-    /**
-     * Gets the droplet and waits until the droplet is Active in Digitalocean.
-     *
-     * @param dropletId
-     */
-    private void waitActiveDroplet(Integer dropletId) {
-        await().atMost(this.timeout, this.timeoutUnit).until(() -> {
-            String path = "/digitalocean/droplet/" + dropletId;
-            Map droplet = given()
-                    .contentType(ContentType.JSON).get(path).then().extract().as(Map.class);
-            return droplet != null && dropletId.equals(droplet.get("id")) && "ACTIVE".equals(droplet.get("status"));
-        });
-    }
-
-    /**
-     * Assert all the actions
-     *
-     * @param actions
-     */
-    private void assertActions(List<Map> actions) {
-        // verify there are actions
-        assertNotNull(actions);
-        // verify there are at least the 7 created actions in the test
-        assertTrue(actions.size() >= 7);
-        List<String> types = Arrays.asList("ENABLE_BACKUPS", "DISABLE_BACKUPS", "SNAPSHOT", "POWER_ON", "POWER_OFF", "REBOOT",
-                "ENABLE_IPV6");
-        types.forEach(type -> assertAction(actions, type));
-    }
-
-    /**
-     * assert a single action
-     *
-     * @param actions
-     * @param actionType
-     */
-    private void assertAction(List<Map> actions, String actionType) {
-        Optional<Map> optional = actions.stream()
-                .filter(a -> actionType.equals(a.get("type")))
+        // List keys
+        List<Map<String, Object>> keys = given()
+                .get("/digitalocean/keys")
+                .then().extract().body().as(List.class);
+        Optional<Map<String, Object>> resultKey = keys.stream()
+                .filter(m -> publicKeyId.equals(m.get("id")))
                 .findAny();
-        assertTrue(optional.isPresent());
+        assertTrue(resultKey.isPresent());
+
+        // delete the key
+        given()
+                .delete("/digitalocean/keys/" + publicKeyId)
+                .then()
+                .body("isRequestSuccess", CoreMatchers.equalTo(true));
+
     }
 
-    void testNeighbors(int dropletId) {
+    @Test
+    void testTags() {
+        // create a tag
+        String name = "awesome";
         given()
-                .when()
-                .get("/digitalocean/droplet/neighbors/" + dropletId)
+                .contentType(ContentType.JSON)
+                .post("/digitalocean/tags/" + name)
                 .then()
-                .statusCode(200);
+                .body("name", equalTo(name));
+
+        // get a tag
+        given()
+                .get("/digitalocean/tags/" + name)
+                .then()
+                .body("name", equalTo(name));
+
+        // get all tags
+        List<Map<String, Object>> tags = given()
+                .contentType(ContentType.JSON)
+                .get("/digitalocean/tags/")
+                .then().extract().body().as(List.class);
+        Optional<Map<String, Object>> resultKey = tags.stream()
+                .filter(t -> name.equals(t.get("name")))
+                .findAny();
+        assertTrue(resultKey.isPresent());
+
+        // delete the tag
+        given()
+                .delete("/digitalocean/tags/" + name)
+                .then()
+                .body("isRequestSuccess", CoreMatchers.equalTo(true));
+
     }
 }
diff --git a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTestResource.java b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTestResource.java
index 1d08000..7e31a36 100644
--- a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTestResource.java
+++ b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTestResource.java
@@ -22,6 +22,7 @@
 public class DigitaloceanTestResource extends WireMockTestResourceLifecycleManager {
     private static final String DIGITALOCEAN_BASE_URL = "api.digitalocean.com";
     private static final String DIGITALOCEAN_AUTH_TOKEN = "DIGITALOCEAN_AUTH_TOKEN";
+    private static final String DIGITALOCEAN_PUBLIC_KEY = "DIGITALOCEAN_PUBLIC_KEY";
 
     @Override
     protected String getRecordTargetBaseUrl() {
@@ -30,7 +31,7 @@
 
     @Override
     protected boolean isMockingEnabled() {
-        return !envVarsPresent(DIGITALOCEAN_AUTH_TOKEN);
+        return !envVarsPresent(DIGITALOCEAN_AUTH_TOKEN, DIGITALOCEAN_PUBLIC_KEY);
     }
 
     @Override
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/account.json b/integration-tests/digitalocean/src/test/resources/mappings/account.json
new file mode 100644
index 0000000..0c083a5
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/account.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/account?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"account\":{\"droplet_limit\":25,\"floating_ip_limit\":5,\"volume_limit\":10,\"email\":\"sammy@digitalocean.com\",\"uuid\":\"b6fr89dbf6d9156cace5f3c78dc9851d957381ef\",\"email_verified\":true,\"status\":\"active\",\"status_message\":\"\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/action.json b/integration-tests/digitalocean/src/test/resources/mappings/action.json
new file mode 100644
index 0000000..d83f90b
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/action.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/actions/36805187?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"action\":{\"id\":36805187,\"status\":\"completed\",\"type\":\"create\",\"started_at\":\"2014-11-14T16:29:21Z\",\"completed_at\":\"2014-11-14T16:30:06Z\",\"resource_id\":3164444,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/actionFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/actionFloatingIp.json
new file mode 100644
index 0000000..46372d5
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/actionFloatingIp.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/floating_ips/45.55.96.47/actions",
+    "method": "POST"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"action\":{\"id\":68212773,\"status\":\"in-progress\",\"type\":\"unassign_ip\",\"started_at\":\"2015-10-15T17:46:15Z\",\"completed_at\":null,\"resource_id\":758603823,\"resource_type\":\"floating_ip\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"region_slug\":\"nyc3\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/actions.json b/integration-tests/digitalocean/src/test/resources/mappings/actions.json
new file mode 100644
index 0000000..7bd5c9b
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/actions.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/actions?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"actions\":[{\"id\":36805187,\"status\":\"completed\",\"type\":\"snapshot\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805188,\"status\":\"completed\",\"type\":\"disable_backups\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805189,\"status\":\"completed\",\"type\":\"enable_backups\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805190,\"status\":\"completed\",\"type\":\"power_off\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805191,\"status\":\"completed\",\"type\":\"power_on\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805192,\"status\":\"completed\",\"type\":\"reboot\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805193,\"status\":\"completed\",\"type\":\"enable_ipv6\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"}],\"links\":{\"pages\":{\"last\":\"https:\/\/api.digitalocean.com\/v2\/droplets\/3164494\/actions?page=3&per_page=1\",\"next\":\"https:\/\/api.digitalocean.com\/v2\/droplets\/3164494\/actions?page=2&per_page=1\"}},\"meta\":{\"total\":7}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/actionsBlockStorage.json b/integration-tests/digitalocean/src/test/resources/mappings/actionsBlockStorage.json
new file mode 100644
index 0000000..8ced42b
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/actionsBlockStorage.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/volumes/actions",
+    "method": "POST"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"action\":{\"id\":72531856,\"status\":\"completed\",\"type\":\"attach_volume\",\"started_at\":\"2015-11-12T17:51:03Z\",\"completed_at\":\"2015-11-12T17:51:14Z\",\"resource_id\":null,\"resource_type\":\"volume\",\"region\":{\"name\":\"Frankfurt 1\",\"slug\":\"fra1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"region_slug\":\"fra1\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/createBlockStorage.json b/integration-tests/digitalocean/src/test/resources/mappings/createBlockStorage.json
new file mode 100644
index 0000000..c68ba89
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/createBlockStorage.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/volumes",
+    "method": "POST"
+  },
+  "response": {
+    "status": 200,
+    "body" : "{\"volume\":{\"id\":\"506f78a4-e098-11e5-ad9f-000f53306ae1\",\"region\":{\"name\":\"New York 1\",\"slug\":\"nyc1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"droplet_ids\":[],\"name\":\"example\",\"description\":\"Block store for examples\",\"size_gigabytes\":10,\"filesystem_type\":\"ext4\",\"filesystem_label\":\"example\",\"created_at\":\"2016-03-02T17:00:49Z\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/createFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/createFloatingIp.json
new file mode 100644
index 0000000..83a4a0f
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/createFloatingIp.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/floating_ips",
+    "method": "POST"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"floating_ip\":{\"ip\":\"45.55.96.47\",\"droplet\":null,\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"locked\":false},\"links\":{}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/createKey.json b/integration-tests/digitalocean/src/test/resources/mappings/createKey.json
new file mode 100644
index 0000000..3afb625
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/createKey.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/account/keys",
+    "method": "POST"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"ssh_key\":{\"id\":512190,\"fingerprint\":\"3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\",\"public_key\":\"ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr\/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example\",\"name\":\"TestKey1\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/createTag.json b/integration-tests/digitalocean/src/test/resources/mappings/createTag.json
new file mode 100644
index 0000000..663fdb0
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/createTag.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/tags",
+    "method": "POST"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"tag\":{\"name\":\"awesome\",\"resources\":{\"count\":0,\"droplets\":{\"count\":0},\"images\":{\"count\":0},\"volumes\":{\"count\":0},\"volume_snapshots\":{\"count\":0},\"databases\":{\"count\":0}}}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteBlockStorage.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteBlockStorage.json
new file mode 100644
index 0000000..e1db36d
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteBlockStorage.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/volumes/506f78a4-e098-11e5-ad9f-000f53306ae1",
+    "method": "DELETE"
+  },
+  "response": {
+    "status": 204,
+    "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteFloatingIp.json
new file mode 100644
index 0000000..36fb6f4
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteFloatingIp.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/floating_ips/45.55.96.47",
+    "method": "DELETE"
+  },
+  "response": {
+    "status": 204,
+    "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteKey.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteKey.json
new file mode 100644
index 0000000..d9b330a
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteKey.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/account/keys/512190",
+    "method": "DELETE"
+  },
+  "response": {
+    "status": 204,
+    "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteSnapshot.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteSnapshot.json
new file mode 100644
index 0000000..fb61437
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteSnapshot.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/snapshots/6372321",
+    "method": "DELETE"
+  },
+  "response": {
+    "status": 204,
+    "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteTag.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteTag.json
new file mode 100644
index 0000000..83a8c0a
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteTag.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/tags/awesome",
+    "method": "DELETE"
+  },
+  "response": {
+    "status": 204,
+    "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllActionsFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllActionsFloatingIp.json
new file mode 100644
index 0000000..0649fc6
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllActionsFloatingIp.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/floating_ips/45.55.96.47/actions?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"actions\":[{\"id\":68212773,\"status\":\"in-progress\",\"type\":\"unassign_ip\",\"started_at\":\"2015-10-15T17:46:15Z\",\"completed_at\":null,\"resource_id\":758603823,\"resource_type\":\"floating_ip\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"region_slug\":\"nyc3\"}],\"links\":{},\"meta\":{\"total\":1}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllBlockstorages.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllBlockstorages.json
new file mode 100644
index 0000000..f16052e
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllBlockstorages.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/volumes?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"volumes\":[{\"id\":\"506f78a4-e098-11e5-ad9f-000f53306ae1\",\"region\":{\"name\":\"Frankfurt 1\",\"slug\":\"fra1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"droplet_ids\":[],\"name\":\"volume1\",\"description\":\"Block store for examples\",\"size_gigabytes\":10,\"created_at\":\"2016-03-02T17:00:49Z\",\"filesystem_type\":\"ext4\",\"filesystem_label\":\"example\",\"tags\":[\"aninterestingtag\"]}],\"links\":{},\"meta\":{\"total\":1}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllFloatingIps.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllFloatingIps.json
new file mode 100644
index 0000000..d9a264b
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllFloatingIps.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/floating_ips?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"floating_ips\":[{\"ip\":\"45.55.96.47\",\"droplet\":null,\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"locked\":false}],\"links\":{},\"meta\":{\"total\":1}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllKeys.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllKeys.json
new file mode 100644
index 0000000..ab6b0e4
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllKeys.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/account/keys?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"ssh_keys\":[{\"id\":512190,\"fingerprint\":\"3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\",\"public_key\":\"ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr\/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example\",\"name\":\"updated_TestKey1\"}],\"links\":{},\"meta\":{\"total\":1}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllTags.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllTags.json
new file mode 100644
index 0000000..5a83fdc
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllTags.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/tags?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"tags\":[{\"name\":\"awesome\",\"resources\":{\"count\":5,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/images\/7555620\",\"droplets\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/droplets\/3164444\"},\"images\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/images\/7555620\"},\"volumes\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/volumes\/3d80cb72-342b-4aaa-b92e-4e4abb24a933\"},\"volume_snapshots\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/snapshots\/1f6f46e8-6b60-11e9-be4e-0a58ac144519\"},\"databases\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/databases\/b92438f6-ba03-416c-b642-e9236db91976\"}}}]}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getBlockStorage.json b/integration-tests/digitalocean/src/test/resources/mappings/getBlockStorage.json
new file mode 100644
index 0000000..72bac69
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getBlockStorage.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/volumes/506f78a4-e098-11e5-ad9f-000f53306ae1?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"volume\":{\"id\":\"506f78a4-e098-11e5-ad9f-000f53306ae1\",\"region\":{\"name\":\"Frankfurt 1\",\"slug\":\"fra1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"droplet_ids\":[],\"name\":\"volume1\",\"description\":\"Block store for examples\",\"size_gigabytes\":10,\"created_at\":\"2016-03-02T17:00:49Z\",\"filesystem_type\":\"ext4\",\"filesystem_label\":\"example\",\"tags\":[\"aninterestingtag\"]}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getDroplet.json b/integration-tests/digitalocean/src/test/resources/mappings/getDroplet.json
index 37e4745..ccc4691 100644
--- a/integration-tests/digitalocean/src/test/resources/mappings/getDroplet.json
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getDroplet.json
@@ -7,7 +7,7 @@
   },
   "response": {
     "status": 200,
-    "body": "{\n  \"droplet\": {\n    \"id\": 3164494,\n   \"name\": \"example.com\",\n   \"memory\": 1024,\n  \"vcpus\": 1,\n \"disk\": 25,\n  \"locked\": true,\n      \"status\": \"active\",\n \"kernel\": {\n   \"id\": 2233,\n   \"name\": \"Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic\",\n   \"version\": \"3.13.0-37-generic\"\n  },\n   \"created_at\": \"2014-11-14T16:36:31Z\",\n  \"features\": [\n    \"virtio\"\n  ],\n    \"backup_ids\": [\n \n  ],\n  \"snapshot_ids\": [\n \n  ],\n  \"image\": {\n   },\n  \"volume_ids\": [\n  \n ],\n \"size\": {\n },\n       \"size_slug\": \"s-1vcpu-1gb\",\n     \"networks\": {\n    },\n    \"region\": {\n  },\n     \"tags\": [\n           \"web\"\n    ]\n    },\n   \"links\": {\n  \"actions\": [\n  {\n \"id\": 36805096,\n \"rel\": \"create\",\n \"href\": \"https://api.digitalocean.com/v2/actions/36805096\"\n      }\n        ]\n}\n            }",
+    "body": "{\n  \"droplet\": {\n    \"id\": 3164494,\n   \"name\": \"example.com\",\n   \"memory\": 1024,\n  \"vcpus\": 1,\n \"disk\": 25,\n  \"locked\": true,\n      \"status\": \"active\",\n \"kernel\": {\n   \"id\": 2233,\n   \"name\": \"Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic\",\n   \"version\": \"3.13.0-37-generic\"\n  },\n   \"created_at\": \"2014-11-14T16:36:31Z\",\n  \"features\": [\n    \"virtio\"\n  ],\n    \"backup_ids\": [\n \n  ],\n  \"snapshot_ids\": [\n \n  ],\n  \"image\": {\n   },\n  \"volume_ids\": [\n \"506f78a4-e098-11e5-ad9f-000f53306ae1\" \n ],\n \"size\": {\n },\n       \"size_slug\": \"s-1vcpu-1gb\",\n     \"networks\": {\n    },\n    \"region\": {\n  },\n     \"tags\": [\n           \"web\"\n    ]\n    },\n   \"links\": {\n  \"actions\": [\n  {\n \"id\": 36805096,\n \"rel\": \"create\",\n \"href\": \"https://api.digitalocean.com/v2/actions/36805096\"\n      }\n        ]\n}\n            }",
     "headers": {
       "Content-Type": "application/json; charset=UTF-8",
       "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/getFloatingIp.json
new file mode 100644
index 0000000..fc3f1b5
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getFloatingIp.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/floating_ips/45.55.96.47?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"floating_ip\":{\"ip\":\"45.55.96.47\",\"droplet\":null,\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"locked\":false}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getKey.json b/integration-tests/digitalocean/src/test/resources/mappings/getKey.json
new file mode 100644
index 0000000..af913c6
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getKey.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/account/keys/512190?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"ssh_key\":{\"id\":512190,\"fingerprint\":\"3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\",\"public_key\":\"ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr\/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example\",\"name\":\"TestKey1\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getTag.json b/integration-tests/digitalocean/src/test/resources/mappings/getTag.json
new file mode 100644
index 0000000..3beb657
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getTag.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/tags/awesome?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"tag\":{\"name\":\"awesome\",\"resources\":{\"count\":5,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/images\/7555620\",\"droplets\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/droplets\/3164444\"},\"images\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/images\/7555620\"},\"volumes\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/volumes\/3d80cb72-342b-4aaa-b92e-4e4abb24a933\"},\"volume_snapshots\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/snapshots\/1f6f46e8-6b60-11e9-be4e-0a58ac144519\"},\"databases\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/databases\/b92438f6-ba03-416c-b642-e9236db91976\"}}}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/imageById.json b/integration-tests/digitalocean/src/test/resources/mappings/imageById.json
new file mode 100644
index 0000000..ba610c7
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/imageById.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/images/7555620?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"image\":{\"id\":7555620,\"name\":\"Nifty New Snapshot\",\"distribution\":\"Ubuntu\",\"slug\":null,\"public\":false,\"regions\":[\"nyc2\",\"nyc2\"],\"created_at\":\"2014-11-04T22:23:02Z\",\"min_disk_size\":20,\"size_gigabytes\":2.34,\"description\":\"\",\"tags\":[],\"status\":\"available\",\"error_message\":\"\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/images.json b/integration-tests/digitalocean/src/test/resources/mappings/images.json
new file mode 100644
index 0000000..62f99ca
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/images.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/images?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body" : "{\"images\":[{\"id\":7555620,\"name\":\"Nifty New Snapshot\",\"distribution\":\"Ubuntu\",\"slug\":null,\"public\":false,\"regions\":[\"nyc2\",\"nyc2\"],\"created_at\":\"2014-11-04T22:23:02Z\",\"type\":\"snapshot\",\"min_disk_size\":20,\"size_gigabytes\":2.34,\"description\":\"\",\"tags\":[],\"status\":\"available\",\"error_message\":\"\"}],\"links\":{\"pages\":{\"last\":\"https:\/\/api.digitalocean.com\/v2\/images?page=56&per_page=1\",\"next\":\"https:\/\/api.digitalocean.com\/v2\/images?page=2&per_page=1\"}},\"meta\":{\"total\":56}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/images_private.json b/integration-tests/digitalocean/src/test/resources/mappings/images_private.json
new file mode 100644
index 0000000..f559e27
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/images_private.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/images?page=1&per_page=25&private=true",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body" : "{\"images\":[{\"id\":7555620,\"name\":\"Nifty New Snapshot\",\"distribution\":\"Ubuntu\",\"slug\":null,\"public\":false,\"regions\":[\"nyc2\",\"nyc2\"],\"created_at\":\"2014-11-04T22:23:02Z\",\"type\":\"snapshot\",\"min_disk_size\":20,\"size_gigabytes\":2.34,\"description\":\"\",\"tags\":[],\"status\":\"available\",\"error_message\":\"\"}],\"links\":{\"pages\":{\"last\":\"https:\/\/api.digitalocean.com\/v2\/images?page=56&per_page=1\",\"next\":\"https:\/\/api.digitalocean.com\/v2\/images?page=2&per_page=1\"}},\"meta\":{\"total\":56}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/regions.json b/integration-tests/digitalocean/src/test/resources/mappings/regions.json
new file mode 100644
index 0000000..6c2a435
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/regions.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/regions?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"regions\":[{\"name\":\"New York 1\",\"slug\":\"nyc1\",\"sizes\":[],\"features\":[\"virtio\",\"backups\"],\"available\":false},{\"name\":\"Amsterdam 1\",\"slug\":\"ams1\",\"sizes\":[],\"features\":[\"virtio\",\"backups\"],\"available\":false},{\"name\":\"San Francisco 1\",\"slug\":\"sfo1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"backups\",\"metadata\"],\"available\":true},{\"name\":\"New York 2\",\"slug\":\"nyc2\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\"],\"available\":true},{\"name\":\"Amsterdam 2\",\"slug\":\"ams2\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"metadata\"],\"available\":true},{\"name\":\"Singapore 1\",\"slug\":\"sgp1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},{\"name\":\"London 1\",\"slug\":\"lon1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},{\"name\":\"Amsterdam 3\",\"slug\":\"ams3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true}],\"links\":{},\"meta\":{\"total\":9}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/sizes.json b/integration-tests/digitalocean/src/test/resources/mappings/sizes.json
new file mode 100644
index 0000000..981a97a
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/sizes.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/sizes?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"sizes\":[{\"slug\":\"s-1vcpu-1gb\",\"memory\":1024,\"vcpus\":1,\"disk\":25,\"transfer\":1,\"price_monthly\":5,\"price_hourly\":0.00744,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-3vcpu-1gb\",\"memory\":1024,\"vcpus\":3,\"disk\":60,\"transfer\":3,\"price_monthly\":15,\"price_hourly\":0.02232,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-1vcpu-2gb\",\"memory\":2048,\"vcpus\":1,\"disk\":50,\"transfer\":2,\"price_monthly\":10,\"price_hourly\":0.01488,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-2vcpu-2gb\",\"memory\":2048,\"vcpus\":2,\"disk\":60,\"transfer\":3,\"price_monthly\":15,\"price_hourly\":0.02232,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-1vcpu-3gb\",\"memory\":3072,\"vcpus\":1,\"disk\":20,\"transfer\":3,\"price_monthly\":15,\"price_hourly\":0.02232,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-2\",\"memory\":4096,\"vcpus\":2,\"disk\":25,\"transfer\":5,\"price_monthly\":40,\"price_hourly\":0.06,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-2vcpu-4gb\",\"memory\":4096,\"vcpus\":2,\"disk\":80,\"transfer\":4,\"price_monthly\":20,\"price_hourly\":0.02976,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-4vcpu-8gb\",\"memory\":8192,\"vcpus\":4,\"disk\":160,\"transfer\":5,\"price_monthly\":40,\"price_hourly\":0.05952,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-4\",\"memory\":8192,\"vcpus\":4,\"disk\":50,\"transfer\":5,\"price_monthly\":80,\"price_hourly\":0.119,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-8\",\"memory\":16384,\"vcpus\":8,\"disk\":100,\"transfer\":5,\"price_monthly\":160,\"price_hourly\":0.238,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-6vcpu-16gb\",\"memory\":16384,\"vcpus\":6,\"disk\":320,\"transfer\":6,\"price_monthly\":80,\"price_hourly\":0.11905,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-8vcpu-32gb\",\"memory\":32768,\"vcpus\":8,\"disk\":640,\"transfer\":7,\"price_monthly\":160,\"price_hourly\":0.2381,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-16\",\"memory\":32768,\"vcpus\":16,\"disk\":200,\"transfer\":5,\"price_monthly\":320,\"price_hourly\":0.476,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-12vcpu-48gb\",\"memory\":49152,\"vcpus\":12,\"disk\":960,\"transfer\":8,\"price_monthly\":240,\"price_hourly\":0.35714,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-16vcpu-64gb\",\"memory\":65536,\"vcpus\":16,\"disk\":1280,\"transfer\":9,\"price_monthly\":320,\"price_hourly\":0.47619,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-32\",\"memory\":65536,\"vcpus\":32,\"disk\":400,\"transfer\":5,\"price_monthly\":640,\"price_hourly\":0.952,\"regions\":[\"fra1\"],\"available\":true},{\"slug\":\"c-48\",\"memory\":73728,\"vcpus\":48,\"disk\":20,\"transfer\":5,\"price_monthly\":960,\"price_hourly\":1.429,\"regions\":[],\"available\":true},{\"slug\":\"s-20vcpu-96gb\",\"memory\":98304,\"vcpus\":20,\"disk\":1920,\"transfer\":10,\"price_monthly\":480,\"price_hourly\":0.71429,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-24vcpu-128gb\",\"memory\":131072,\"vcpus\":24,\"disk\":2560,\"transfer\":11,\"price_monthly\":640,\"price_hourly\":0.95238,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-32vcpu-192gb\",\"memory\":196608,\"vcpus\":24,\"disk\":3840,\"transfer\":12,\"price_monthly\":960,\"price_hourly\":1.42857,\"regions\":[],\"available\":true}],\"links\":{},\"meta\":{\"total\":20}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/snapshotById.json b/integration-tests/digitalocean/src/test/resources/mappings/snapshotById.json
new file mode 100644
index 0000000..0acf1a6
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/snapshotById.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/snapshots/6372321?per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"snapshot\":{\"id\":\"6372321\",\"name\":\"big-data-snapshot1475170902\",\"regions\":[\"nyc1\"],\"created_at\":\"2016-09-29T17:41:42Z\",\"resource_id\":\"fbcbc5c8-866b-11e6-96bf-000f53315a41\",\"resource_type\":\"volume\",\"min_disk_size\":10,\"size_gigabytes\":0,\"tags\":[\"aninterestingtag\"]}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/snapshots.json b/integration-tests/digitalocean/src/test/resources/mappings/snapshots.json
new file mode 100644
index 0000000..1e71ef1
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/snapshots.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/snapshots?page=1&per_page=25",
+    "method": "GET"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"snapshots\":[{\"id\":6372321,\"name\":\"5.10 x64\",\"regions\":[\"nyc1\",\"ams1\",\"sfo1\",\"nyc2\",\"ams2\",\"sgp1\",\"lon1\",\"nyc3\",\"ams3\",\"fra1\",\"tor1\"],\"created_at\":\"2014-09-26T16:40:18Z\",\"resource_id\":2713828,\"resource_type\":\"droplet\",\"min_disk_size\":20,\"size_gigabytes\":1.42,\"tags\":[]}],\"links\":{\"pages\":{\"last\":\"https:\/\/api.digitalocean.com\/v2\/snapshots?page=110&per_page=1\",\"next\":\"https:\/\/api.digitalocean.com\/v2\/snapshots?page=2&per_page=1\"}},\"meta\":{\"total\":110}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/updateKey.json b/integration-tests/digitalocean/src/test/resources/mappings/updateKey.json
new file mode 100644
index 0000000..a884264
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/updateKey.json
@@ -0,0 +1,28 @@
+{
+  "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "name": "digitalocean_api_json",
+  "request": {
+    "url": "/v2/account/keys/512190",
+    "method": "PUT"
+  },
+  "response": {
+    "status": 200,
+    "body": "{\"ssh_key\":{\"id\":512190,\"fingerprint\":\"3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\",\"public_key\":\"ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr\/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example\",\"name\":\"updated_TestKey1\"}}",
+    "headers": {
+      "Content-Type": "application/json; charset=UTF-8",
+      "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma": "no-cache",
+      "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control": "no-cache, must-revalidate",
+      "Vary": "Accept-Language",
+      "Server": "mafe",
+      "X-XSS-Protection": "0",
+      "X-Frame-Options": "SAMEORIGIN",
+      "Server-Timing": "gfet4t7; dur=263",
+      "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file