diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestResponseFactory.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestResponseFactory.java
index 07e6f3463d6a4c7e9624668d1d0f275856a6e7e2..b457c6ec72096a65905a19d039c219264680c492 100644
--- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestResponseFactory.java
+++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestResponseFactory.java
@@ -60,6 +60,7 @@ import org.activiti.rest.api.history.HistoricProcessInstanceResponse;
import org.activiti.rest.api.history.HistoricTaskInstanceResponse;
import org.activiti.rest.api.history.HistoricVariableInstanceResponse;
import org.activiti.rest.api.identity.GroupResponse;
+import org.activiti.rest.api.identity.MembershipResponse;
import org.activiti.rest.api.identity.UserInfoResponse;
import org.activiti.rest.api.identity.UserResponse;
import org.activiti.rest.api.legacy.identity.LegacyRestIdentityLink;
@@ -582,6 +583,13 @@ public class RestResponseFactory {
return response;
}
+ public MembershipResponse createMembershipResponse(SecuredResource securedResource, String userId, String groupId) {
+ MembershipResponse response = new MembershipResponse();
+ response.setGroupId(groupId);
+ response.setUserId(userId);
+ response.setUrl(securedResource.createFullResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP, groupId, userId));
+ return response;
+ }
/**
* Called once when the converters need to be initialized. Override of custom conversion
diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestUrls.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestUrls.java
index 7a68f8a474a82b4a5760c32ca49dcb9a0984b7c7..d3ecbe001d0dabb3f8156373f72ebeb755542009 100644
--- a/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestUrls.java
+++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/RestUrls.java
@@ -63,6 +63,7 @@ public final class RestUrls {
public static final String SEGMENT_GROUPS = "groups";
public static final String SEGMENT_PICTURE = "picture";
public static final String SEGMENT_INFO = "info";
+ public static final String SEGMENT_MEMBERS = "members";
/**
* URL template for the deployment collection: repository/deployments
@@ -378,6 +379,16 @@ public final class RestUrls {
*/
public static final String[] URL_GROUP = {SEGMENT_IDENTITY_RESOURCES, SEGMENT_GROUPS, "{0}"};
+ /**
+ * URL template for the membership-collection of a group: identity/groups/{0:groupId}/members
+ */
+ public static final String[] URL_GROUP_MEMBERSHIP_COLLECTION = {SEGMENT_IDENTITY_RESOURCES, SEGMENT_GROUPS, "{0}", SEGMENT_MEMBERS};
+
+ /**
+ * URL template for the membership-collection of a single group membership: identity/groups/{0:groupId}/members/{1:userId}
+ */
+ public static final String[] URL_GROUP_MEMBERSHIP = {SEGMENT_IDENTITY_RESOURCES, SEGMENT_GROUPS, "{0}", SEGMENT_MEMBERS, "{1}"};
+
/**
* Creates an url based on the passed fragments and replaces any placeholders with the given arguments. The
* placeholders are folowing the {@link MessageFormat} convention
diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/GroupMembershipCollectionResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/GroupMembershipCollectionResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..5febff6c541b7e0f5e6669a5e59e5e148a5a38db
--- /dev/null
+++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/GroupMembershipCollectionResource.java
@@ -0,0 +1,52 @@
+/* Licensed 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.activiti.rest.api.identity;
+
+import org.activiti.engine.ActivitiIllegalArgumentException;
+import org.activiti.engine.identity.Group;
+import org.activiti.rest.api.ActivitiUtil;
+import org.activiti.rest.application.ActivitiRestServicesApplication;
+import org.restlet.data.Status;
+import org.restlet.resource.Post;
+import org.restlet.resource.ResourceException;
+
+/**
+ * @author Frederik Heremans
+ */
+public class GroupMembershipCollectionResource extends BaseGroupResource {
+
+ @Post
+ public MembershipResponse createMembership(MembershipRequest memberShip) {
+ Group group = getGroupFromRequest();
+
+ if(memberShip.getUserId() == null) {
+ throw new ActivitiIllegalArgumentException("UserId cannot be null.");
+ }
+
+ // Check if user is member of group since API doesn't return typed exception
+ if(ActivitiUtil.getIdentityService().createUserQuery()
+ .memberOfGroup(group.getId())
+ .userId(memberShip.getUserId())
+ .count() > 0) {
+ throw new ResourceException(Status.CLIENT_ERROR_CONFLICT.getCode(), "User '" + memberShip.getUserId() +
+ "' is already part of group '" + group.getId() + "'.", null, null);
+ }
+
+ ActivitiUtil.getIdentityService().createMembership(memberShip.getUserId(), group.getId());
+ setStatus(Status.SUCCESS_CREATED);
+
+ return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory()
+ .createMembershipResponse(this, memberShip.getUserId(), group.getId());
+ }
+}
diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/GroupMembershipResource.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/GroupMembershipResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc1fc61d0a17ec468ea3a0da83aeffa4894d15e1
--- /dev/null
+++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/GroupMembershipResource.java
@@ -0,0 +1,49 @@
+/* Licensed 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.activiti.rest.api.identity;
+
+import org.activiti.engine.ActivitiIllegalArgumentException;
+import org.activiti.engine.identity.Group;
+import org.activiti.rest.api.ActivitiUtil;
+import org.restlet.data.Status;
+import org.restlet.resource.Delete;
+import org.restlet.resource.ResourceException;
+
+/**
+ * @author Frederik Heremans
+ */
+public class GroupMembershipResource extends BaseGroupResource {
+
+ @Delete
+ public void deleteMembership() {
+ Group group = getGroupFromRequest();
+
+ String userId = getAttribute("userId");
+ if(userId == null) {
+ throw new ActivitiIllegalArgumentException("UserId cannot be null.");
+ }
+
+ // Check if user is not a member of group since API doesn't return typed exception
+ if(ActivitiUtil.getIdentityService().createUserQuery()
+ .memberOfGroup(group.getId())
+ .userId(userId)
+ .count() != 1) {
+ throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND.getCode(), "User '" + userId +
+ "' is not part of group '" + group.getId() + "'.", null, null);
+ }
+
+ ActivitiUtil.getIdentityService().deleteMembership(userId, group.getId());
+ setStatus(Status.SUCCESS_NO_CONTENT);
+ }
+}
diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/MembershipRequest.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/MembershipRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6ca053900a60614aba6cfd35f6693b94cd22922
--- /dev/null
+++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/MembershipRequest.java
@@ -0,0 +1,30 @@
+/* Licensed 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.activiti.rest.api.identity;
+
+
+/**
+ * @author Frederik Heremans
+ */
+public class MembershipRequest {
+
+ protected String userId;
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+ public String getUserId() {
+ return userId;
+ }
+}
diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/MembershipResponse.java b/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/MembershipResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..1603c85338e97b9bc0a72b2a541da8a8ba71b3cf
--- /dev/null
+++ b/modules/activiti-rest/src/main/java/org/activiti/rest/api/identity/MembershipResponse.java
@@ -0,0 +1,37 @@
+/* Licensed 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.activiti.rest.api.identity;
+
+
+/**
+ * @author Frederik Heremans
+ */
+public class MembershipResponse extends MembershipRequest {
+
+ protected String url;
+ protected String groupId;
+
+ public void setGroupId(String groupId) {
+ this.groupId = groupId;
+ }
+ public String getGroupId() {
+ return groupId;
+ }
+ public String getUrl() {
+ return url;
+ }
+ public void setUrl(String url) {
+ this.url = url;
+ }
+}
diff --git a/modules/activiti-rest/src/main/java/org/activiti/rest/application/RestServicesInit.java b/modules/activiti-rest/src/main/java/org/activiti/rest/application/RestServicesInit.java
index 163308ccb0e5a2338e90ab767d6ce4d3dae757c5..01da98e414502cb7d9669190d124ad80687a19c9 100644
--- a/modules/activiti-rest/src/main/java/org/activiti/rest/application/RestServicesInit.java
+++ b/modules/activiti-rest/src/main/java/org/activiti/rest/application/RestServicesInit.java
@@ -16,6 +16,8 @@ import org.activiti.rest.api.history.HistoricTaskInstanceResource;
import org.activiti.rest.api.history.HistoricVariableInstanceCollectionResource;
import org.activiti.rest.api.history.HistoricVariableInstanceQueryResource;
import org.activiti.rest.api.identity.GroupCollectionResource;
+import org.activiti.rest.api.identity.GroupMembershipCollectionResource;
+import org.activiti.rest.api.identity.GroupMembershipResource;
import org.activiti.rest.api.identity.GroupResource;
import org.activiti.rest.api.identity.UserCollectionResource;
import org.activiti.rest.api.identity.UserInfoCollectionResource;
@@ -179,6 +181,8 @@ public class RestServicesInit {
router.attach("/identity/users/{userId}/info", UserInfoCollectionResource.class);
router.attach("/identity/groups", GroupCollectionResource.class);
router.attach("/identity/groups/{groupId}", GroupResource.class);
+ router.attach("/identity/groups/{groupId}/members", GroupMembershipCollectionResource.class);
+ router.attach("/identity/groups/{groupId}/members/{userId}", GroupMembershipResource.class);
router.attach("/query/tasks", TaskQueryResource.class);
diff --git a/modules/activiti-rest/src/test/java/org/activiti/rest/api/identity/GroupMembershipResourceTest.java b/modules/activiti-rest/src/test/java/org/activiti/rest/api/identity/GroupMembershipResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e24fef69e60d6703b9cbec71c0a288226929721
--- /dev/null
+++ b/modules/activiti-rest/src/test/java/org/activiti/rest/api/identity/GroupMembershipResourceTest.java
@@ -0,0 +1,246 @@
+/* Licensed 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.activiti.rest.api.identity;
+
+import org.activiti.engine.identity.Group;
+import org.activiti.engine.identity.User;
+import org.activiti.rest.BaseRestTestCase;
+import org.activiti.rest.api.RestUrls;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.node.ObjectNode;
+import org.restlet.data.Status;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ClientResource;
+import org.restlet.resource.ResourceException;
+
+
+/**
+ * @author Frederik Heremans
+ */
+public class GroupMembershipResourceTest extends BaseRestTestCase {
+
+ public void testCreatemembership() throws Exception {
+ try {
+ Group testGroup = identityService.newGroup("testgroup");
+ testGroup.setName("Test group");
+ testGroup.setType("Test type");
+ identityService.saveGroup(testGroup);
+
+ User testUser = identityService.newUser("testuser");
+ identityService.saveUser(testUser);
+
+ ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP_COLLECTION, "testgroup"));
+
+ ObjectNode requestNode = objectMapper.createObjectNode();
+ requestNode.put("userId", "testuser");
+
+ Representation response = client.post(requestNode);
+ assertEquals(Status.SUCCESS_CREATED, client.getResponse().getStatus());
+
+ JsonNode responseNode = objectMapper.readTree(response.getStream());
+ assertNotNull(responseNode);
+ assertEquals("testuser", responseNode.get("userId").getTextValue());
+ assertEquals("testgroup", responseNode.get("groupId").getTextValue());
+ assertTrue(responseNode.get("url").getTextValue().endsWith(RestUrls.createRelativeResourceUrl(
+ RestUrls.URL_GROUP_MEMBERSHIP, testGroup.getId(), testUser.getId())));
+
+ Group createdGroup = identityService.createGroupQuery().groupId("testgroup").singleResult();
+ assertNotNull(createdGroup);
+ assertEquals("Test group", createdGroup.getName());
+ assertEquals("Test type", createdGroup.getType());
+
+ assertNotNull(identityService.createUserQuery().memberOfGroup("testgroup").singleResult());
+ assertEquals("testuser", identityService.createUserQuery().memberOfGroup("testgroup").singleResult().getId());
+ } finally {
+ try {
+ identityService.deleteGroup("testgroup");
+ } catch(Throwable ignore) {
+ // Ignore, since the group may not have been created in the test
+ // or already deleted
+ }
+
+ try {
+ identityService.deleteUser("testuser");
+ } catch(Throwable ignore) {
+ // Ignore, since the group may not have been created in the test
+ // or already deleted
+ }
+ }
+ }
+
+ public void testCreateMembershipAlreadyExisting() throws Exception {
+ try {
+ Group testGroup = identityService.newGroup("testgroup");
+ testGroup.setName("Test group");
+ testGroup.setType("Test type");
+ identityService.saveGroup(testGroup);
+
+ User testUser = identityService.newUser("testuser");
+ identityService.saveUser(testUser);
+
+ identityService.createMembership("testuser", "testgroup");
+
+ ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP_COLLECTION, "testgroup"));
+
+ ObjectNode requestNode = objectMapper.createObjectNode();
+ requestNode.put("userId", "testuser");
+
+ try {
+ client.post(requestNode);
+ fail("Exception expected");
+ } catch(ResourceException expected) {
+ assertEquals(Status.CLIENT_ERROR_CONFLICT, expected.getStatus());
+ assertEquals("User 'testuser' is already part of group 'testgroup'.", expected.getStatus().getDescription());
+ }
+ } finally {
+ try {
+ identityService.deleteGroup("testgroup");
+ } catch(Throwable ignore) {
+ // Ignore, since the group may not have been created in the test
+ // or already deleted
+ }
+
+ try {
+ identityService.deleteUser("testuser");
+ } catch(Throwable ignore) {
+ // Ignore, since the group may not have been created in the test
+ // or already deleted
+ }
+ }
+ }
+
+ public void testDeleteMembership() throws Exception {
+ try {
+ Group testGroup = identityService.newGroup("testgroup");
+ testGroup.setName("Test group");
+ testGroup.setType("Test type");
+ identityService.saveGroup(testGroup);
+
+ User testUser = identityService.newUser("testuser");
+ identityService.saveUser(testUser);
+
+ identityService.createMembership("testuser", "testgroup");
+
+ ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(
+ RestUrls.URL_GROUP_MEMBERSHIP, "testgroup", "testuser"));
+
+ Representation response = client.delete();
+ assertEquals(Status.SUCCESS_NO_CONTENT, client.getResponse().getStatus());
+ assertEquals(0, response.getSize());
+
+ // Check if membership is actually deleted
+ assertNull(identityService.createUserQuery().memberOfGroup("testgroup").singleResult());
+ } finally {
+ try {
+ identityService.deleteGroup("testgroup");
+ } catch(Throwable ignore) {
+ // Ignore, since the group may not have been created in the test
+ // or already deleted
+ }
+
+ try {
+ identityService.deleteUser("testuser");
+ } catch(Throwable ignore) {
+ // Ignore, since the group may not have been created in the test
+ // or already deleted
+ }
+ }
+ }
+
+ /**
+ * Test delete membership that is no member in the group.
+ */
+ public void testDeleteMembershipNoMember() throws Exception {
+ try {
+ Group testGroup = identityService.newGroup("testgroup");
+ testGroup.setName("Test group");
+ testGroup.setType("Test type");
+ identityService.saveGroup(testGroup);
+
+ User testUser = identityService.newUser("testuser");
+ identityService.saveUser(testUser);
+
+ ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(
+ RestUrls.URL_GROUP_MEMBERSHIP, "testgroup", "testuser"));
+
+ try {
+ client.delete();
+ fail("Exception expected");
+ } catch(ResourceException expected) {
+ assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
+ assertEquals("User 'testuser' is not part of group 'testgroup'.", expected.getStatus().getDescription());
+ }
+
+ } finally {
+ try {
+ identityService.deleteGroup("testgroup");
+ } catch(Throwable ignore) {
+ // Ignore, since the group may not have been created in the test
+ // or already deleted
+ }
+
+ try {
+ identityService.deleteUser("testuser");
+ } catch(Throwable ignore) {
+ // Ignore, since the group may not have been created in the test
+ // or already deleted
+ }
+ }
+ }
+
+ /**
+ * Test deleting member from an unexisting group.
+ */
+ public void testDeleteMemberfromUnexistingGroup() throws Exception {
+ ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(
+ RestUrls.URL_GROUP_MEMBERSHIP, "unexisting", "kermit"));
+ try {
+ client.delete();
+ fail("Exception expected");
+ } catch(ResourceException expected) {
+ assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
+ assertEquals("Could not find a group with id 'unexisting'.", expected.getStatus().getDescription());
+ }
+ }
+
+ /**
+ * Test adding member to an unexisting group.
+ */
+ public void testAddMemberToUnexistingGroup() throws Exception {
+ ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP_COLLECTION, "unexisting"));
+
+ try {
+ client.post(objectMapper.createObjectNode());
+ fail("Exception expected");
+ } catch(ResourceException expected) {
+ assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
+ assertEquals("Could not find a group with id 'unexisting'.", expected.getStatus().getDescription());
+ }
+ }
+
+ /**
+ * Test adding member to a group, without specifying userId
+ */
+ public void testAddMemberNoUserId() throws Exception {
+ ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP_COLLECTION, "admin"));
+
+ try {
+ client.post(objectMapper.createObjectNode());
+ fail("Exception expected");
+ } catch(ResourceException expected) {
+ assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
+ assertEquals("UserId cannot be null.", expected.getStatus().getDescription());
+ }
+ }
+}
diff --git a/userguide/src/en/chapters/ch14-REST.xml b/userguide/src/en/chapters/ch14-REST.xml
index c0020234bbd1a6bdb9b52b0314054795163da44e..c9643a15b03553b2848820d8d4dcc599bbc0bfa3 100644
--- a/userguide/src/en/chapters/ch14-REST.xml
+++ b/userguide/src/en/chapters/ch14-REST.xml
@@ -5479,6 +5479,153 @@ Only the attachment name is required to create a new attachment.
+
+ Get members in a group
+ There is no GET allowed on identity/groups/members. Use the identity/users?memberOfGroup=sales URL to get all users that are part of a particular group.
+
+
+ Add a member to a group
+
+ POST identity/groups/{groupId}/members
+
+
+
+ URL parameters
+
+
+
+ Parameter
+ Required
+ Value
+ Description
+
+
+
+
+ groupId
+ Yes
+ String
+ The id of the group to add a member to.
+
+
+
+
+
+
+ Body JSON:
+
+{
+ "userId":"kermit"
+}
+
+
+
+ Response codes
+
+
+
+ Response code
+ Description
+
+
+
+
+ 201
+ Indicates the group was found and the member has been added.
+
+
+ 404
+ Indicates the userId was not included in the request body.
+
+
+ 404
+ Indicates the requested group was not found.
+
+
+ 409
+ Indicates the requested user is already a member of the group.
+
+
+
+
+
+
+ Response Body:
+
+{
+ "userId":"kermit",
+ "groupId":"sales",
+ "url":"http://localhost:8182/identity/groups/sales/members/kermit"
+}
+
+
+
+ Delete a member from a group
+
+ DELETE identity/groups/{groupId}/members/{userId}
+
+
+
+ URL parameters
+
+
+
+ Parameter
+ Required
+ Value
+ Description
+
+
+
+
+ groupId
+ Yes
+ String
+ The id of the group to remove a member from.
+
+
+ userId
+ Yes
+ String
+ The id of the user to remove.
+
+
+
+
+
+
+
+ Response codes
+
+
+
+ Response code
+ Description
+
+
+
+
+ 204
+ Indicates the group was found and the member has been deleted. The response body is left empty intentionally.
+
+
+ 404
+ Indicates the requested group was not found or that the user is not a member of the group. The status description contains additional information about the error.
+
+
+
+
+
+
+ Response Body:
+
+{
+ "userId":"kermit",
+ "groupId":"sales",
+ "url":"http://localhost:8182/identity/groups/sales/members/kermit"
+}
+
+