diff --git a/doc/3/controllers/collection/get-specifications/index.md b/doc/3/controllers/collection/get-specifications/index.md
new file mode 100644
index 00000000..3874bcef
--- /dev/null
+++ b/doc/3/controllers/collection/get-specifications/index.md
@@ -0,0 +1,33 @@
+---
+code: true
+type: page
+title: getSpecifications
+description: Returns the validation specifications
+---
+
+# getSpecifications
+
+Returns the validation specifications associated to the given index and collection.
+
+
+
+```java
+ public CompletableFuture> getSpecifications(
+ final String index,
+ final String collection)
+```
+
+
+
+| Arguments | Type | Description |
+| ------------ | ----------------- | --------------- |
+| `index` | String
| Index name |
+| `collection` | String
| Collection name |
+
+## Returns
+
+Returns a `ConcurrentHashMap` representing the collection specifications.
+
+## Usage
+
+<<< ./snippets/get-specifications.java
\ No newline at end of file
diff --git a/doc/3/controllers/collection/get-specifications/snippets/get-specifications.java b/doc/3/controllers/collection/get-specifications/snippets/get-specifications.java
new file mode 100644
index 00000000..96aa0edb
--- /dev/null
+++ b/doc/3/controllers/collection/get-specifications/snippets/get-specifications.java
@@ -0,0 +1,21 @@
+ ConcurrentHashMap result = kuzzle
+ .getCollectionController()
+ .getSpecifications("nyc-open-data", "yellow-taxi")
+ .get();
+
+/*
+ {
+ collection="yellow-taxi",
+ index="nyc-open-data",
+ validation={
+ fields={
+ age={
+ defaultValue=42,
+ mandatory=true,
+ type="integer"
+ }
+ },
+ strict=true
+ }
+ }
+*/
\ No newline at end of file
diff --git a/doc/3/controllers/collection/get-specifications/snippets/get-specifications.test.yml b/doc/3/controllers/collection/get-specifications/snippets/get-specifications.test.yml
new file mode 100644
index 00000000..5f7533bf
--- /dev/null
+++ b/doc/3/controllers/collection/get-specifications/snippets/get-specifications.test.yml
@@ -0,0 +1,11 @@
+name: collection#getSpecifications
+description: Returns the validation specifications
+hooks:
+ before: |
+ curl -X DELETE kuzzle:7512/nyc-open-data
+ curl -X POST kuzzle:7512/nyc-open-data/_create
+ curl -X PUT kuzzle:7512/nyc-open-data/yellow-taxi
+ curl -X PUT -H "Content-Type: application/json" -d '{ "strict": false, "fields": {"license": {"type": "string"} } }' kuzzle:7512/nyc-open-data/yellow-taxi/_specifications
+ after:
+template: print-result
+expected: 'fields'
\ No newline at end of file
diff --git a/src/main/java/io/kuzzle/sdk/API/Controllers/CollectionController.java b/src/main/java/io/kuzzle/sdk/API/Controllers/CollectionController.java
index c0c84472..224c9d4d 100644
--- a/src/main/java/io/kuzzle/sdk/API/Controllers/CollectionController.java
+++ b/src/main/java/io/kuzzle/sdk/API/Controllers/CollectionController.java
@@ -136,4 +136,31 @@ public CompletableFuture> getMapping(
.thenApplyAsync(
(response) -> (ConcurrentHashMap) response.result);
}
+
+ /**
+ * Gets the validation specifications associated to the given index and collection.
+ *
+ * @param index
+ * @param collection
+ * @return a CompletableFuture
+ * @throws NotConnectedException
+ * @throws InternalException
+ */
+ public CompletableFuture> getSpecifications(
+ final String index,
+ final String collection) throws NotConnectedException, InternalException {
+
+ final KuzzleMap query = new KuzzleMap();
+
+ query
+ .put("index", index)
+ .put("collection", collection)
+ .put("controller", "collection")
+ .put("action", "getSpecifications");
+
+ return kuzzle
+ .query(query)
+ .thenApplyAsync(
+ (response) -> (ConcurrentHashMap) response.result);
+ }
}
diff --git a/src/test/java/io/kuzzle/test/API/Controllers/CollectionTest.java b/src/test/java/io/kuzzle/test/API/Controllers/CollectionTest.java
index f02222c8..30c3a876 100644
--- a/src/test/java/io/kuzzle/test/API/Controllers/CollectionTest.java
+++ b/src/test/java/io/kuzzle/test/API/Controllers/CollectionTest.java
@@ -178,4 +178,35 @@ public void getMappingShouldThrowWhenNotConnected() throws NotConnectedException
kuzzleMock.getCollectionController().getMapping(index, collection);
}
+
+ @Test
+ public void getSpecificationsCollectionTest() throws NotConnectedException, InternalException {
+
+ Kuzzle kuzzleMock = spy(new Kuzzle(networkProtocol));
+ String index = "nyc-open-data";
+ String collection = "yellow-taxi";
+
+ ArgumentCaptor arg = ArgumentCaptor.forClass(KuzzleMap.class);
+
+ kuzzleMock.getCollectionController().getSpecifications(index, collection);
+ Mockito.verify(kuzzleMock, Mockito.times(1)).query(arg.capture());
+
+ assertEquals((arg.getValue()).getString("controller"), "collection");
+ assertEquals((arg.getValue()).getString("action"), "getSpecifications");
+ assertEquals((arg.getValue()).getString("index"), "nyc-open-data");
+ assertEquals((arg.getValue()).getString("collection"), "yellow-taxi");
+ }
+
+ @Test(expected = NotConnectedException.class)
+ public void getSpecificationsCollectionThrowWhenNotConnected() throws NotConnectedException, InternalException {
+
+ AbstractProtocol fakeNetworkProtocol = Mockito.mock(WebSocket.class);
+ Mockito.when(fakeNetworkProtocol.getState()).thenAnswer((Answer) invocation -> ProtocolState.CLOSE);
+
+ Kuzzle kuzzleMock = spy(new Kuzzle(fakeNetworkProtocol));
+ String index = "nyc-open-data";
+ String collection = "yellow-taxi";
+
+ kuzzleMock.getCollectionController().getSpecifications(index, collection);
+ }
}