diff --git a/java/com/google/gerrit/extensions/restapi/AcceptsCreate.java b/java/com/google/gerrit/extensions/restapi/AcceptsCreate.java
deleted file mode 100644
index 994e7f28f1..0000000000
--- a/java/com/google/gerrit/extensions/restapi/AcceptsCreate.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// 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 com.google.gerrit.extensions.restapi;
-
-/**
- * Optional interface for {@link RestCollection}.
- *
- * 
Collections that implement this interface can accept a {@code PUT} or {@code POST} when the
- * parse method throws {@link ResourceNotFoundException}.
- */
-public interface AcceptsCreate
 {
-  /**
-   * Handle creation of a child resource.
-   *
-   * @param parent parent collection handle.
-   * @param id id of the resource being created.
-   * @return a view to perform the creation. The create method must embed the id into the newly
-   *     returned view object, as it will not be passed.
-   * @throws RestApiException the view cannot be constructed.
-   */
-  RestModifyView
 create(P parent, IdString id) throws RestApiException;
-}
diff --git a/java/com/google/gerrit/extensions/restapi/RestApiModule.java b/java/com/google/gerrit/extensions/restapi/RestApiModule.java
index 0db28917b8..783df0b7ff 100644
--- a/java/com/google/gerrit/extensions/restapi/RestApiModule.java
+++ b/java/com/google/gerrit/extensions/restapi/RestApiModule.java
@@ -28,6 +28,7 @@ public abstract class RestApiModule extends FactoryModule {
   protected static final String PUT = "PUT";
   protected static final String DELETE = "DELETE";
   protected static final String POST = "POST";
+  protected static final String CREATE = "CREATE";
 
   protected  ReadViewBinder get(TypeLiteral> viewType) {
     return new ReadViewBinder<>(view(viewType, GET, "/"));
@@ -45,6 +46,11 @@ public abstract class RestApiModule extends FactoryModule {
     return new ModifyViewBinder<>(view(viewType, DELETE, "/"));
   }
 
+  protected  CreateViewBinder create(
+      TypeLiteral> viewType) {
+    return new CreateViewBinder<>(createView(viewType, CREATE, "/"));
+  }
+
   protected  ReadViewBinder get(
       TypeLiteral> viewType, String name) {
     return new ReadViewBinder<>(view(viewType, GET, name));
@@ -75,6 +81,12 @@ public abstract class RestApiModule extends FactoryModule {
     return bind(viewType).annotatedWith(export(method, name));
   }
 
+  protected 
+      LinkedBindingBuilder> createView(
+          TypeLiteral> viewType, String method, String name) {
+    return bind(viewType).annotatedWith(export(method, name));
+  }
+
   private static Export export(String method, String name) {
     if (name.length() > 1 && name.startsWith("/")) {
       // Views may be bound as "/" to mean the resource itself, or
@@ -137,6 +149,33 @@ public abstract class RestApiModule extends FactoryModule {
     }
   }
 
+  public static class CreateViewBinder {
+    private final LinkedBindingBuilder> binder;
+
+    private CreateViewBinder(LinkedBindingBuilder> binder) {
+      this.binder = binder;
+    }
+
+    public > ScopedBindingBuilder to(
+        Class impl) {
+      return binder.to(impl);
+    }
+
+    public > void toInstance(T impl) {
+      binder.toInstance(impl);
+    }
+
+    public 
>
+        ScopedBindingBuilder toProvider(Class extends Provider extends T>> providerType) {
+      return binder.toProvider(providerType);
+    }
+
+    public 
>
+        ScopedBindingBuilder toProvider(Provider extends T> provider) {
+      return binder.toProvider(provider);
+    }
+  }
+
   public static class ChildCollectionBinder
 {
     private final LinkedBindingBuilder> binder;
 
diff --git a/java/com/google/gerrit/extensions/restapi/RestCreateView.java b/java/com/google/gerrit/extensions/restapi/RestCreateView.java
new file mode 100644
index 0000000000..5278deb0a9
--- /dev/null
+++ b/java/com/google/gerrit/extensions/restapi/RestCreateView.java
@@ -0,0 +1,45 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// 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 com.google.gerrit.extensions.restapi;
+
+/**
+ * RestView that supports accepting input and creating a resource.
+ *
+ * The input must be supplied as JSON as the body of the HTTP request. Create views can be
+ * invoked by the HTTP methods {@code PUT} and {@code POST}.
+ *
+ * 
The RestCreateView is only invoked when the parse method of the {@code RestCollection} throws
+ * {@link ResourceNotFoundException}, and hence the resource doesn't exist yet.
+ *
+ * @param 
 type of the parent resource
+ * @param  type of the child resource that is created
+ * @param  type of input the JSON parser will parse the input into.
+ */
+public interface RestCreateView
+    extends RestView {
+
+  /**
+   * Process the view operation by creating the resource.
+   *
+   * @param parentResource parent resource of the resource that should be created
+   * @param input input after parsing from request.
+   * @return result to return to the client. Use {@link BinaryResult} to avoid automatic conversion
+   *     to JSON.
+   * @throws RestApiException if the resource creation is rejected
+   * @throws Exception the implementation of the view failed. The exception will be logged and HTTP
+   *     500 Internal Server Error will be returned to the client.
+   */
+  Object apply(P parentResource, IdString id, I input) throws Exception;
+}
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 546bb9fd8b..1196e470f7 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -68,7 +68,6 @@ import com.google.gerrit.common.RawInputUtil;
 import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.extensions.registration.DynamicItem;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AcceptsDelete;
 import com.google.gerrit.extensions.restapi.AcceptsPost;
 import com.google.gerrit.extensions.restapi.AuthException;
@@ -88,6 +87,7 @@ import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestCollection;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.extensions.restapi.RestResource;
@@ -323,11 +323,15 @@ public class RestApiServlet extends HttpServlet {
             checkPreconditions(req);
           }
         } catch (ResourceNotFoundException e) {
-          if (rc instanceof AcceptsCreate && path.isEmpty() && (isPost(req) || isPut(req))) {
-            @SuppressWarnings("unchecked")
-            AcceptsCreate ac = (AcceptsCreate) rc;
-            viewData = new ViewData(null, ac.create(rsrc, id));
+          if (!path.isEmpty() || (!isPost(req) && !isPut(req))) {
+            throw e;
+          }
+
+          RestView createView = rc.views().get("gerrit", "CREATE./");
+          if (createView != null) {
+            viewData = new ViewData(null, createView);
             status = SC_CREATED;
+            path.add(id);
           } else {
             throw e;
           }
@@ -365,12 +369,20 @@ public class RestApiServlet extends HttpServlet {
           checkPreconditions(req);
           viewData = new ViewData(null, null);
         } catch (ResourceNotFoundException e) {
-          if (c instanceof AcceptsCreate && path.isEmpty() && (isPost(req) || isPut(req))) {
-            @SuppressWarnings("unchecked")
-            AcceptsCreate ac = (AcceptsCreate) c;
-            viewData = new ViewData(viewData.pluginName, ac.create(rsrc, id));
-            status = SC_CREATED;
-          } else if (c instanceof AcceptsDelete && path.isEmpty() && isDelete(req)) {
+          if (!path.isEmpty()) {
+            throw e;
+          }
+
+          if (isPost(req) || isPut(req)) {
+            RestView createView = c.views().get("gerrit", "CREATE./");
+            if (createView != null) {
+              viewData = new ViewData(null, createView);
+              status = SC_CREATED;
+              path.add(id);
+            } else {
+              throw e;
+            }
+          } else if (c instanceof AcceptsDelete && isDelete(req)) {
             @SuppressWarnings("unchecked")
             AcceptsDelete ac = (AcceptsDelete) c;
             viewData = new ViewData(viewData.pluginName, ac.delete(rsrc, id));
@@ -409,6 +421,19 @@ public class RestApiServlet extends HttpServlet {
             ServletUtils.consumeRequestBody(is);
           }
         }
+      } else if (viewData.view instanceof RestCreateView, ?, ?>) {
+        @SuppressWarnings("unchecked")
+        RestCreateView m =
+            (RestCreateView) viewData.view;
+
+        Type type = inputType(m);
+        inputRequestBody = parseRequest(req, type);
+        result = m.apply(rsrc, path.get(0), inputRequestBody);
+        if (inputRequestBody instanceof RawInput) {
+          try (InputStream is = req.getInputStream()) {
+            ServletUtils.consumeRequestBody(is);
+          }
+        }
       } else {
         throw new ResourceNotFoundException();
       }
@@ -735,6 +760,24 @@ public class RestApiServlet extends HttpServlet {
     return ((ParameterizedType) supertype).getActualTypeArguments()[1];
   }
 
+  private static Type inputType(RestCreateView m) {
+    // MyCreateView implements RestCreateView
+    TypeLiteral> typeLiteral = TypeLiteral.get(m.getClass());
+
+    // RestCreateView
+    // This is smart enough to resolve even when there are intervening subclasses, even if they have
+    // reordered type arguments.
+    TypeLiteral> supertypeLiteral = typeLiteral.getSupertype(RestCreateView.class);
+
+    Type supertype = supertypeLiteral.getType();
+    checkState(
+        supertype instanceof ParameterizedType,
+        "supertype of %s is not parameterized: %s",
+        typeLiteral,
+        supertypeLiteral);
+    return ((ParameterizedType) supertype).getActualTypeArguments()[2];
+  }
+
   private Object parseRequest(HttpServletRequest req, Type type)
       throws IOException, BadRequestException, SecurityException, IllegalArgumentException,
           NoSuchMethodException, IllegalAccessException, InstantiationException,
diff --git a/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java b/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
index ead73c496f..2d6ef2cc88 100644
--- a/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
+++ b/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
@@ -111,7 +111,7 @@ public class AccountApiImpl implements AccountApi {
   private final Stars.Get starsGet;
   private final Stars.Post starsPost;
   private final GetEmails getEmails;
-  private final CreateEmail.Factory createEmailFactory;
+  private final CreateEmail createEmail;
   private final DeleteEmail deleteEmail;
   private final GpgApiAdapter gpgApiAdapter;
   private final GetSshKeys getSshKeys;
@@ -151,7 +151,7 @@ public class AccountApiImpl implements AccountApi {
       Stars.Get starsGet,
       Stars.Post starsPost,
       GetEmails getEmails,
-      CreateEmail.Factory createEmailFactory,
+      CreateEmail createEmail,
       DeleteEmail deleteEmail,
       GpgApiAdapter gpgApiAdapter,
       GetSshKeys getSshKeys,
@@ -190,7 +190,7 @@ public class AccountApiImpl implements AccountApi {
     this.starsGet = starsGet;
     this.starsPost = starsPost;
     this.getEmails = getEmails;
-    this.createEmailFactory = createEmailFactory;
+    this.createEmail = createEmail;
     this.deleteEmail = deleteEmail;
     this.getSshKeys = getSshKeys;
     this.addSshKey = addSshKey;
@@ -341,9 +341,8 @@ public class AccountApiImpl implements AccountApi {
   @Override
   public void starChange(String changeId) throws RestApiException {
     try {
-      ChangeResource rsrc = changes.parse(TopLevelResource.INSTANCE, IdString.fromUrl(changeId));
-      starredChangesCreate.setChange(rsrc);
-      starredChangesCreate.apply(account, new StarredChanges.EmptyInput());
+      starredChangesCreate.apply(
+          account, IdString.fromUrl(changeId), new StarredChanges.EmptyInput());
     } catch (Exception e) {
       throw asRestApiException("Cannot star change", e);
     }
@@ -412,7 +411,7 @@ public class AccountApiImpl implements AccountApi {
   public void addEmail(EmailInput input) throws RestApiException {
     AccountResource.Email rsrc = new AccountResource.Email(account.getUser(), input.email);
     try {
-      createEmailFactory.create(input.email).apply(rsrc, input);
+      createEmail.apply(rsrc, IdString.fromDecoded(input.email), input);
     } catch (Exception e) {
       throw asRestApiException("Cannot add email", e);
     }
@@ -432,7 +431,7 @@ public class AccountApiImpl implements AccountApi {
   public EmailApi createEmail(EmailInput input) throws RestApiException {
     AccountResource.Email rsrc = new AccountResource.Email(account.getUser(), input.email);
     try {
-      createEmailFactory.create(input.email).apply(rsrc, input);
+      createEmail.apply(rsrc, IdString.fromDecoded(input.email), input);
       return email(rsrc.getEmail());
     } catch (Exception e) {
       throw asRestApiException("Cannot create email", e);
diff --git a/java/com/google/gerrit/server/api/accounts/AccountsImpl.java b/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
index 44b6610d77..ca5aca4c75 100644
--- a/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
+++ b/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
@@ -45,7 +45,7 @@ public class AccountsImpl implements Accounts {
   private final AccountApiImpl.Factory api;
   private final PermissionBackend permissionBackend;
   private final Provider self;
-  private final CreateAccount.Factory createAccount;
+  private final CreateAccount createAccount;
   private final Provider queryAccountsProvider;
 
   @Inject
@@ -54,7 +54,7 @@ public class AccountsImpl implements Accounts {
       AccountApiImpl.Factory api,
       PermissionBackend permissionBackend,
       Provider self,
-      CreateAccount.Factory createAccount,
+      CreateAccount createAccount,
       Provider queryAccountsProvider) {
     this.accounts = accounts;
     this.api = api;
@@ -99,9 +99,13 @@ public class AccountsImpl implements Accounts {
       throw new BadRequestException("AccountInput must specify username");
     }
     try {
-      CreateAccount impl = createAccount.create(in.username);
-      permissionBackend.currentUser().checkAny(GlobalPermission.fromAnnotation(impl.getClass()));
-      AccountInfo info = impl.apply(TopLevelResource.INSTANCE, in).value();
+      permissionBackend
+          .currentUser()
+          .checkAny(GlobalPermission.fromAnnotation(createAccount.getClass()));
+      AccountInfo info =
+          createAccount
+              .apply(TopLevelResource.INSTANCE, IdString.fromDecoded(in.username), in)
+              .value();
       return id(info._accountId);
     } catch (Exception e) {
       throw asRestApiException("Cannot create account " + in.username, e);
diff --git a/java/com/google/gerrit/server/api/groups/GroupsImpl.java b/java/com/google/gerrit/server/api/groups/GroupsImpl.java
index 247be44bf2..bac6649928 100644
--- a/java/com/google/gerrit/server/api/groups/GroupsImpl.java
+++ b/java/com/google/gerrit/server/api/groups/GroupsImpl.java
@@ -49,7 +49,7 @@ class GroupsImpl implements Groups {
   private final Provider listGroups;
   private final Provider queryGroups;
   private final PermissionBackend permissionBackend;
-  private final CreateGroup.Factory createGroup;
+  private final CreateGroup createGroup;
   private final GroupApiImpl.Factory api;
 
   @Inject
@@ -60,7 +60,7 @@ class GroupsImpl implements Groups {
       Provider listGroups,
       Provider queryGroups,
       PermissionBackend permissionBackend,
-      CreateGroup.Factory createGroup,
+      CreateGroup createGroup,
       GroupApiImpl.Factory api) {
     this.accounts = accounts;
     this.groups = groups;
@@ -90,9 +90,11 @@ class GroupsImpl implements Groups {
       throw new BadRequestException("GroupInput must specify name");
     }
     try {
-      CreateGroup impl = createGroup.create(in.name);
-      permissionBackend.currentUser().checkAny(GlobalPermission.fromAnnotation(impl.getClass()));
-      GroupInfo info = impl.apply(TopLevelResource.INSTANCE, in);
+      permissionBackend
+          .currentUser()
+          .checkAny(GlobalPermission.fromAnnotation(createGroup.getClass()));
+      GroupInfo info =
+          createGroup.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(in.name), in);
       return id(info.id);
     } catch (Exception e) {
       throw asRestApiException("Cannot create group " + in.name, e);
diff --git a/java/com/google/gerrit/server/api/projects/BranchApiImpl.java b/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
index 78b34b878a..b3506fc5d7 100644
--- a/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
+++ b/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
@@ -46,7 +46,7 @@ public class BranchApiImpl implements BranchApi {
   }
 
   private final BranchesCollection branches;
-  private final CreateBranch.Factory createBranchFactory;
+  private final CreateBranch createBranch;
   private final DeleteBranch deleteBranch;
   private final FilesCollection filesCollection;
   private final GetBranch getBranch;
@@ -58,7 +58,7 @@ public class BranchApiImpl implements BranchApi {
   @Inject
   BranchApiImpl(
       BranchesCollection branches,
-      CreateBranch.Factory createBranchFactory,
+      CreateBranch createBranch,
       DeleteBranch deleteBranch,
       FilesCollection filesCollection,
       GetBranch getBranch,
@@ -67,7 +67,7 @@ public class BranchApiImpl implements BranchApi {
       @Assisted ProjectResource project,
       @Assisted String ref) {
     this.branches = branches;
-    this.createBranchFactory = createBranchFactory;
+    this.createBranch = createBranch;
     this.deleteBranch = deleteBranch;
     this.filesCollection = filesCollection;
     this.getBranch = getBranch;
@@ -80,7 +80,7 @@ public class BranchApiImpl implements BranchApi {
   @Override
   public BranchApi create(BranchInput input) throws RestApiException {
     try {
-      createBranchFactory.create(ref).apply(project, input);
+      createBranch.apply(project, IdString.fromDecoded(ref), input);
       return this;
     } catch (Exception e) {
       throw asRestApiException("Cannot create branch", e);
diff --git a/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java b/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
index 46d9180319..1065bffde0 100644
--- a/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
+++ b/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
@@ -88,7 +88,7 @@ public class ProjectApiImpl implements ProjectApi {
   }
 
   private final PermissionBackend permissionBackend;
-  private final CreateProject.Factory createProjectFactory;
+  private final CreateProject createProject;
   private final ProjectApiImpl.Factory projectApi;
   private final ProjectsCollection projects;
   private final GetDescription getDescription;
@@ -122,7 +122,7 @@ public class ProjectApiImpl implements ProjectApi {
   @AssistedInject
   ProjectApiImpl(
       PermissionBackend permissionBackend,
-      CreateProject.Factory createProjectFactory,
+      CreateProject createProject,
       ProjectApiImpl.Factory projectApi,
       ProjectsCollection projects,
       GetDescription getDescription,
@@ -153,7 +153,7 @@ public class ProjectApiImpl implements ProjectApi {
       @Assisted ProjectResource project) {
     this(
         permissionBackend,
-        createProjectFactory,
+        createProject,
         projectApi,
         projects,
         getDescription,
@@ -188,7 +188,7 @@ public class ProjectApiImpl implements ProjectApi {
   @AssistedInject
   ProjectApiImpl(
       PermissionBackend permissionBackend,
-      CreateProject.Factory createProjectFactory,
+      CreateProject createProject,
       ProjectApiImpl.Factory projectApi,
       ProjectsCollection projects,
       GetDescription getDescription,
@@ -219,7 +219,7 @@ public class ProjectApiImpl implements ProjectApi {
       @Assisted String name) {
     this(
         permissionBackend,
-        createProjectFactory,
+        createProject,
         projectApi,
         projects,
         getDescription,
@@ -253,7 +253,7 @@ public class ProjectApiImpl implements ProjectApi {
 
   private ProjectApiImpl(
       PermissionBackend permissionBackend,
-      CreateProject.Factory createProjectFactory,
+      CreateProject createProject,
       ProjectApiImpl.Factory projectApi,
       ProjectsCollection projects,
       GetDescription getDescription,
@@ -284,7 +284,7 @@ public class ProjectApiImpl implements ProjectApi {
       SetParent setParent,
       String name) {
     this.permissionBackend = permissionBackend;
-    this.createProjectFactory = createProjectFactory;
+    this.createProject = createProject;
     this.projectApi = projectApi;
     this.projects = projects;
     this.getDescription = getDescription;
@@ -330,9 +330,10 @@ public class ProjectApiImpl implements ProjectApi {
       if (in.name != null && !name.equals(in.name)) {
         throw new BadRequestException("name must match input.name");
       }
-      CreateProject impl = createProjectFactory.create(name);
-      permissionBackend.currentUser().checkAny(GlobalPermission.fromAnnotation(impl.getClass()));
-      impl.apply(TopLevelResource.INSTANCE, in);
+      permissionBackend
+          .currentUser()
+          .checkAny(GlobalPermission.fromAnnotation(createProject.getClass()));
+      createProject.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(name), in);
       return projectApi.create(projects.parse(name));
     } catch (Exception e) {
       throw asRestApiException("Cannot create project: " + e.getMessage(), e);
diff --git a/java/com/google/gerrit/server/api/projects/TagApiImpl.java b/java/com/google/gerrit/server/api/projects/TagApiImpl.java
index 03e2162297..005486a870 100644
--- a/java/com/google/gerrit/server/api/projects/TagApiImpl.java
+++ b/java/com/google/gerrit/server/api/projects/TagApiImpl.java
@@ -39,7 +39,7 @@ public class TagApiImpl implements TagApi {
   }
 
   private final ListTags listTags;
-  private final CreateTag.Factory createTagFactory;
+  private final CreateTag createTag;
   private final DeleteTag deleteTag;
   private final TagsCollection tags;
   private final String ref;
@@ -48,13 +48,13 @@ public class TagApiImpl implements TagApi {
   @Inject
   TagApiImpl(
       ListTags listTags,
-      CreateTag.Factory createTagFactory,
+      CreateTag createTag,
       DeleteTag deleteTag,
       TagsCollection tags,
       @Assisted ProjectResource project,
       @Assisted String ref) {
     this.listTags = listTags;
-    this.createTagFactory = createTagFactory;
+    this.createTag = createTag;
     this.deleteTag = deleteTag;
     this.tags = tags;
     this.project = project;
@@ -64,7 +64,7 @@ public class TagApiImpl implements TagApi {
   @Override
   public TagApi create(TagInput input) throws RestApiException {
     try {
-      createTagFactory.create(ref).apply(project, input);
+      createTag.apply(project, IdString.fromDecoded(ref), input);
       return this;
     } catch (Exception e) {
       throw asRestApiException("Cannot create tag", e);
diff --git a/java/com/google/gerrit/server/plugins/InstallPlugin.java b/java/com/google/gerrit/server/plugins/InstallPlugin.java
index ee9099eca3..f1c1fe75b4 100644
--- a/java/com/google/gerrit/server/plugins/InstallPlugin.java
+++ b/java/com/google/gerrit/server/plugins/InstallPlugin.java
@@ -19,8 +19,10 @@ import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.extensions.common.InstallPluginInput;
 import com.google.gerrit.extensions.common.PluginInfo;
 import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.inject.Inject;
@@ -91,6 +93,26 @@ public class InstallPlugin implements RestModifyView {
+    private final PluginLoader loader;
+    private final Provider install;
+
+    @Inject
+    Create(PluginLoader loader, Provider install) {
+      this.loader = loader;
+      this.install = install;
+    }
+
+    @Override
+    public Response apply(
+        TopLevelResource parentResource, IdString id, InstallPluginInput input) throws Exception {
+      loader.checkRemoteAdminEnabled();
+      return install.get().setName(id.get()).setCreated(true).apply(parentResource, input);
+    }
+  }
+
   @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
   static class Overwrite implements RestModifyView {
     private final Provider install;
diff --git a/java/com/google/gerrit/server/plugins/PluginRestApiModule.java b/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
index cad0e1e616..8dbea781d1 100644
--- a/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
+++ b/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
@@ -27,6 +27,7 @@ public class PluginRestApiModule extends RestApiModule {
     requireBinding(Key.get(PluginUser.Factory.class));
     bind(PluginsCollection.class);
     DynamicMap.mapOf(binder(), PLUGIN_KIND);
+    create(PLUGIN_KIND).to(InstallPlugin.Create.class);
     put(PLUGIN_KIND).to(InstallPlugin.Overwrite.class);
     delete(PLUGIN_KIND).to(DisablePlugin.class);
     get(PLUGIN_KIND, "status").to(GetStatus.class);
diff --git a/java/com/google/gerrit/server/plugins/PluginsCollection.java b/java/com/google/gerrit/server/plugins/PluginsCollection.java
index 0d2a0188e4..7cc006e5bb 100644
--- a/java/com/google/gerrit/server/plugins/PluginsCollection.java
+++ b/java/com/google/gerrit/server/plugins/PluginsCollection.java
@@ -15,10 +15,8 @@
 package com.google.gerrit.server.plugins;
 
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestCollection;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
@@ -27,24 +25,18 @@ import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 @Singleton
-public class PluginsCollection
-    implements RestCollection, AcceptsCreate {
+public class PluginsCollection implements RestCollection {
 
   private final DynamicMap> views;
   private final PluginLoader loader;
   private final Provider list;
-  private final Provider install;
 
   @Inject
   public PluginsCollection(
-      DynamicMap> views,
-      PluginLoader loader,
-      Provider list,
-      Provider install) {
+      DynamicMap> views, PluginLoader loader, Provider list) {
     this.views = views;
     this.loader = loader;
     this.list = list;
-    this.install = install;
   }
 
   @Override
@@ -66,12 +58,6 @@ public class PluginsCollection
     return new PluginResource(p);
   }
 
-  @Override
-  public InstallPlugin create(TopLevelResource parent, IdString id) throws RestApiException {
-    loader.checkRemoteAdminEnabled();
-    return install.get().setName(id.get()).setCreated(true);
-  }
-
   @Override
   public DynamicMap> views() {
     return views;
diff --git a/java/com/google/gerrit/server/restapi/account/AccountsCollection.java b/java/com/google/gerrit/server/restapi/account/AccountsCollection.java
index 6cec565912..370833cd31 100644
--- a/java/com/google/gerrit/server/restapi/account/AccountsCollection.java
+++ b/java/com/google/gerrit/server/restapi/account/AccountsCollection.java
@@ -16,11 +16,9 @@ package com.google.gerrit.server.restapi.account;
 
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestCollection;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
@@ -40,15 +38,13 @@ import java.io.IOException;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 @Singleton
-public class AccountsCollection
-    implements RestCollection, AcceptsCreate {
+public class AccountsCollection implements RestCollection {
   private final Provider self;
   private final AccountResolver resolver;
   private final AccountControl.Factory accountControlFactory;
   private final IdentifiedUser.GenericFactory userFactory;
   private final Provider list;
   private final DynamicMap> views;
-  private final CreateAccount.Factory createAccountFactory;
 
   @Inject
   public AccountsCollection(
@@ -57,15 +53,13 @@ public class AccountsCollection
       AccountControl.Factory accountControlFactory,
       IdentifiedUser.GenericFactory userFactory,
       Provider list,
-      DynamicMap> views,
-      CreateAccount.Factory createAccountFactory) {
+      DynamicMap> views) {
     this.self = self;
     this.resolver = resolver;
     this.accountControlFactory = accountControlFactory;
     this.userFactory = userFactory;
     this.list = list;
     this.views = views;
-    this.createAccountFactory = createAccountFactory;
   }
 
   @Override
@@ -159,9 +153,4 @@ public class AccountsCollection
   public DynamicMap> views() {
     return views;
   }
-
-  @Override
-  public CreateAccount create(TopLevelResource parent, IdString username) throws RestApiException {
-    return createAccountFactory.create(username.get());
-  }
 }
diff --git a/java/com/google/gerrit/server/restapi/account/CreateAccount.java b/java/com/google/gerrit/server/restapi/account/CreateAccount.java
index 404b3d3462..b1581abbaf 100644
--- a/java/com/google/gerrit/server/restapi/account/CreateAccount.java
+++ b/java/com/google/gerrit/server/restapi/account/CreateAccount.java
@@ -29,9 +29,10 @@ import com.google.gerrit.extensions.api.accounts.AccountInput;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.reviewdb.client.Account;
@@ -40,6 +41,7 @@ import com.google.gerrit.server.Sequences;
 import com.google.gerrit.server.UserInitiated;
 import com.google.gerrit.server.account.AccountExternalIdCreator;
 import com.google.gerrit.server.account.AccountLoader;
+import com.google.gerrit.server.account.AccountResource;
 import com.google.gerrit.server.account.AccountsUpdate;
 import com.google.gerrit.server.account.VersionedAuthorizedKeys;
 import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
@@ -52,7 +54,6 @@ import com.google.gerrit.server.ssh.SshKeyCache;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-import com.google.inject.assistedinject.Assisted;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -61,11 +62,8 @@ import java.util.Set;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 @RequiresCapability(GlobalCapability.CREATE_ACCOUNT)
-public class CreateAccount implements RestModifyView {
-  public interface Factory {
-    CreateAccount create(String username);
-  }
-
+public class CreateAccount
+    implements RestCreateView {
   private final Sequences seq;
   private final GroupsCollection groupsCollection;
   private final VersionedAuthorizedKeys.Accessor authorizedKeys;
@@ -75,7 +73,6 @@ public class CreateAccount implements RestModifyView externalIdCreators;
   private final Provider groupsUpdate;
   private final OutgoingEmailValidator validator;
-  private final String username;
 
   @Inject
   CreateAccount(
@@ -87,8 +84,7 @@ public class CreateAccount implements RestModifyView externalIdCreators,
       @UserInitiated Provider groupsUpdate,
-      OutgoingEmailValidator validator,
-      @Assisted String username) {
+      OutgoingEmailValidator validator) {
     this.seq = seq;
     this.groupsCollection = groupsCollection;
     this.authorizedKeys = authorizedKeys;
@@ -98,23 +94,23 @@ public class CreateAccount implements RestModifyView apply(TopLevelResource rsrc, @Nullable AccountInput input)
+  public Response apply(
+      TopLevelResource rsrc, IdString id, @Nullable AccountInput input)
       throws BadRequestException, ResourceConflictException, UnprocessableEntityException,
           OrmException, IOException, ConfigInvalidException {
-    return apply(input != null ? input : new AccountInput());
+    return apply(id, input != null ? input : new AccountInput());
   }
 
-  public Response apply(AccountInput input)
+  public Response apply(IdString id, AccountInput input)
       throws BadRequestException, ResourceConflictException, UnprocessableEntityException,
           OrmException, IOException, ConfigInvalidException {
+    String username = id.get();
     if (input.username != null && !username.equals(input.username)) {
       throw new BadRequestException("username must match URL");
     }
-
     if (!ExternalId.isValidUsername(username)) {
       throw new BadRequestException(
           "Username '" + username + "' must contain only letters, numbers, _, - or .");
@@ -122,19 +118,19 @@ public class CreateAccount implements RestModifyView groups = parseGroups(input.groups);
 
-    Account.Id id = new Account.Id(seq.nextAccountId());
+    Account.Id accountId = new Account.Id(seq.nextAccountId());
     List extIds = new ArrayList<>();
 
     if (input.email != null) {
       if (!validator.isValid(input.email)) {
         throw new BadRequestException("invalid email address");
       }
-      extIds.add(ExternalId.createEmail(id, input.email));
+      extIds.add(ExternalId.createEmail(accountId, input.email));
     }
 
-    extIds.add(ExternalId.createUsername(username, id, input.httpPassword));
+    extIds.add(ExternalId.createUsername(username, accountId, input.httpPassword));
     for (AccountExternalIdCreator c : externalIdCreators) {
-      extIds.addAll(c.create(id, username, input.email));
+      extIds.addAll(c.create(accountId, username, input.email));
     }
 
     try {
@@ -142,7 +138,7 @@ public class CreateAccount implements RestModifyView u.setFullName(input.name).setPreferredEmail(input.email).addExternalIds(extIds));
     } catch (DuplicateExternalIdKeyException e) {
       if (e.getDuplicateKey().isScheme(SCHEME_USERNAME)) {
@@ -159,7 +155,7 @@ public class CreateAccount implements RestModifyView {
+public class CreateEmail
+    implements RestCreateView {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
-  public interface Factory {
-    CreateEmail create(String email);
-  }
-
   private final Provider self;
   private final Realm realm;
   private final PermissionBackend permissionBackend;
@@ -61,7 +58,6 @@ public class CreateEmail implements RestModifyView
   private final RegisterNewEmailSender.Factory registerNewEmailFactory;
   private final PutPreferred putPreferred;
   private final OutgoingEmailValidator validator;
-  private final String email;
   private final boolean isDevMode;
 
   @Inject
@@ -73,8 +69,7 @@ public class CreateEmail implements RestModifyView
       AccountManager accountManager,
       RegisterNewEmailSender.Factory registerNewEmailFactory,
       PutPreferred putPreferred,
-      OutgoingEmailValidator validator,
-      @Assisted String email) {
+      OutgoingEmailValidator validator) {
     this.self = self;
     this.realm = realm;
     this.permissionBackend = permissionBackend;
@@ -82,12 +77,11 @@ public class CreateEmail implements RestModifyView
     this.registerNewEmailFactory = registerNewEmailFactory;
     this.putPreferred = putPreferred;
     this.validator = validator;
-    this.email = email != null ? email.trim() : null;
     this.isDevMode = authConfig.getAuthType() == DEVELOPMENT_BECOME_ANY_ACCOUNT;
   }
 
   @Override
-  public Response apply(AccountResource rsrc, EmailInput input)
+  public Response apply(AccountResource rsrc, IdString id, EmailInput input)
       throws RestApiException, OrmException, EmailException, MethodNotAllowedException, IOException,
           ConfigInvalidException, PermissionBackendException {
     if (input == null) {
@@ -102,13 +96,15 @@ public class CreateEmail implements RestModifyView
       throw new MethodNotAllowedException("realm does not allow adding emails");
     }
 
-    return apply(rsrc.getUser(), input);
+    return apply(rsrc.getUser(), id, input);
   }
 
   /** To be used from plugins that want to create emails without permission checks. */
-  public Response apply(IdentifiedUser user, EmailInput input)
+  public Response apply(IdentifiedUser user, IdString id, EmailInput input)
       throws RestApiException, OrmException, EmailException, MethodNotAllowedException, IOException,
           ConfigInvalidException, PermissionBackendException {
+    String email = id.get().trim();
+
     if (input == null) {
       input = new EmailInput();
     }
diff --git a/java/com/google/gerrit/server/restapi/account/EmailsCollection.java b/java/com/google/gerrit/server/restapi/account/EmailsCollection.java
index 8694da04b6..434b9d6174 100644
--- a/java/com/google/gerrit/server/restapi/account/EmailsCollection.java
+++ b/java/com/google/gerrit/server/restapi/account/EmailsCollection.java
@@ -16,7 +16,6 @@ package com.google.gerrit.server.restapi.account;
 
 import com.google.common.base.Strings;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ChildCollection;
 import com.google.gerrit.extensions.restapi.IdString;
@@ -33,27 +32,22 @@ import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 @Singleton
-public class EmailsCollection
-    implements ChildCollection,
-        AcceptsCreate {
+public class EmailsCollection implements ChildCollection {
   private final DynamicMap> views;
   private final GetEmails list;
   private final Provider self;
   private final PermissionBackend permissionBackend;
-  private final CreateEmail.Factory createEmailFactory;
 
   @Inject
   EmailsCollection(
       DynamicMap> views,
       GetEmails list,
       Provider self,
-      PermissionBackend permissionBackend,
-      CreateEmail.Factory createEmailFactory) {
+      PermissionBackend permissionBackend) {
     this.views = views;
     this.list = list;
     this.self = self;
     this.permissionBackend = permissionBackend;
-    this.createEmailFactory = createEmailFactory;
   }
 
   @Override
@@ -85,9 +79,4 @@ public class EmailsCollection
   public DynamicMap> views() {
     return views;
   }
-
-  @Override
-  public CreateEmail create(AccountResource parent, IdString email) {
-    return createEmailFactory.create(email.get());
-  }
 }
diff --git a/java/com/google/gerrit/server/restapi/account/Module.java b/java/com/google/gerrit/server/restapi/account/Module.java
index ca5f08e434..7b09bc9cae 100644
--- a/java/com/google/gerrit/server/restapi/account/Module.java
+++ b/java/com/google/gerrit/server/restapi/account/Module.java
@@ -43,6 +43,7 @@ public class Module extends RestApiModule {
     DynamicMap.mapOf(binder(), STARRED_CHANGE_KIND);
     DynamicMap.mapOf(binder(), STAR_KIND);
 
+    create(ACCOUNT_KIND).to(CreateAccount.class);
     put(ACCOUNT_KIND).to(PutAccount.class);
     get(ACCOUNT_KIND).to(GetAccount.class);
     get(ACCOUNT_KIND, "detail").to(GetDetail.class);
@@ -58,6 +59,7 @@ public class Module extends RestApiModule {
     put(ACCOUNT_KIND, "active").to(PutActive.class);
     delete(ACCOUNT_KIND, "active").to(DeleteActive.class);
     child(ACCOUNT_KIND, "emails").to(EmailsCollection.class);
+    create(EMAIL_KIND).to(CreateEmail.class);
     get(EMAIL_KIND).to(GetEmail.class);
     put(EMAIL_KIND).to(PutEmail.class);
     delete(EMAIL_KIND).to(DeleteEmail.class);
@@ -93,6 +95,7 @@ public class Module extends RestApiModule {
     put(ACCOUNT_KIND, "agreements").to(PutAgreement.class);
 
     child(ACCOUNT_KIND, "starred.changes").to(StarredChanges.class);
+    create(STARRED_CHANGE_KIND).to(StarredChanges.Create.class);
     put(STARRED_CHANGE_KIND).to(StarredChanges.Put.class);
     delete(STARRED_CHANGE_KIND).to(StarredChanges.Delete.class);
     bind(StarredChanges.Create.class);
@@ -104,8 +107,6 @@ public class Module extends RestApiModule {
     get(ACCOUNT_KIND, "external.ids").to(GetExternalIds.class);
     post(ACCOUNT_KIND, "external.ids:delete").to(DeleteExternalIds.class);
 
-    factory(CreateAccount.Factory.class);
-    factory(CreateEmail.Factory.class);
     factory(AccountsUpdate.Factory.class);
   }
 
diff --git a/java/com/google/gerrit/server/restapi/account/StarredChanges.java b/java/com/google/gerrit/server/restapi/account/StarredChanges.java
index e804b64a6d..e049539855 100644
--- a/java/com/google/gerrit/server/restapi/account/StarredChanges.java
+++ b/java/com/google/gerrit/server/restapi/account/StarredChanges.java
@@ -16,7 +16,6 @@ package com.google.gerrit.server.restapi.account;
 
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ChildCollection;
@@ -25,6 +24,7 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.extensions.restapi.RestView;
@@ -49,24 +49,20 @@ import java.io.IOException;
 
 @Singleton
 public class StarredChanges
-    implements ChildCollection,
-        AcceptsCreate {
+    implements ChildCollection {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final ChangesCollection changes;
   private final DynamicMap> views;
-  private final Provider createProvider;
   private final StarredChangesUtil starredChangesUtil;
 
   @Inject
   StarredChanges(
       ChangesCollection changes,
       DynamicMap> views,
-      Provider createProvider,
       StarredChangesUtil starredChangesUtil) {
     this.changes = changes;
     this.views = views;
-    this.createProvider = createProvider;
     this.starredChangesUtil = starredChangesUtil;
   }
 
@@ -101,42 +97,40 @@ public class StarredChanges
     };
   }
 
-  @Override
-  public RestModifyView create(AccountResource parent, IdString id)
-      throws RestApiException {
-    try {
-      return createProvider.get().setChange(changes.parse(TopLevelResource.INSTANCE, id));
-    } catch (ResourceNotFoundException e) {
-      throw new UnprocessableEntityException(String.format("change %s not found", id.get()));
-    } catch (OrmException | PermissionBackendException | IOException e) {
-      logger.atSevere().withCause(e).log("cannot resolve change");
-      throw new UnprocessableEntityException("internal server error");
-    }
-  }
-
   @Singleton
-  public static class Create implements RestModifyView {
+  public static class Create
+      implements RestCreateView {
     private final Provider self;
+    private final ChangesCollection changes;
     private final StarredChangesUtil starredChangesUtil;
-    private ChangeResource change;
 
     @Inject
-    Create(Provider self, StarredChangesUtil starredChangesUtil) {
+    Create(
+        Provider self,
+        ChangesCollection changes,
+        StarredChangesUtil starredChangesUtil) {
       this.self = self;
+      this.changes = changes;
       this.starredChangesUtil = starredChangesUtil;
     }
 
-    public Create setChange(ChangeResource change) {
-      this.change = change;
-      return this;
-    }
-
     @Override
-    public Response> apply(AccountResource rsrc, EmptyInput in)
+    public Response> apply(AccountResource rsrc, IdString id, EmptyInput in)
         throws RestApiException, OrmException, IOException {
       if (!self.get().hasSameAccountId(rsrc.getUser())) {
         throw new AuthException("not allowed to add starred change");
       }
+
+      ChangeResource change;
+      try {
+        change = changes.parse(TopLevelResource.INSTANCE, id);
+      } catch (ResourceNotFoundException e) {
+        throw new UnprocessableEntityException(String.format("change %s not found", id.get()));
+      } catch (OrmException | PermissionBackendException | IOException e) {
+        logger.atSevere().withCause(e).log("cannot resolve change");
+        throw new UnprocessableEntityException("internal server error");
+      }
+
       try {
         starredChangesUtil.star(
             self.get().getAccountId(),
diff --git a/java/com/google/gerrit/server/restapi/change/ChangeEdits.java b/java/com/google/gerrit/server/restapi/change/ChangeEdits.java
index b7a029b89d..1e24a7f523 100644
--- a/java/com/google/gerrit/server/restapi/change/ChangeEdits.java
+++ b/java/com/google/gerrit/server/restapi/change/ChangeEdits.java
@@ -19,7 +19,6 @@ import com.google.gerrit.extensions.common.DiffWebLinkInfo;
 import com.google.gerrit.extensions.common.EditInfo;
 import com.google.gerrit.extensions.common.Input;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AcceptsDelete;
 import com.google.gerrit.extensions.restapi.AcceptsPost;
 import com.google.gerrit.extensions.restapi.AuthException;
@@ -33,6 +32,7 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.extensions.restapi.RestView;
@@ -72,11 +72,9 @@ import org.kohsuke.args4j.Option;
 @Singleton
 public class ChangeEdits
     implements ChildCollection,
-        AcceptsCreate,
         AcceptsPost,
         AcceptsDelete {
   private final DynamicMap> views;
-  private final Create.Factory createFactory;
   private final DeleteFile.Factory deleteFileFactory;
   private final Provider detail;
   private final ChangeEditUtil editUtil;
@@ -85,13 +83,11 @@ public class ChangeEdits
   @Inject
   ChangeEdits(
       DynamicMap> views,
-      Create.Factory createFactory,
       Provider detail,
       ChangeEditUtil editUtil,
       Post post,
       DeleteFile.Factory deleteFileFactory) {
     this.views = views;
-    this.createFactory = createFactory;
     this.detail = detail;
     this.editUtil = editUtil;
     this.post = post;
@@ -118,11 +114,6 @@ public class ChangeEdits
     return new ChangeEditResource(rsrc, edit.get(), id.get());
   }
 
-  @Override
-  public Create create(ChangeResource parent, IdString id) throws RestApiException {
-    return createFactory.create(id.get());
-  }
-
   @Override
   public Post post(ChangeResource parent) throws RestApiException {
     return post;
@@ -141,26 +132,20 @@ public class ChangeEdits
     return deleteFileFactory.create(id.get());
   }
 
-  public static class Create implements RestModifyView {
-
-    interface Factory {
-      Create create(String path);
-    }
-
+  public static class Create
+      implements RestCreateView {
     private final Put putEdit;
-    private final String path;
 
     @Inject
-    Create(Put putEdit, @Assisted String path) {
+    Create(Put putEdit) {
       this.putEdit = putEdit;
-      this.path = path;
     }
 
     @Override
-    public Response> apply(ChangeResource resource, Put.Input input)
+    public Response> apply(ChangeResource resource, IdString id, Put.Input input)
         throws AuthException, ResourceConflictException, IOException, OrmException,
             PermissionBackendException {
-      putEdit.apply(resource, path, input.content);
+      putEdit.apply(resource, id.get(), input.content);
       return Response.none();
     }
   }
diff --git a/java/com/google/gerrit/server/restapi/change/Module.java b/java/com/google/gerrit/server/restapi/change/Module.java
index 7955fa59d6..d27b136ef1 100644
--- a/java/com/google/gerrit/server/restapi/change/Module.java
+++ b/java/com/google/gerrit/server/restapi/change/Module.java
@@ -165,6 +165,7 @@ public class Module extends RestApiModule {
     get(FILE_KIND, "blame").to(GetBlame.class);
 
     child(CHANGE_KIND, "edit").to(ChangeEdits.class);
+    create(CHANGE_EDIT_KIND).to(ChangeEdits.Create.class);
     delete(CHANGE_KIND, "edit").to(DeleteChangeEdit.class);
     child(CHANGE_KIND, "edit:publish").to(PublishChangeEdit.class);
     child(CHANGE_KIND, "edit:rebase").to(RebaseChangeEdit.class);
@@ -180,7 +181,6 @@ public class Module extends RestApiModule {
     get(CHANGE_MESSAGE_KIND).to(GetChangeMessage.class);
 
     factory(AccountLoader.Factory.class);
-    factory(ChangeEdits.Create.Factory.class);
     factory(ChangeEdits.DeleteFile.Factory.class);
     factory(ChangeInserter.Factory.class);
     factory(ChangeResource.Factory.class);
diff --git a/java/com/google/gerrit/server/restapi/group/AddMembers.java b/java/com/google/gerrit/server/restapi/group/AddMembers.java
index 84fbbb7d3f..3e2d1e7de1 100644
--- a/java/com/google/gerrit/server/restapi/group/AddMembers.java
+++ b/java/com/google/gerrit/server/restapi/group/AddMembers.java
@@ -23,8 +23,10 @@ import com.google.gerrit.extensions.client.AuthType;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.DefaultInput;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.reviewdb.client.Account;
@@ -211,22 +213,20 @@ public class AddMembers implements RestModifyView {
     return result;
   }
 
-  public static class PutMember implements RestModifyView {
-
+  public static class CreateMember implements RestCreateView {
     private final AddMembers put;
-    private final String id;
 
-    public PutMember(AddMembers put, String id) {
+    @Inject
+    public CreateMember(AddMembers put) {
       this.put = put;
-      this.id = id;
     }
 
     @Override
-    public AccountInfo apply(GroupResource resource, Input input)
+    public AccountInfo apply(GroupResource resource, IdString id, Input input)
         throws AuthException, MethodNotAllowedException, ResourceNotFoundException, OrmException,
             IOException, ConfigInvalidException {
       AddMembers.Input in = new AddMembers.Input();
-      in._oneMember = id;
+      in._oneMember = id.get();
       try {
         List list = put.apply(resource, in);
         if (list.size() == 1) {
diff --git a/java/com/google/gerrit/server/restapi/group/AddSubgroups.java b/java/com/google/gerrit/server/restapi/group/AddSubgroups.java
index d0be5ac61a..21b698192a 100644
--- a/java/com/google/gerrit/server/restapi/group/AddSubgroups.java
+++ b/java/com/google/gerrit/server/restapi/group/AddSubgroups.java
@@ -23,8 +23,10 @@ import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.DefaultInput;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -127,22 +129,21 @@ public class AddSubgroups implements RestModifyView {
     groupsUpdateProvider.get().updateGroup(parentGroupUuid, groupUpdate);
   }
 
-  public static class PutSubgroup implements RestModifyView {
-
+  public static class CreateSubgroup
+      implements RestCreateView {
     private final AddSubgroups addSubgroups;
-    private final String id;
 
-    public PutSubgroup(AddSubgroups addSubgroups, String id) {
+    @Inject
+    public CreateSubgroup(AddSubgroups addSubgroups) {
       this.addSubgroups = addSubgroups;
-      this.id = id;
     }
 
     @Override
-    public GroupInfo apply(GroupResource resource, Input input)
+    public GroupInfo apply(GroupResource resource, IdString id, Input input)
         throws AuthException, MethodNotAllowedException, ResourceNotFoundException, OrmException,
             IOException, ConfigInvalidException {
       AddSubgroups.Input in = new AddSubgroups.Input();
-      in.groups = ImmutableList.of(id);
+      in.groups = ImmutableList.of(id.get());
       try {
         List list = addSubgroups.apply(resource, in);
         if (list.size() == 1) {
diff --git a/java/com/google/gerrit/server/restapi/group/CreateGroup.java b/java/com/google/gerrit/server/restapi/group/CreateGroup.java
index 79f9688699..6ecb5aa499 100644
--- a/java/com/google/gerrit/server/restapi/group/CreateGroup.java
+++ b/java/com/google/gerrit/server/restapi/group/CreateGroup.java
@@ -26,9 +26,10 @@ import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.extensions.restapi.Url;
@@ -42,6 +43,7 @@ import com.google.gerrit.server.account.CreateGroupArgs;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.account.GroupUUID;
 import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.group.GroupResource;
 import com.google.gerrit.server.group.InternalGroup;
 import com.google.gerrit.server.group.InternalGroupDescription;
 import com.google.gerrit.server.group.SystemGroupBackend;
@@ -54,7 +56,6 @@ import com.google.gwtorm.server.OrmDuplicateKeyException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-import com.google.inject.assistedinject.Assisted;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -67,11 +68,7 @@ import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.PersonIdent;
 
 @RequiresCapability(GlobalCapability.CREATE_GROUP)
-public class CreateGroup implements RestModifyView {
-  public interface Factory {
-    CreateGroup create(@Assisted String name);
-  }
-
+public class CreateGroup implements RestCreateView {
   private final Provider self;
   private final PersonIdent serverIdent;
   private final Provider groupsUpdateProvider;
@@ -82,7 +79,6 @@ public class CreateGroup implements RestModifyView
   private final AddMembers addMembers;
   private final SystemGroupBackend systemGroupBackend;
   private final boolean defaultVisibleToAll;
-  private final String name;
   private final Sequences sequences;
 
   @Inject
@@ -97,7 +93,6 @@ public class CreateGroup implements RestModifyView
       AddMembers addMembers,
       SystemGroupBackend systemGroupBackend,
       @GerritServerConfig Config cfg,
-      @Assisted String name,
       Sequences sequences) {
     this.self = self;
     this.serverIdent = serverIdent;
@@ -109,7 +104,6 @@ public class CreateGroup implements RestModifyView
     this.addMembers = addMembers;
     this.systemGroupBackend = systemGroupBackend;
     this.defaultVisibleToAll = cfg.getBoolean("groups", "newGroupsVisibleToAll", false);
-    this.name = name;
     this.sequences = sequences;
   }
 
@@ -124,10 +118,11 @@ public class CreateGroup implements RestModifyView
   }
 
   @Override
-  public GroupInfo apply(TopLevelResource resource, GroupInput input)
+  public GroupInfo apply(TopLevelResource resource, IdString id, GroupInput input)
       throws AuthException, BadRequestException, UnprocessableEntityException,
           ResourceConflictException, OrmException, IOException, ConfigInvalidException,
           ResourceNotFoundException {
+    String name = id.get();
     if (input == null) {
       input = new GroupInput();
     }
diff --git a/java/com/google/gerrit/server/restapi/group/GroupsCollection.java b/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
index fba1f1fbf4..40a11c7e38 100644
--- a/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
+++ b/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
@@ -18,13 +18,11 @@ import com.google.common.collect.ListMultimap;
 import com.google.gerrit.common.data.GroupDescription;
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.NeedsParams;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestCollection;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
@@ -44,13 +42,10 @@ import com.google.inject.Provider;
 import java.util.Optional;
 
 public class GroupsCollection
-    implements RestCollection,
-        AcceptsCreate,
-        NeedsParams {
+    implements RestCollection, NeedsParams {
   private final DynamicMap> views;
   private final Provider list;
   private final Provider queryGroups;
-  private final CreateGroup.Factory createGroup;
   private final GroupControl.Factory groupControlFactory;
   private final GroupBackend groupBackend;
   private final GroupCache groupCache;
@@ -63,7 +58,6 @@ public class GroupsCollection
       DynamicMap> views,
       Provider list,
       Provider queryGroups,
-      CreateGroup.Factory createGroup,
       GroupControl.Factory groupControlFactory,
       GroupBackend groupBackend,
       GroupCache groupCache,
@@ -71,7 +65,6 @@ public class GroupsCollection
     this.views = views;
     this.list = list;
     this.queryGroups = queryGroups;
-    this.createGroup = createGroup;
     this.groupControlFactory = groupControlFactory;
     this.groupBackend = groupBackend;
     this.groupCache = groupCache;
@@ -199,11 +192,6 @@ public class GroupsCollection
     return null;
   }
 
-  @Override
-  public CreateGroup create(TopLevelResource root, IdString name) throws RestApiException {
-    return createGroup.create(name.get());
-  }
-
   @Override
   public DynamicMap> views() {
     return views;
diff --git a/java/com/google/gerrit/server/restapi/group/MembersCollection.java b/java/com/google/gerrit/server/restapi/group/MembersCollection.java
index cf2e0b8338..fec14436fe 100644
--- a/java/com/google/gerrit/server/restapi/group/MembersCollection.java
+++ b/java/com/google/gerrit/server/restapi/group/MembersCollection.java
@@ -16,7 +16,6 @@ package com.google.gerrit.server.restapi.group;
 
 import com.google.gerrit.common.data.GroupDescription;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ChildCollection;
 import com.google.gerrit.extensions.restapi.IdString;
@@ -27,7 +26,6 @@ import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.group.GroupResource;
 import com.google.gerrit.server.group.MemberResource;
 import com.google.gerrit.server.restapi.account.AccountsCollection;
-import com.google.gerrit.server.restapi.group.AddMembers.PutMember;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -36,23 +34,19 @@ import java.io.IOException;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 @Singleton
-public class MembersCollection
-    implements ChildCollection, AcceptsCreate {
+public class MembersCollection implements ChildCollection {
   private final DynamicMap> views;
   private final Provider list;
   private final AccountsCollection accounts;
-  private final AddMembers put;
 
   @Inject
   MembersCollection(
       DynamicMap> views,
       Provider list,
-      AccountsCollection accounts,
-      AddMembers put) {
+      AccountsCollection accounts) {
     this.views = views;
     this.list = list;
     this.accounts = accounts;
-    this.put = put;
   }
 
   @Override
@@ -78,11 +72,6 @@ public class MembersCollection
     return group.getMembers().contains(user.getAccountId());
   }
 
-  @Override
-  public PutMember create(GroupResource group, IdString id) {
-    return new PutMember(put, id.get());
-  }
-
   @Override
   public DynamicMap> views() {
     return views;
diff --git a/java/com/google/gerrit/server/restapi/group/Module.java b/java/com/google/gerrit/server/restapi/group/Module.java
index fa1e5c7796..741c3da774 100644
--- a/java/com/google/gerrit/server/restapi/group/Module.java
+++ b/java/com/google/gerrit/server/restapi/group/Module.java
@@ -24,7 +24,9 @@ import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.ServerInitiated;
 import com.google.gerrit.server.UserInitiated;
 import com.google.gerrit.server.group.db.GroupsUpdate;
+import com.google.gerrit.server.restapi.group.AddMembers.CreateMember;
 import com.google.gerrit.server.restapi.group.AddMembers.UpdateMember;
+import com.google.gerrit.server.restapi.group.AddSubgroups.CreateSubgroup;
 import com.google.gerrit.server.restapi.group.AddSubgroups.UpdateSubgroup;
 import com.google.gerrit.server.restapi.group.DeleteMembers.DeleteMember;
 import com.google.gerrit.server.restapi.group.DeleteSubgroups.DeleteSubgroup;
@@ -40,6 +42,7 @@ public class Module extends RestApiModule {
     DynamicMap.mapOf(binder(), MEMBER_KIND);
     DynamicMap.mapOf(binder(), SUBGROUP_KIND);
 
+    create(GROUP_KIND).to(CreateGroup.class);
     get(GROUP_KIND).to(GetGroup.class);
     put(GROUP_KIND).to(PutGroup.class);
     get(GROUP_KIND, "detail").to(GetDetail.class);
@@ -62,16 +65,17 @@ public class Module extends RestApiModule {
     get(GROUP_KIND, "log.audit").to(GetAuditLog.class);
 
     child(GROUP_KIND, "members").to(MembersCollection.class);
+    create(MEMBER_KIND).to(CreateMember.class);
     get(MEMBER_KIND).to(GetMember.class);
     put(MEMBER_KIND).to(UpdateMember.class);
     delete(MEMBER_KIND).to(DeleteMember.class);
 
     child(GROUP_KIND, "groups").to(SubgroupsCollection.class);
+    create(SUBGROUP_KIND).to(CreateSubgroup.class);
     get(SUBGROUP_KIND).to(GetSubgroup.class);
     put(SUBGROUP_KIND).to(UpdateSubgroup.class);
     delete(SUBGROUP_KIND).to(DeleteSubgroup.class);
 
-    factory(CreateGroup.Factory.class);
     factory(GroupsUpdate.Factory.class);
   }
 
diff --git a/java/com/google/gerrit/server/restapi/group/SubgroupsCollection.java b/java/com/google/gerrit/server/restapi/group/SubgroupsCollection.java
index 83520f17a7..cebc27a407 100644
--- a/java/com/google/gerrit/server/restapi/group/SubgroupsCollection.java
+++ b/java/com/google/gerrit/server/restapi/group/SubgroupsCollection.java
@@ -16,7 +16,6 @@ package com.google.gerrit.server.restapi.group;
 
 import com.google.gerrit.common.data.GroupDescription;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ChildCollection;
 import com.google.gerrit.extensions.restapi.IdString;
@@ -25,28 +24,23 @@ import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.server.group.GroupResource;
 import com.google.gerrit.server.group.SubgroupResource;
-import com.google.gerrit.server.restapi.group.AddSubgroups.PutSubgroup;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
 @Singleton
-public class SubgroupsCollection
-    implements ChildCollection, AcceptsCreate {
+public class SubgroupsCollection implements ChildCollection {
   private final DynamicMap> views;
   private final ListSubgroups list;
   private final GroupsCollection groupsCollection;
-  private final AddSubgroups addSubgroups;
 
   @Inject
   SubgroupsCollection(
       DynamicMap> views,
       ListSubgroups list,
-      GroupsCollection groupsCollection,
-      AddSubgroups addSubgroups) {
+      GroupsCollection groupsCollection) {
     this.views = views;
     this.list = list;
     this.groupsCollection = groupsCollection;
-    this.addSubgroups = addSubgroups;
   }
 
   @Override
@@ -73,11 +67,6 @@ public class SubgroupsCollection
     return parent.getSubgroups().contains(member.getGroupUUID());
   }
 
-  @Override
-  public PutSubgroup create(GroupResource group, IdString id) {
-    return new PutSubgroup(addSubgroups, id.get());
-  }
-
   @Override
   public DynamicMap> views() {
     return views;
diff --git a/java/com/google/gerrit/server/restapi/project/BranchesCollection.java b/java/com/google/gerrit/server/restapi/project/BranchesCollection.java
index f8ff7b9f8b..389cc2f1a2 100644
--- a/java/com/google/gerrit/server/restapi/project/BranchesCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/BranchesCollection.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.server.restapi.project;
 
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ChildCollection;
 import com.google.gerrit.extensions.restapi.IdString;
@@ -39,26 +38,22 @@ import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 
 @Singleton
-public class BranchesCollection
-    implements ChildCollection, AcceptsCreate {
+public class BranchesCollection implements ChildCollection {
   private final DynamicMap> views;
   private final Provider list;
   private final PermissionBackend permissionBackend;
   private final GitRepositoryManager repoManager;
-  private final CreateBranch.Factory createBranchFactory;
 
   @Inject
   BranchesCollection(
       DynamicMap> views,
       Provider list,
       PermissionBackend permissionBackend,
-      GitRepositoryManager repoManager,
-      CreateBranch.Factory createBranchFactory) {
+      GitRepositoryManager repoManager) {
     this.views = views;
     this.list = list;
     this.permissionBackend = permissionBackend;
     this.repoManager = repoManager;
-    this.createBranchFactory = createBranchFactory;
   }
 
   @Override
@@ -98,9 +93,4 @@ public class BranchesCollection
   public DynamicMap> views() {
     return views;
   }
-
-  @Override
-  public CreateBranch create(ProjectResource parent, IdString name) {
-    return createBranchFactory.create(name.get());
-  }
 }
diff --git a/java/com/google/gerrit/server/restapi/project/CreateBranch.java b/java/com/google/gerrit/server/restapi/project/CreateBranch.java
index 0296c9c4e6..4c7b27a06c 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateBranch.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateBranch.java
@@ -21,8 +21,9 @@ import com.google.gerrit.extensions.api.projects.BranchInfo;
 import com.google.gerrit.extensions.api.projects.BranchInput;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.IdentifiedUser;
@@ -31,6 +32,7 @@ import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.permissions.RefPermission;
+import com.google.gerrit.server.project.BranchResource;
 import com.google.gerrit.server.project.CreateRefControl;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectResource;
@@ -39,7 +41,6 @@ import com.google.gerrit.server.project.RefValidationHelper;
 import com.google.gerrit.server.util.MagicBranch;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-import com.google.inject.assistedinject.Assisted;
 import java.io.IOException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.lib.Constants;
@@ -50,20 +51,15 @@ import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.ReceiveCommand;
 
-public class CreateBranch implements RestModifyView {
+public class CreateBranch implements RestCreateView {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
-  public interface Factory {
-    CreateBranch create(String ref);
-  }
-
   private final Provider identifiedUser;
   private final PermissionBackend permissionBackend;
   private final GitRepositoryManager repoManager;
   private final GitReferenceUpdated referenceUpdated;
   private final RefValidationHelper refCreationValidator;
   private final CreateRefControl createRefControl;
-  private String ref;
 
   @Inject
   CreateBranch(
@@ -72,21 +68,20 @@ public class CreateBranch implements RestModifyView {
+  private final Provider setDefault;
+
+  @Option(name = "--inherited", usage = "set dashboard inherited by children")
+  private boolean inherited;
+
+  @Inject
+  CreateDashboard(Provider setDefault) {
+    this.setDefault = setDefault;
+  }
+
+  @Override
+  public Response apply(ProjectResource parent, IdString id, SetDashboardInput input)
+      throws RestApiException, IOException, PermissionBackendException {
+    parent.getProjectState().checkStatePermitsWrite();
+    if (!DashboardsCollection.isDefaultDashboard(id)) {
+      throw new ResourceNotFoundException(id);
+    }
+    SetDefaultDashboard set = setDefault.get();
+    set.inherited = inherited;
+    return set.apply(
+        DashboardResource.projectDefault(parent.getProjectState(), parent.getUser()), input);
+  }
+}
diff --git a/java/com/google/gerrit/server/restapi/project/CreateProject.java b/java/com/google/gerrit/server/restapi/project/CreateProject.java
index 3a9a0e7659..09fd91442f 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateProject.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateProject.java
@@ -37,10 +37,11 @@ import com.google.gerrit.extensions.events.NewProjectCreatedListener;
 import com.google.gerrit.extensions.registration.DynamicItem;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
@@ -64,13 +65,13 @@ import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectConfig;
 import com.google.gerrit.server.project.ProjectJson;
 import com.google.gerrit.server.project.ProjectNameLockManager;
+import com.google.gerrit.server.project.ProjectResource;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.restapi.group.GroupsCollection;
 import com.google.gerrit.server.validators.ProjectCreationValidationListener;
 import com.google.gerrit.server.validators.ValidationException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-import com.google.inject.assistedinject.Assisted;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -89,13 +90,10 @@ import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.ReceiveCommand;
 
 @RequiresCapability(GlobalCapability.CREATE_PROJECT)
-public class CreateProject implements RestModifyView {
+public class CreateProject
+    implements RestCreateView {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
-  public interface Factory {
-    CreateProject create(String name);
-  }
-
   private final Provider projectsCollection;
   private final Provider groupsCollection;
   private final DynamicSet projectCreationValidationListeners;
@@ -114,7 +112,6 @@ public class CreateProject implements RestModifyView lockManager;
-  private final String name;
 
   @Inject
   CreateProject(
@@ -135,8 +132,7 @@ public class CreateProject implements RestModifyView putConfig,
       AllProjectsName allProjects,
       AllUsersName allUsers,
-      DynamicItem lockManager,
-      @Assisted String name) {
+      DynamicItem lockManager) {
     this.projectsCollection = projectsCollection;
     this.groupsCollection = groupsCollection;
     this.projectCreationValidationListeners = projectCreationValidationListeners;
@@ -155,12 +151,12 @@ public class CreateProject implements RestModifyView apply(TopLevelResource resource, ProjectInput input)
+  public Response apply(TopLevelResource resource, IdString id, ProjectInput input)
       throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException {
+    String name = id.get();
     if (input == null) {
       input = new ProjectInput();
     }
diff --git a/java/com/google/gerrit/server/restapi/project/CreateTag.java b/java/com/google/gerrit/server/restapi/project/CreateTag.java
index b09d8706b4..b2fdff28be 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateTag.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateTag.java
@@ -23,10 +23,11 @@ import com.google.gerrit.extensions.api.projects.TagInfo;
 import com.google.gerrit.extensions.api.projects.TagInput;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.RestCreateView;
 import com.google.gerrit.server.WebLinks;
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -38,8 +39,8 @@ import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.gerrit.server.project.RefUtil;
 import com.google.gerrit.server.project.RefUtil.InvalidRevisionException;
+import com.google.gerrit.server.project.TagResource;
 import com.google.inject.Inject;
-import com.google.inject.assistedinject.Assisted;
 import java.io.IOException;
 import java.util.TimeZone;
 import org.eclipse.jgit.api.Git;
@@ -52,19 +53,13 @@ import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevWalk;
 
-public class CreateTag implements RestModifyView {
+public class CreateTag implements RestCreateView {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
-  public interface Factory {
-    CreateTag create(String ref);
-  }
-
   private final PermissionBackend permissionBackend;
   private final GitRepositoryManager repoManager;
   private final TagCache tagCache;
   private final GitReferenceUpdated referenceUpdated;
   private final WebLinks links;
-  private String ref;
 
   @Inject
   CreateTag(
@@ -72,19 +67,18 @@ public class CreateTag implements RestModifyView {
       GitRepositoryManager repoManager,
       TagCache tagCache,
       GitReferenceUpdated referenceUpdated,
-      WebLinks webLinks,
-      @Assisted String ref) {
+      WebLinks webLinks) {
     this.permissionBackend = permissionBackend;
     this.repoManager = repoManager;
     this.tagCache = tagCache;
     this.referenceUpdated = referenceUpdated;
     this.links = webLinks;
-    this.ref = ref;
   }
 
   @Override
-  public TagInfo apply(ProjectResource resource, TagInput input)
+  public TagInfo apply(ProjectResource resource, IdString id, TagInput input)
       throws RestApiException, IOException, PermissionBackendException, NoSuchProjectException {
+    String ref = id.get();
     if (input == null) {
       input = new TagInput();
     }
diff --git a/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java b/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java
index b7589cfe0a..07691e7251 100644
--- a/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java
@@ -25,14 +25,12 @@ import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.api.projects.DashboardInfo;
 import com.google.gerrit.extensions.api.projects.DashboardSectionInfo;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ChildCollection;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.Url;
 import com.google.gerrit.reviewdb.client.Project;
@@ -60,14 +58,12 @@ import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
 
 @Singleton
-public class DashboardsCollection
-    implements ChildCollection, AcceptsCreate {
+public class DashboardsCollection implements ChildCollection {
   public static final String DEFAULT_DASHBOARD_NAME = "default";
 
   private final GitRepositoryManager gitManager;
   private final DynamicMap> views;
   private final Provider list;
-  private final Provider createDefault;
   private final PermissionBackend permissionBackend;
 
   @Inject
@@ -75,12 +71,10 @@ public class DashboardsCollection
       GitRepositoryManager gitManager,
       DynamicMap> views,
       Provider list,
-      Provider createDefault,
       PermissionBackend permissionBackend) {
     this.gitManager = gitManager;
     this.views = views;
     this.list = list;
-    this.createDefault = createDefault;
     this.permissionBackend = permissionBackend;
   }
 
@@ -97,16 +91,6 @@ public class DashboardsCollection
     return list.get();
   }
 
-  @Override
-  public RestModifyView create(ProjectResource parent, IdString id)
-      throws RestApiException {
-    parent.getProjectState().checkStatePermitsWrite();
-    if (isDefaultDashboard(id)) {
-      return createDefault.get();
-    }
-    throw new ResourceNotFoundException(id);
-  }
-
   @Override
   public DashboardResource parse(ProjectResource parent, IdString id)
       throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException {
diff --git a/java/com/google/gerrit/server/restapi/project/Module.java b/java/com/google/gerrit/server/restapi/project/Module.java
index 17a675d618..d2e59cd783 100644
--- a/java/com/google/gerrit/server/restapi/project/Module.java
+++ b/java/com/google/gerrit/server/restapi/project/Module.java
@@ -41,6 +41,7 @@ public class Module extends RestApiModule {
     DynamicMap.mapOf(binder(), COMMIT_KIND);
     DynamicMap.mapOf(binder(), TAG_KIND);
 
+    create(PROJECT_KIND).to(CreateProject.class);
     put(PROJECT_KIND).to(PutProject.class);
     get(PROJECT_KIND).to(GetProject.class);
     get(PROJECT_KIND, "description").to(GetDescription.class);
@@ -69,11 +70,11 @@ public class Module extends RestApiModule {
     post(PROJECT_KIND, "index").to(Index.class);
 
     child(PROJECT_KIND, "branches").to(BranchesCollection.class);
+    create(BRANCH_KIND).to(CreateBranch.class);
     put(BRANCH_KIND).to(PutBranch.class);
     get(BRANCH_KIND).to(GetBranch.class);
     delete(BRANCH_KIND).to(DeleteBranch.class);
     post(PROJECT_KIND, "branches:delete").to(DeleteBranches.class);
-    factory(CreateBranch.Factory.class);
     get(BRANCH_KIND, "mergeable").to(CheckMergeability.class);
     factory(RefValidationHelper.Factory.class);
     get(BRANCH_KIND, "reflog").to(GetReflog.class);
@@ -86,17 +87,17 @@ public class Module extends RestApiModule {
     child(COMMIT_KIND, "files").to(FilesInCommitCollection.class);
 
     child(PROJECT_KIND, "tags").to(TagsCollection.class);
+    create(TAG_KIND).to(CreateTag.class);
     get(TAG_KIND).to(GetTag.class);
     put(TAG_KIND).to(PutTag.class);
     delete(TAG_KIND).to(DeleteTag.class);
     post(PROJECT_KIND, "tags:delete").to(DeleteTags.class);
-    factory(CreateTag.Factory.class);
 
     child(PROJECT_KIND, "dashboards").to(DashboardsCollection.class);
+    create(DASHBOARD_KIND).to(CreateDashboard.class);
     get(DASHBOARD_KIND).to(GetDashboard.class);
     put(DASHBOARD_KIND).to(SetDashboard.class);
     delete(DASHBOARD_KIND).to(DeleteDashboard.class);
-    factory(CreateProject.Factory.class);
 
     get(PROJECT_KIND, "config").to(GetConfig.class);
     put(PROJECT_KIND, "config").to(PutConfig.class);
diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
index 1ba993cce5..dafc2fab6f 100644
--- a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
@@ -17,7 +17,6 @@ package com.google.gerrit.server.restapi.project;
 import com.google.common.collect.ListMultimap;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.IdString;
@@ -46,16 +45,13 @@ import org.eclipse.jgit.lib.Constants;
 
 @Singleton
 public class ProjectsCollection
-    implements RestCollection,
-        AcceptsCreate,
-        NeedsParams {
+    implements RestCollection, NeedsParams {
   private final DynamicMap> views;
   private final Provider list;
   private final Provider queryProjects;
   private final ProjectCache projectCache;
   private final PermissionBackend permissionBackend;
   private final Provider user;
-  private final CreateProject.Factory createProjectFactory;
 
   private boolean hasQuery;
 
@@ -66,7 +62,6 @@ public class ProjectsCollection
       Provider queryProjects,
       ProjectCache projectCache,
       PermissionBackend permissionBackend,
-      CreateProject.Factory factory,
       Provider user) {
     this.views = views;
     this.list = list;
@@ -74,7 +69,6 @@ public class ProjectsCollection
     this.projectCache = projectCache;
     this.permissionBackend = permissionBackend;
     this.user = user;
-    this.createProjectFactory = factory;
   }
 
   @Override
@@ -179,9 +173,4 @@ public class ProjectsCollection
   public DynamicMap> views() {
     return views;
   }
-
-  @Override
-  public CreateProject create(TopLevelResource parent, IdString name) throws RestApiException {
-    return createProjectFactory.create(name.get());
-  }
 }
diff --git a/java/com/google/gerrit/server/restapi/project/SetDefaultDashboard.java b/java/com/google/gerrit/server/restapi/project/SetDefaultDashboard.java
index ba91e0ef3b..68fef53425 100644
--- a/java/com/google/gerrit/server/restapi/project/SetDefaultDashboard.java
+++ b/java/com/google/gerrit/server/restapi/project/SetDefaultDashboard.java
@@ -49,7 +49,7 @@ class SetDefaultDashboard implements RestModifyView {
-    private final Provider setDefault;
-
-    @Option(name = "--inherited", usage = "set dashboard inherited by children")
-    private boolean inherited;
-
-    @Inject
-    CreateDefault(Provider setDefault) {
-      this.setDefault = setDefault;
-    }
-
-    @Override
-    public Response apply(ProjectResource resource, SetDashboardInput input)
-        throws RestApiException, IOException, PermissionBackendException {
-      SetDefaultDashboard set = setDefault.get();
-      set.inherited = inherited;
-      return set.apply(
-          DashboardResource.projectDefault(resource.getProjectState(), resource.getUser()), input);
-    }
-  }
 }
diff --git a/java/com/google/gerrit/server/restapi/project/TagsCollection.java b/java/com/google/gerrit/server/restapi/project/TagsCollection.java
index fdace77afd..a129bda834 100644
--- a/java/com/google/gerrit/server/restapi/project/TagsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/TagsCollection.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.server.restapi.project;
 
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.ChildCollection;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -30,20 +29,14 @@ import com.google.inject.Singleton;
 import java.io.IOException;
 
 @Singleton
-public class TagsCollection
-    implements ChildCollection, AcceptsCreate {
+public class TagsCollection implements ChildCollection {
   private final DynamicMap> views;
   private final Provider list;
-  private final CreateTag.Factory createTagFactory;
 
   @Inject
-  public TagsCollection(
-      DynamicMap> views,
-      Provider list,
-      CreateTag.Factory createTagFactory) {
+  public TagsCollection(DynamicMap> views, Provider list) {
     this.views = views;
     this.list = list;
-    this.createTagFactory = createTagFactory;
   }
 
   @Override
@@ -62,9 +55,4 @@ public class TagsCollection
   public DynamicMap> views() {
     return views;
   }
-
-  @Override
-  public CreateTag create(ProjectResource resource, IdString name) {
-    return createTagFactory.create(name.get());
-  }
 }
diff --git a/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java b/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
index 9dc9a50008..c83660d252 100644
--- a/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
+++ b/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
@@ -20,6 +20,7 @@ import com.google.common.collect.Lists;
 import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.extensions.api.accounts.AccountInput;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -66,7 +67,7 @@ final class CreateAccountCommand extends SshCommand {
   @Argument(index = 0, required = true, metaVar = "USERNAME", usage = "name of the user account")
   private String username;
 
-  @Inject private CreateAccount.Factory createAccountFactory;
+  @Inject private CreateAccount createAccount;
 
   @Override
   protected void run() throws OrmException, IOException, ConfigInvalidException, UnloggedFailure {
@@ -78,7 +79,7 @@ final class CreateAccountCommand extends SshCommand {
     input.httpPassword = httpPassword;
     input.groups = Lists.transform(groups, AccountGroup.Id::toString);
     try {
-      createAccountFactory.create(username).apply(TopLevelResource.INSTANCE, input);
+      createAccount.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(username), input);
     } catch (RestApiException e) {
       throw die(e.getMessage());
     }
diff --git a/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java b/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
index 5a83b01318..03f9616e4d 100644
--- a/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
+++ b/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
@@ -91,7 +91,7 @@ final class CreateGroupCommand extends SshCommand {
     initialGroups.add(id);
   }
 
-  @Inject private CreateGroup.Factory createGroupFactory;
+  @Inject private CreateGroup createGroup;
 
   @Inject private GroupsCollection groups;
 
@@ -126,7 +126,8 @@ final class CreateGroupCommand extends SshCommand {
       input.ownerId = String.valueOf(ownerGroupId.get());
     }
 
-    GroupInfo group = createGroupFactory.create(groupName).apply(TopLevelResource.INSTANCE, input);
+    GroupInfo group =
+        createGroup.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(groupName), input);
     return groups.parse(TopLevelResource.INSTANCE, IdString.fromUrl(group.id));
   }
 
diff --git a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
index 379fc6864a..852969f9df 100644
--- a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
+++ b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
@@ -29,6 +29,7 @@ import com.google.gerrit.extensions.common.Input;
 import com.google.gerrit.extensions.common.NameInput;
 import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Account;
@@ -119,7 +120,7 @@ final class SetAccountCommand extends SshCommand {
 
   @Inject private IdentifiedUser.GenericFactory genericUserFactory;
 
-  @Inject private CreateEmail.Factory createEmailFactory;
+  @Inject private CreateEmail createEmail;
 
   @Inject private GetEmails getEmails;
 
@@ -269,7 +270,7 @@ final class SetAccountCommand extends SshCommand {
     in.email = email;
     in.noConfirmation = true;
     try {
-      createEmailFactory.create(email).apply(rsrc, in);
+      createEmail.apply(rsrc, IdString.fromDecoded(email), in);
     } catch (EmailException e) {
       throw die(e.getMessage());
     }
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/CreateAccountIT.java b/javatests/com/google/gerrit/acceptance/rest/account/CreateAccountIT.java
new file mode 100644
index 0000000000..aca6c4cbac
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/account/CreateAccountIT.java
@@ -0,0 +1,34 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// 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 com.google.gerrit.acceptance.rest.account;
+
+import static com.google.common.truth.Truth8.assertThat;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.extensions.api.accounts.AccountInput;
+import org.junit.Test;
+
+public class CreateAccountIT extends AbstractDaemonTest {
+  @Test
+  public void createAccountRestApi() throws Exception {
+    AccountInput input = new AccountInput();
+    input.username = "foo";
+    assertThat(accountCache.getByUsername(input.username)).isEmpty();
+    RestResponse r = adminRestSession.put("/accounts/" + input.username, input);
+    r.assertCreated();
+    assertThat(accountCache.getByUsername(input.username)).isPresent();
+  }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java b/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
index 7657e2e47a..4d499f0c4a 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
@@ -29,6 +29,7 @@ import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.extensions.common.ChangeInput;
 import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -42,7 +43,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 public class SuggestReviewersIT extends AbstractDaemonTest {
-  @Inject private CreateGroup.Factory createGroupFactory;
+  @Inject private CreateGroup createGroup;
 
   private InternalGroup group1;
   private InternalGroup group2;
@@ -490,7 +491,8 @@ public class SuggestReviewersIT extends AbstractDaemonTest {
   }
 
   private InternalGroup newGroup(String name) throws Exception {
-    GroupInfo group = createGroupFactory.create(name(name)).apply(TopLevelResource.INSTANCE, null);
+    GroupInfo group =
+        createGroup.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(name(name)), null);
     return group(new AccountGroup.UUID(group.id));
   }
 
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java b/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
index 48dc99488b..0b7758eead 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
@@ -15,12 +15,14 @@
 package com.google.gerrit.acceptance.rest.project;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth8.assertThat;
+import static com.google.gerrit.reviewdb.client.RefNames.REFS_HEADS;
 import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
 import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.GerritConfig;
-import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.RestResponse;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.extensions.api.projects.BranchApi;
 import com.google.gerrit.extensions.api.projects.BranchInfo;
@@ -35,7 +37,6 @@ import com.google.gerrit.reviewdb.client.RefNames;
 import org.junit.Before;
 import org.junit.Test;
 
-@NoHttpd
 public class CreateBranchIT extends AbstractDaemonTest {
   private Branch.NameKey testBranch;
 
@@ -44,6 +45,19 @@ public class CreateBranchIT extends AbstractDaemonTest {
     testBranch = new Branch.NameKey(project, "test");
   }
 
+  @Test
+  public void createBranchRestApi() throws Exception {
+    BranchInput input = new BranchInput();
+    input.ref = "foo";
+    assertThat(gApi.projects().name(project.get()).branches().get().stream().map(i -> i.ref))
+        .doesNotContain(REFS_HEADS + input.ref);
+    RestResponse r =
+        adminRestSession.put("/projects/" + project.get() + "/branches/" + input.ref, input);
+    r.assertCreated();
+    assertThat(gApi.projects().name(project.get()).branches().get().stream().map(i -> i.ref))
+        .contains(REFS_HEADS + input.ref);
+  }
+
   @Test
   public void createBranch_Forbidden() throws Exception {
     setApiUser(user);