Repository: radius-project/radius

Issue:
Decouple `rad list` command for new connectors from typed CLIs
**Overview of feature request**
Currently rad list command queries clients for each resource type like mongo, redis and rabbitmq sequentially. This is because we don't have an implementation on the server side for querying resources of different types.

One solution is to implement resource filtering on the server side and decouple the client side from querying each client sequentially.

[AB#6941](https://dev.azure.com/azure-octo/e61041b4-555f-47ae-95b2-4f8ab480ea57/_workitems/edit/6941)

Discussion:
@jkotalik: @bjoginapally does this need to be P0? I don't think this is blocking bug bash.@bjoginapally: > @bjoginapally does this need to be P0? I don't think this is blocking bug bash.

Yeah P0 after private preview. We need an API on the server side@nicolejms: very old so closing

Solution patch:
diff --git a/cmd/rad/cmd/appRun.go b/cmd/rad/cmd/appRun.go
index 6fb72a9a3..7a1fefc7e 100644
--- a/cmd/rad/cmd/appRun.go
+++ b/cmd/rad/cmd/appRun.go
@@ -11,6 +11,8 @@ import (
 	"os"
 	"path"
 
+	"github.com/spf13/cobra"
+
 	"github.com/project-radius/radius/pkg/cli"
 	"github.com/project-radius/radius/pkg/cli/bicep"
 	"github.com/project-radius/radius/pkg/cli/builders"
@@ -20,7 +22,6 @@ import (
 	"github.com/project-radius/radius/pkg/cli/stages"
 	"github.com/project-radius/radius/pkg/cli/tools"
 	"github.com/project-radius/radius/pkg/version"
-	"github.com/spf13/cobra"
 )
 
 // appRunCmd command deploys an application interactively based on a rad.yaml
diff --git a/cmd/rad/cmd/envInit.go b/cmd/rad/cmd/envInit.go
index 9fc2d7743..1746b8819 100644
--- a/cmd/rad/cmd/envInit.go
+++ b/cmd/rad/cmd/envInit.go
@@ -6,15 +6,29 @@
 package cmd
 
 import (
+	"context"
+	"encoding/json"
 	"errors"
 	"fmt"
+	"net/http"
+	"strings"
 
 	"github.com/Azure/go-autorest/autorest/azure/auth"
+	"github.com/mitchellh/mapstructure"
 	"github.com/spf13/cobra"
+	client_go "k8s.io/client-go/kubernetes"
+	runtime_client "sigs.k8s.io/controller-runtime/pkg/client"
 
+	"github.com/project-radius/radius/pkg/cli"
 	"github.com/project-radius/radius/pkg/cli/azure"
+	"github.com/project-radius/radius/pkg/cli/environments"
+	"github.com/project-radius/radius/pkg/cli/helm"
+	"github.com/project-radius/radius/pkg/cli/k3d"
+	"github.com/project-radius/radius/pkg/cli/kubernetes"
 	"github.com/project-radius/radius/pkg/cli/output"
 	"github.com/project-radius/radius/pkg/cli/prompt"
+	coreRpApps "github.com/project-radius/radius/pkg/corerp/api/v20220315privatepreview"
+	"github.com/project-radius/radius/pkg/featureflag"
 )
 
 var envInitCmd = &cobra.Command{
@@ -52,6 +66,266 @@ const (
 	Dev
 )
 
+func (k EnvKind) String() string {
+	return [...]string{"Azure", "Kubernetes", "Dev"}[k]
+}
+
+func initSelfHosted(cmd *cobra.Command, args []string, kind EnvKind) error {
+	config := ConfigFromContext(cmd.Context())
+	env, err := cli.ReadEnvironmentSection(config)
+	if err != nil {
+		return err
+	}
+
+	sharedArgs, err := parseArgs(cmd)
+	if err != nil {
+		return err
+	}
+
+	ucpImage, err := cmd.Flags().GetString("ucp-image")
+	if err != nil {
+		return err
+	}
+
+	ucpTag, err := cmd.Flags().GetString("ucp-tag")
+	if err != nil {
+		return err
+	}
+
+	// Configure Azure provider for cloud resources if specified
+	azureProvider, err := parseAzureProviderFromArgs(cmd, sharedArgs.Interactive)
+	if err != nil {
+		return err
+	}
+
+	if kind == Kubernetes {
+		sharedArgs.Namespace, err = selectNamespace(cmd, "default", sharedArgs.Interactive)
+		if err != nil {
+			return err
+		}
+	}
+
+	var defaultEnvName string
+
+	switch kind {
+	case Dev:
+		defaultEnvName = "dev"
+	case Kubernetes:
+		k8sConfig, err := kubernetes.ReadKubeConfig()
+		if err != nil {
+			return err
+		}
+		defaultEnvName = k8sConfig.CurrentContext
+
+	default:
+		return fmt.Errorf("unknown environment type: %s", kind)
+	}
+
+	environmentName, err := selectEnvironment(cmd, defaultEnvName, sharedArgs.Interactive)
+	if err != nil {
+		return err
+	}
+
+	params := &DevEnvironmentParams{
+		Name:      environmentName,
+		Providers: &environments.Providers{AzureProvider: azureProvider},
+	}
+
+	_, foundConflict := env.Items[environmentName]
+	if foundConflict {
+		return fmt.Errorf("an environment named %s already exists. Use `rad env delete %s` to delete or select a different name", params.Name, params.Name)
+	}
+
+	clusterOptions := helm.ClusterOptions{
+		Namespace: sharedArgs.Namespace,
+		Radius: helm.RadiusOptions{
+			ChartPath:     sharedArgs.ChartPath,
+			Image:         sharedArgs.Image,
+			Tag:           sharedArgs.Tag,
+			UCPImage:      ucpImage,
+			UCPTag:        ucpTag,
+			AppCoreImage:  sharedArgs.AppCoreImage,
+			AppCoreTag:    sharedArgs.AppCoreTag,
+			AzureProvider: azureProvider,
+		},
+	}
+
+	var k8sGoClient client_go.Interface
+	var runtimeClient runtime_client.Client
+	var contextName string
+
+	switch kind {
+	case Dev:
+		// Create environment
+		step := output.BeginStep("Creating Cluster...")
+		cluster, err := k3d.CreateCluster(cmd.Context(), params.Name)
+		if err != nil {
+			return err
+		}
+		output.CompleteStep(step)
+		k8sGoClient, runtimeClient, _, err = createKubernetesClients(cluster.ContextName)
+		if err != nil {
+			return err
+		}
+		clusterOptions.Contour.HostNetwork = true
+		clusterOptions.Radius.PublicEndpointOverride = cluster.HTTPEndpoint
+		env.Items[params.Name] = map[string]interface{}{
+			"kind":        "dev",
+			"context":     cluster.ContextName,
+			"clustername": cluster.ClusterName,
+			"namespace":   sharedArgs.Namespace,
+			"enableucp":   featureflag.EnableUnifiedControlPlane.IsActive(),
+			"registry": &environments.Registry{
+				PushEndpoint: cluster.RegistryPushEndpoint,
+				PullEndpoint: cluster.RegistryPullEndpoint,
+			},
+		}
+
+	case Kubernetes:
+		k8sGoClient, runtimeClient, contextName, err = createKubernetesClients("")
+		if err != nil {
+			return err
+		}
+		env.Items[params.Name] = map[string]interface{}{
+			"kind":      environments.KindKubernetes,
+			"context":   contextName,
+			"namespace": sharedArgs.Namespace,
+			"enableucp": featureflag.EnableUnifiedControlPlane.IsActive(),
+		}
+
+	}
+
+	step := output.BeginStep("Installing Radius...")
+	if err := helm.InstallOnCluster(cmd.Context(), clusterOptions, k8sGoClient, runtimeClient); err != nil {
+		return err
+	}
+
+	if featureflag.EnableUnifiedControlPlane.IsActive() {
+		// As decided by the team we will have a temporary 1:1 correspondence between UCP resource group and environment
+		ucpRgName := fmt.Sprintf("%s-rg", environmentName)
+		env.Items[environmentName]["ucpresourcegroupname"] = ucpRgName
+		ucpRgId, err := createUCPResourceGroup(contextName, ucpRgName)
+		if err != nil {
+			return err
+		}
+		env.Items[environmentName]["scope"] = ucpRgId
+		ucpEnvId, err := createEnvironmentResource(cmd.Context(), contextName, ucpRgName, environmentName)
+		if err != nil {
+			return err
+		}
+		env.Items[environmentName]["id"] = ucpEnvId
+	}
+
+	output.CompleteStep(step)
+
+	// Persist settings
+
+	if params.Providers != nil {
+		providerData := map[string]interface{}{}
+		err = mapstructure.Decode(params.Providers, &providerData)
+		if err != nil {
+			return err
+		}
+
+		env.Items[params.Name]["providers"] = providerData
+	}
+	err = cli.SaveConfigOnLock(cmd.Context(), config, cli.UpdateEnvironmentWithLatestConfig(env, cli.MergeInitEnvConfig(params.Name)))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func createUCPResourceGroup(kubeCtxName, resourceGroupName string) (string, error) {
+	baseUrl, rt, err := kubernetes.GetBaseUrlAndRoundTripperForDeploymentEngine(
+		"",
+		"",
+		kubeCtxName,
+		featureflag.EnableUnifiedControlPlane.IsActive(),
+	)
+	if err != nil {
+		return "", err
+	}
+
+	createRgRequest, err := http.NewRequest(
+		http.MethodPut,
+		fmt.Sprintf("%s/planes/radius/local/resourceGroups/%s", baseUrl, resourceGroupName),
+		strings.NewReader(`{}`),
+	)
+	if err != nil {
+		return "", fmt.Errorf("failed to create UCP resourceGroup: %w", err)
+	}
+	resp, err := rt.RoundTrip(createRgRequest)
+	if err != nil {
+		return "", fmt.Errorf("failed to create UCP resourceGroup: %w", err)
+	}
+
+	if resp.StatusCode != http.StatusCreated {
+		return "", fmt.Errorf("request to create UCP resouceGroup failed with status: %d, request: %+v", resp.StatusCode, resp)
+	}
+	defer resp.Body.Close()
+	var jsonBody map[string]interface{}
+	if json.NewDecoder(resp.Body).Decode(&jsonBody) != nil {
+		return "", nil
+	}
+
+	return jsonBody["id"].(string), nil
+}
+
+func createEnvironmentResource(ctx context.Context, kubeCtxName, resourceGroupName, environmentName string) (string, error) {
+	_, conn, err := kubernetes.CreateAPIServerConnection(kubeCtxName, "")
+	if err != nil {
+		return "", err
+	}
+
+	toCreate := coreRpApps.EnvironmentResource{
+		Properties: &coreRpApps.EnvironmentProperties{
+			Compute: &coreRpApps.EnvironmentCompute{
+				Kind: coreRpApps.EnvironmentComputeKindKubernetes.ToPtr(),
+			},
+		},
+	}
+
+	rootScope := fmt.Sprintf("planes/radius/local/resourceGroups/%s", resourceGroupName)
+	c := coreRpApps.NewEnvironmentsClient(conn, rootScope)
+	resp, err := c.CreateOrUpdate(ctx, environmentName, toCreate, nil)
+	if err != nil {
+		return "", fmt.Errorf("failed to create Applications.Core/environments resource: %w", err)
+	}
+	return *resp.ID, nil
+}
+
+func createKubernetesClients(contextName string) (client_go.Interface, runtime_client.Client, string, error) {
+	k8sConfig, err := kubernetes.ReadKubeConfig()
+	if err != nil {
+		return nil, nil, "", err
+	}
+
+	if contextName == "" && k8sConfig.CurrentContext == "" {
+		return nil, nil, "", errors.New("no kubernetes context is set")
+	} else if contextName == "" {
+		contextName = k8sConfig.CurrentContext
+	}
+
+	context := k8sConfig.Contexts[contextName]
+	if context == nil {
+		return nil, nil, "", fmt.Errorf("kubernetes context '%s' could not be found", contextName)
+	}
+
+	client, _, err := kubernetes.CreateTypedClient(contextName)
+	if err != nil {
+		return nil, nil, "", err
+	}
+
+	runtimeClient, err := kubernetes.CreateRuntimeClient(contextName, kubernetes.Scheme)
+	if err != nil {
+		return nil, nil, "", err
+	}
+
+	return client, runtimeClient, contextName, nil
+}
+
 func parseArgs(cmd *cobra.Command) (sharedArgs, error) {
 	// the below function call should never errors given a default is defined
 	interactive, err := cmd.Flags().GetBool("interactive")
@@ -85,13 +359,13 @@ func parseArgs(cmd *cobra.Command) (sharedArgs, error) {
 	}
 
 	return sharedArgs{
-		Interactive: interactive,
-		Namespace:   namespace,
-		ChartPath:   chartPath,
-		Image:       image,
-		Tag:         tag,
+		Interactive:  interactive,
+		Namespace:    namespace,
+		ChartPath:    chartPath,
+		Image:        image,
+		Tag:          tag,
 		AppCoreImage: appcoreImage,
-		AppCoreTag: appcoreTag,
+		AppCoreTag:   appcoreTag,
 	}, nil
 }
 
diff --git a/cmd/rad/cmd/envInitAzure.go b/cmd/rad/cmd/envInitAzure.go
index b75bcacaf..2f2a540a1 100644
--- a/cmd/rad/cmd/envInitAzure.go
+++ b/cmd/rad/cmd/envInitAzure.go
@@ -395,7 +395,9 @@ func connect(ctx context.Context, environmentName string, subscriptionID string,
 		// We already have a provider in this resource group
 		output.LogInfo("Found existing environment...\n\n"+
 			"Environment '%v' available at:\n%v\n", environmentName, envUrl)
-		err = storeEnvironment(ctx, armauth, environmentName, subscriptionID, resourceGroup, clusterName, fmt.Sprintf("%s-rg", environmentName))
+
+		//TODO: Need to figure out here how to fetch the environment's resource group and scope
+		err = storeEnvironment(ctx, armauth, environmentName, subscriptionID, resourceGroup, clusterName, fmt.Sprintf("%s-rg", environmentName), "", "")
 		if err != nil {
 			return err
 		}
@@ -480,19 +482,23 @@ func connect(ctx context.Context, environmentName string, subscriptionID string,
 	if err != nil {
 		return err
 	}
-	
+
 	// As decided by the team we will have a temporary 1:1 correspondence between UCP resource group and environment
 	ucpRgName := fmt.Sprintf("%s-rg", environmentName)
+	var scope, ucpEnvId string
 	if featureflag.EnableUnifiedControlPlane.IsActive() {
-		if createUCPResourceGroup(clusterName, ucpRgName) != nil {
+		ucpRgId, err := createUCPResourceGroup(clusterName, ucpRgName)
+		if err != nil {
 			return err
 		}
-		if createEnvironmentResource(clusterName, ucpRgName, environmentName) != nil {
+		scope = ucpRgId
+		ucpEnvId, err = createEnvironmentResource(ctx, clusterName, ucpRgName, environmentName)
+		if err != nil {
 			return err
 		}
 	}
 
-	err = storeEnvironment(ctx, armauth, environmentName, subscriptionID, resourceGroup, clusterName, ucpRgName)
+	err = storeEnvironment(ctx, armauth, environmentName, subscriptionID, resourceGroup, clusterName, ucpRgName, scope, ucpEnvId)
 	if err != nil {
 		return err
 	}
@@ -736,7 +742,7 @@ func findClusterInDeployment(ctx context.Context, deployment resources.Deploymen
 	return clusterName, nil
 }
 
-func storeEnvironment(ctx context.Context, authorizer autorest.Authorizer, envName, subId, azureRg, clusterName, ucpRgName string) error {
+func storeEnvironment(ctx context.Context, authorizer autorest.Authorizer, envName, subId, azureRg, clusterName, ucpRgName, scope, ucpEnvId string) error {
 	step := output.BeginStep("Updating Config...")
 
 	config := ConfigFromContext(ctx)
@@ -756,6 +762,8 @@ func storeEnvironment(ctx context.Context, authorizer autorest.Authorizer, envNa
 	}
 	if featureflag.EnableUnifiedControlPlane.IsActive() {
 		env.Items[envName]["ucpresourcegroupname"] = ucpRgName
+		env.Items[envName]["scope"] = scope
+		env.Items[envName]["id"] = ucpEnvId
 	}
 
 	err = cli.SaveConfigOnLock(ctx, config, cli.UpdateEnvironmentWithLatestConfig(env, cli.MergeInitEnvConfig(envName)))
diff --git a/cmd/rad/cmd/envInitDev.go b/cmd/rad/cmd/envInitDev.go
index b1f7c546f..42ce3ac17 100644
--- a/cmd/rad/cmd/envInitDev.go
+++ b/cmd/rad/cmd/envInitDev.go
@@ -6,17 +6,9 @@
 package cmd
 
 import (
-	"fmt"
-
-	"github.com/mitchellh/mapstructure"
 	"github.com/spf13/cobra"
 
-	"github.com/project-radius/radius/pkg/cli"
 	"github.com/project-radius/radius/pkg/cli/environments"
-	"github.com/project-radius/radius/pkg/cli/helm"
-	"github.com/project-radius/radius/pkg/cli/k3d"
-	"github.com/project-radius/radius/pkg/cli/output"
-	"github.com/project-radius/radius/pkg/featureflag"
 )
 
 func init() {
@@ -38,129 +30,8 @@ var envInitLocalCmd = &cobra.Command{
 	Use:   "dev",
 	Short: "Initializes a local development environment",
 	Long:  `Initializes a local development environment`,
-	RunE:  initDevRadEnvironment,
-}
-
-func initDevRadEnvironment(cmd *cobra.Command, args []string) error {
-	config := ConfigFromContext(cmd.Context())
-	env, err := cli.ReadEnvironmentSection(config)
-	if err != nil {
-		return err
-	}
-
-	sharedArgs, err := parseArgs(cmd)
-	if err != nil {
-		return err
-	}
-
-	environmentName, err := selectEnvironment(cmd, "dev", sharedArgs.Interactive)
-	if err != nil {
-		return err
-	}
-
-	azureProvider, err := parseAzureProviderFromArgs(cmd, sharedArgs.Interactive)
-	if err != nil {
-		return err
-	}
-
-	params := &DevEnvironmentParams{
-		Name:      environmentName,
-		Providers: &environments.Providers{AzureProvider: azureProvider},
-	}
-
-	ucpImage, err := cmd.Flags().GetString("ucp-image")
-	if err != nil {
-		return err
-	}
-
-	ucpTag, err := cmd.Flags().GetString("ucp-tag")
-	if err != nil {
-		return err
-	}
-
-	_, foundConflict := env.Items[environmentName]
-	if foundConflict {
-		return fmt.Errorf("an environment named %s already exists. Use `rad env delete %s` to delete or select a different name", params.Name, params.Name)
-	}
-
-	// Create environment
-	step := output.BeginStep("Creating Cluster...")
-	cluster, err := k3d.CreateCluster(cmd.Context(), params.Name)
-	if err != nil {
-		return err
-	}
-	output.CompleteStep(step)
-
-	step = output.BeginStep("Installing Radius...")
-
-	client, runtimeClient, _, err := createKubernetesClients(cluster.ContextName)
-	if err != nil {
-		return err
-	}
-
-	cliOptions := helm.ClusterOptions{
-		Namespace: sharedArgs.Namespace,
-		Radius: helm.RadiusOptions{
-			ChartPath:    sharedArgs.ChartPath,
-			Image:        sharedArgs.Image,
-			Tag:          sharedArgs.Tag,
-			UCPImage:     ucpImage,
-			UCPTag:       ucpTag,
-			AppCoreImage: sharedArgs.AppCoreImage,
-			AppCoreTag:   sharedArgs.AppCoreTag,
-		},
-	}
-	options := helm.NewClusterOptions(cliOptions)
-	options.Contour.HostNetwork = true
-	options.Radius.PublicEndpointOverride = cluster.HTTPEndpoint
-	options.Radius.AzureProvider = azureProvider
-
-	err = helm.InstallOnCluster(cmd.Context(), options, client, runtimeClient)
-	if err != nil {
-		return err
-	}
-
-	// Persist settings
-	env.Items[params.Name] = map[string]interface{}{
-		"kind":        "dev",
-		"context":     cluster.ContextName,
-		"clustername": cluster.ClusterName,
-		"namespace":   sharedArgs.Namespace,
-		"registry": &environments.Registry{
-			PushEndpoint: cluster.RegistryPushEndpoint,
-			PullEndpoint: cluster.RegistryPullEndpoint,
-		},
-		"enableucp": featureflag.EnableUnifiedControlPlane.IsActive(),
-	}
-
-	if featureflag.EnableUnifiedControlPlane.IsActive() {
-		// As decided by the team we will have a temporary 1:1 correspondence between UCP resource group and environment
-		ucpRGName := fmt.Sprintf("%s-rg", environmentName)
-		env.Items[params.Name]["ucpresourcegroupname"] = ucpRGName
-		if createUCPResourceGroup(cluster.ContextName, ucpRGName) != nil {
-			return err
-		}
-		if createEnvironmentResource(cluster.ContextName, ucpRGName, environmentName) != nil {
-			return err
-		}
-	}
-
-	output.CompleteStep(step)
-
-	if params.Providers != nil {
-		providerData := map[string]interface{}{}
-		err = mapstructure.Decode(params.Providers, &providerData)
-		if err != nil {
-			return err
-		}
-
-		env.Items[params.Name]["providers"] = providerData
-	}
-
-	err = cli.SaveConfigOnLock(cmd.Context(), config, cli.UpdateEnvironmentWithLatestConfig(env, cli.MergeInitEnvConfig(params.Name)))
-	if err != nil {
-		return err
-	}
-
-	return nil
+	// RunE:  initDevRadEnvironment,
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return initSelfHosted(cmd, args, Dev)
+	},
 }
diff --git a/cmd/rad/cmd/envInitKubernetes.go b/cmd/rad/cmd/envInitKubernetes.go
index fa3e734b2..fc9adb0a3 100644
--- a/cmd/rad/cmd/envInitKubernetes.go
+++ b/cmd/rad/cmd/envInitKubernetes.go
@@ -7,21 +7,8 @@ package cmd
 
 import (
 	_ "embed"
-	"errors"
-	"fmt"
-	"net/http"
-	"strings"
 
 	"github.com/spf13/cobra"
-	client_go "k8s.io/client-go/kubernetes"
-	runtime_client "sigs.k8s.io/controller-runtime/pkg/client"
-
-	"github.com/project-radius/radius/pkg/cli"
-	"github.com/project-radius/radius/pkg/cli/environments"
-	"github.com/project-radius/radius/pkg/cli/helm"
-	"github.com/project-radius/radius/pkg/cli/kubernetes"
-	"github.com/project-radius/radius/pkg/cli/output"
-	"github.com/project-radius/radius/pkg/featureflag"
 )
 
 const (
@@ -32,194 +19,9 @@ var envInitKubernetesCmd = &cobra.Command{
 	Use:   "kubernetes",
 	Short: "Initializes a kubernetes environment",
 	Long:  `Initializes a kubernetes environment.`,
-	RunE:  installKubernetes,
-}
-
-func installKubernetes(cmd *cobra.Command, args []string) error {
-	sharedArgs, err := parseArgs(cmd)
-	if err != nil {
-		return err
-	}
-	sharedArgs.Namespace, err = selectNamespace(cmd, "default", sharedArgs.Interactive)
-	if err != nil {
-		return err
-	}
-
-	client, runtimeClient, contextName, err := createKubernetesClients("")
-	if err != nil {
-		return err
-	}
-	environmentName, err := selectEnvironment(cmd, contextName, sharedArgs.Interactive)
-	if err != nil {
-		return err
-	}
-
-	// Configure Azure provider for cloud resources if specified
-	azureProvider, err := parseAzureProviderFromArgs(cmd, sharedArgs.Interactive)
-	if err != nil {
-		return err
-	}
-
-	ucpImage, err := cmd.Flags().GetString("ucp-image")
-	if err != nil {
-		return err
-	}
-
-	ucpTag, err := cmd.Flags().GetString("ucp-tag")
-	if err != nil {
-		return err
-	}
-
-	config := ConfigFromContext(cmd.Context())
-	env, err := cli.ReadEnvironmentSection(config)
-	if err != nil {
-		return err
-	}
-
-	_, foundConflict := env.Items[environmentName]
-	if foundConflict {
-		return fmt.Errorf("an environment named %s already exists. Use `rad env delete %s` to delete or select a different name", environmentName, environmentName)
-	}
-
-	step := output.BeginStep("Installing Radius...")
-
-	cliOptions := helm.ClusterOptions{
-		Namespace: sharedArgs.Namespace,
-		Radius: helm.RadiusOptions{
-			ChartPath:    sharedArgs.ChartPath,
-			Image:        sharedArgs.Image,
-			Tag:          sharedArgs.Tag,
-			UCPImage:     ucpImage,
-			UCPTag:       ucpTag,
-			AppCoreImage: sharedArgs.AppCoreImage,
-			AppCoreTag:   sharedArgs.AppCoreTag,
-		},
-	}
-
-	clusterOptions := helm.NewClusterOptions(cliOptions)
-	clusterOptions.Radius.AzureProvider = azureProvider
-
-	if err := helm.InstallOnCluster(cmd.Context(), clusterOptions, client, runtimeClient); err != nil {
-		return err
-	}
-
-	env.Items[environmentName] = map[string]interface{}{
-		"kind":      environments.KindKubernetes,
-		"context":   contextName,
-		"namespace": sharedArgs.Namespace,
-		"enableucp": featureflag.EnableUnifiedControlPlane.IsActive(),
-	}
-
-	if featureflag.EnableUnifiedControlPlane.IsActive() {
-		// As decided by the team we will have a temporary 1:1 correspondence between UCP resource group and environment
-		ucpRGName := fmt.Sprintf("%s-rg", environmentName)
-		env.Items[environmentName]["ucpresourcegroupname"] = ucpRGName
-		if createUCPResourceGroup(contextName, ucpRGName) != nil {
-			return err
-		}
-		if createEnvironmentResource(contextName, ucpRGName, environmentName) != nil {
-			return err
-		}
-	}
-
-	output.CompleteStep(step)
-
-	if err := cli.SaveConfigOnLock(cmd.Context(), config, cli.UpdateEnvironmentWithLatestConfig(env, cli.MergeInitEnvConfig(environmentName))); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func createUCPResourceGroup(kubeCtxName, resourceGroupName string) error {
-	baseUrl, rt, err := kubernetes.GetBaseUrlAndRoundTripperForDeploymentEngine(
-		"",
-		"",
-		kubeCtxName,
-		featureflag.EnableUnifiedControlPlane.IsActive(),
-	)
-	if err != nil {
-		return err
-	}
-
-	createRgRequest, err := http.NewRequest(
-		http.MethodPut,
-		fmt.Sprintf("%s/planes/radius/local/resourceGroups/%s", baseUrl, resourceGroupName),
-		strings.NewReader(`{}`),
-	)
-	if err != nil {
-		return fmt.Errorf("failed to create UCP resourceGroup: %w", err)
-	}
-	res, err := rt.RoundTrip(createRgRequest)
-	if err != nil {
-		return fmt.Errorf("failed to create UCP resourceGroup: %w", err)
-	}
-
-	if res.StatusCode != http.StatusCreated {
-		return fmt.Errorf("request to create UCP resouceGroup failed with status: %d, request: %+v", res.StatusCode, res)
-	}
-	return nil
-}
-
-func createEnvironmentResource(kubeCtxName, resourceGroupName, environmentName string) error {
-	baseUrl, rt, err := kubernetes.GetBaseUrlAndRoundTripperForDeploymentEngine(
-		"",
-		"",
-		kubeCtxName,
-		featureflag.EnableUnifiedControlPlane.IsActive(),
-	)
-	if err != nil {
-		return err
-	}
-
-	createEnvRequest, err := http.NewRequest(
-		http.MethodPut,
-		fmt.Sprintf("%s/planes/radius/local/resourceGroups/%s/providers/applications.core/environments/%s?api-version=%s", baseUrl, resourceGroupName, environmentName, CORE_RP_API_VERSION),
-		strings.NewReader(`{"properties":{"compute":{"kind":""}}}`),
-	)
-	createEnvRequest.Header.Add("Content-Type", "application/json")
-	if err != nil {
-		return fmt.Errorf("failed to create Applications.Core/environments resource: %w", err)
-	}
-	res, err := rt.RoundTrip(createEnvRequest)
-	if err != nil {
-		return fmt.Errorf("failed to create Applications.Core/environments resource: %w", err)
-	}
-
-	if res.StatusCode != http.StatusOK { //shouldn't it be http.StatusCreated for consistency with rg?
-		return fmt.Errorf("request to create Applications.Core/environments resource failed with status: %d, request: %+v", res.StatusCode, res)
-	}
-	return nil
-}
-
-func createKubernetesClients(contextName string) (client_go.Interface, runtime_client.Client, string, error) {
-	k8sConfig, err := kubernetes.ReadKubeConfig()
-	if err != nil {
-		return nil, nil, "", err
-	}
-
-	if contextName == "" && k8sConfig.CurrentContext == "" {
-		return nil, nil, "", errors.New("no kubernetes context is set")
-	} else if contextName == "" {
-		contextName = k8sConfig.CurrentContext
-	}
-
-	context := k8sConfig.Contexts[contextName]
-	if context == nil {
-		return nil, nil, "", fmt.Errorf("kubernetes context '%s' could not be found", contextName)
-	}
-
-	client, _, err := kubernetes.CreateTypedClient(contextName)
-	if err != nil {
-		return nil, nil, "", err
-	}
-
-	runtimeClient, err := kubernetes.CreateRuntimeClient(contextName, kubernetes.Scheme)
-	if err != nil {
-		return nil, nil, "", err
-	}
-
-	return client, runtimeClient, contextName, nil
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return initSelfHosted(cmd, args, Kubernetes)
+	},
 }
 
 func init() {
diff --git a/cmd/rad/cmd/envInstallKubernetes.go b/cmd/rad/cmd/envInstallKubernetes.go
index 0b507336e..f9a973edf 100644
--- a/cmd/rad/cmd/envInstallKubernetes.go
+++ b/cmd/rad/cmd/envInstallKubernetes.go
@@ -15,7 +15,9 @@ var envInstallKubernetesCmd = &cobra.Command{
 	Use:   "kubernetes",
 	Short: "Installs radius onto a kubernetes cluster",
 	Long:  `Installs radius onto a kubernetes cluster`,
-	RunE:  installKubernetes,
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return initSelfHosted(cmd, args, Kubernetes)
+	},
 }
 
 func init() {
diff --git a/cmd/rad/cmd/resourceList.go b/cmd/rad/cmd/resourceList.go
index faba10fb1..6d6472b85 100644
--- a/cmd/rad/cmd/resourceList.go
+++ b/cmd/rad/cmd/resourceList.go
@@ -91,12 +91,13 @@ func printOutput(cmd *cobra.Command, obj interface{}, isLegacy bool) error {
 	if err != nil {
 		return err
 	}
-
+	var formatterOptions output.FormatterOptions
 	if !isLegacy {
-		err = output.Write(format, obj, cmd.OutOrStdout(), objectformats.GetResourceTableFormat())
+		formatterOptions = objectformats.GetResourceTableFormat()
 	} else {
-		err = output.Write(format, obj, cmd.OutOrStdout(), objectformats.GetResourceTableFormatOld())
+		formatterOptions = objectformats.GetResourceTableFormatOld()
 	}
+	err = output.Write(format, obj, cmd.OutOrStdout(), formatterOptions)
 	if err != nil {
 		return err
 	}
diff --git a/deploy/Chart/charts/de/templates/serviceaccount.yaml b/deploy/Chart/charts/de/templates/serviceaccount.yaml
index b951cf5b2..785308722 100644
--- a/deploy/Chart/charts/de/templates/serviceaccount.yaml
+++ b/deploy/Chart/charts/de/templates/serviceaccount.yaml
@@ -9,33 +9,33 @@ kind: ClusterRole
 metadata:
   name: de-manager-role
 rules:
-- apiGroups:
-  - ""
-  resources:
-  - configmaps
-  - secrets
-  - services
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - apps
-  resources:
-  - deployments
-  - statefulsets
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
+  - apiGroups:
+      - ""
+    resources:
+      - configmaps
+      - secrets
+      - services
+    verbs:
+      - create
+      - delete
+      - get
+      - list
+      - patch
+      - update
+      - watch
+  - apiGroups:
+      - apps
+    resources:
+      - deployments
+      - statefulsets
+    verbs:
+      - create
+      - delete
+      - get
+      - list
+      - patch
+      - update
+      - watch
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
@@ -46,6 +46,6 @@ roleRef:
   kind: ClusterRole
   name: de-manager-role
 subjects:
-- kind: ServiceAccount
-  name: de-manager
-  namespace: {{ .Release.Namespace }}
\ No newline at end of file
+  - kind: ServiceAccount
+    name: de-manager
+    namespace: {{ .Release.Namespace }}
diff --git a/deploy/Chart/charts/ucp/ucp-config.yaml b/deploy/Chart/charts/ucp/ucp-config.yaml
index 27618bdc9..7f2e151ff 100644
--- a/deploy/Chart/charts/ucp/ucp-config.yaml
+++ b/deploy/Chart/charts/ucp/ucp-config.yaml
@@ -31,8 +31,10 @@ planes:
       resourceProviders:
         Applications.Core: "http://appcore-rp.radius-system:5443"
         Applications.Connector: "http://appcore-rp.radius-system:5444"
+      kind: "UCPNative"
   - id: "/planes/deployments/local"
     properties:
       resourceProviders:
         Microsoft.Resources: "http://de-api.radius-system:6443"
+      kind: "UCPNative"
 
diff --git a/hack/bicep-types-radius/generated/applications/applications.connector/2022-03-15-privatepreview/types.json b/hack/bicep-types-radius/generated/applications/applications.connector/2022-03-15-privatepreview/types.json
index 3ddb04243..763c8b99b 100644
--- a/hack/bicep-types-radius/generated/applications/applications.connector/2022-03-15-privatepreview/types.json
+++ b/hack/bicep-types-radius/generated/applications/applications.connector/2022-03-15-privatepreview/types.json
@@ -1 +1 @@
-[{"1":{"Kind":1}},{"1":{"Kind":2}},{"1":{"Kind":3}},{"1":{"Kind":4}},{"1":{"Kind":5}},{"1":{"Kind":6}},{"1":{"Kind":7}},{"1":{"Kind":8}},{"6":{"Value":"Applications.Connector/mongoDatabases"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/mongoDatabases","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":8,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":9,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":22,"Flags":1,"Description":"MongoDatabse connector properties"},"tags":{"Type":34,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":16,"Flags":0,"Description":"The type of identity that created the resource."},"createdAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource creation (UTC)."},"lastModifiedBy":{"Type":4,"Flags":0,"Description":"The identity that last modified the resource."},"lastModifiedByType":{"Type":21,"Flags":0,"Description":"The type of identity that created the resource."},"lastModifiedAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource last modification (UTC)"}}}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[12,13,14,15]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[17,18,19,20]}},{"2":{"Name":"MongoDatabaseProperties","Properties":{"provisioningState":{"Type":30,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"resource":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID of a supported resource with Mongo API to use for this connector"},"host":{"Type":4,"Flags":0,"Description":"Host name of the target Mongo database"},"port":{"Type":3,"Flags":0,"Description":"Port value of the target Mongo database"},"secrets":{"Type":31,"Flags":0,"Description":"The secret values for the given MongoDatabase resource"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[23,24,25,26,27,28,29]}},{"2":{"Name":"MongoDatabaseSecrets","Properties":{"username":{"Type":4,"Flags":0,"Description":"Username to use when connecting to the target Mongo database"},"password":{"Type":4,"Flags":0,"Description":"Password to use when connecting to the target Mongo database"},"connectionString":{"Type":4,"Flags":0,"Description":"Connection string used to connect to the target Mongo database"}}}},{"2":{"Name":"ResourceStatus","Properties":{"outputResources":{"Type":33,"Flags":0,"Description":"Array of AnyObject"}}}},{"3":{"ItemType":0}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/mongoDatabases@2022-03-15-privatepreview","ScopeType":0,"Body":10}},{"6":{"Value":"Applications.Connector/daprPubSubBrokers"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/daprPubSubBrokers","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":36,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":37,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":39,"Flags":1,"Description":"DaprPubSubBroker connector properties"},"tags":{"Type":52,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"7":{"Name":"DaprPubSubBrokerProperties","Discriminator":"kind","BaseProperties":{"provisioningState":{"Type":47,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"environment":{"Type":4,"Flags":1,"Description":"The resource id of the environment linked to the daprPubSubBroker connector"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}},"Elements":{"generic":48,"pubsub.azure.servicebus":50}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[40,41,42,43,44,45,46]}},{"2":{"Name":"DaprPubSubGenericResourceProperties","Properties":{"metadata":{"Type":0,"Flags":1,"Description":"Any object"},"type":{"Type":4,"Flags":1,"Description":"Dapr PubSub type. These strings match the format used by Dapr Kubernetes configuration format."},"version":{"Type":4,"Flags":1,"Description":"Dapr component version"},"kind":{"Type":49,"Flags":1,"Description":"The DaprPubSubProperties kind"}}}},{"6":{"Value":"generic"}},{"2":{"Name":"DaprPubSubAzureServiceBusResourceProperties","Properties":{"resource":{"Type":4,"Flags":1,"Description":"PubSub resource"},"kind":{"Type":51,"Flags":1,"Description":"The DaprPubSubProperties kind"}}}},{"6":{"Value":"pubsub.azure.servicebus"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/daprPubSubBrokers@2022-03-15-privatepreview","ScopeType":0,"Body":38}},{"6":{"Value":"Applications.Connector/sqlDatabases"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/sqlDatabases","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":54,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":55,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":57,"Flags":1,"Description":"SQLDatabse connector properties"},"tags":{"Type":66,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"SQLDatabaseProperties","Properties":{"provisioningState":{"Type":65,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"The resource id of the environment linked to the sqlDatabase connector"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"resource":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID of a supported resource with SQL API to use for this connector"},"database":{"Type":4,"Flags":0,"Description":"The name of the SQL database."},"server":{"Type":4,"Flags":0,"Description":"The fully qualified domain name of the SQL database."},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[58,59,60,61,62,63,64]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/sqlDatabases@2022-03-15-privatepreview","ScopeType":0,"Body":56}},{"6":{"Value":"Applications.Connector/redisCaches"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/redisCaches","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":68,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":69,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":71,"Flags":1,"Description":"RedisCache connector properties"},"tags":{"Type":81,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"RedisCacheProperties","Properties":{"provisioningState":{"Type":79,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"resource":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID of a supported resource with Redis API to use for this connector"},"host":{"Type":4,"Flags":0,"Description":"The host name of the target redis cache"},"port":{"Type":3,"Flags":0,"Description":"The port value of the target redis cache"},"secrets":{"Type":80,"Flags":0,"Description":"The secret values for the given RedisCache resource"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[72,73,74,75,76,77,78]}},{"2":{"Name":"RedisCacheSecrets","Properties":{"connectionString":{"Type":4,"Flags":0,"Description":"The connection string used to connect to the redis cache"},"password":{"Type":4,"Flags":0,"Description":"The password for this Redis instance"}}}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/redisCaches@2022-03-15-privatepreview","ScopeType":0,"Body":70}},{"6":{"Value":"Applications.Connector/rabbitMQMessageQueues"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/rabbitMQMessageQueues","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":83,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":84,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":86,"Flags":1,"Description":"RabbitMQMessageQueue connector properties"},"tags":{"Type":96,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"RabbitMQMessageQueueProperties","Properties":{"provisioningState":{"Type":94,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"queue":{"Type":4,"Flags":1,"Description":"The name of the queue"},"secrets":{"Type":95,"Flags":0,"Description":"The secret values for the given RabbitMQMessageQueue resource"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[87,88,89,90,91,92,93]}},{"2":{"Name":"RabbitMQSecrets","Properties":{"connectionString":{"Type":4,"Flags":0,"Description":"The connection string used to connect to this RabbitMQ instance"}}}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/rabbitMQMessageQueues@2022-03-15-privatepreview","ScopeType":0,"Body":85}},{"6":{"Value":"Applications.Connector/daprSecretStores"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/daprSecretStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":98,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":99,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":101,"Flags":1,"Description":"DaprSecretStore connector properties"},"tags":{"Type":111,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"DaprSecretStoreProperties","Properties":{"provisioningState":{"Type":109,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"kind":{"Type":110,"Flags":1,"Description":"Radius kind for Dapr Secret Store"},"type":{"Type":4,"Flags":1,"Description":"Dapr Secret Store type. These strings match the types defined in Dapr Component format: https://docs.dapr.io/reference/components-reference/supported-secret-stores/"},"version":{"Type":4,"Flags":1,"Description":"Dapr component version"},"metadata":{"Type":0,"Flags":1,"Description":"Any object"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[102,103,104,105,106,107,108]}},{"6":{"Value":"generic"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/daprSecretStores@2022-03-15-privatepreview","ScopeType":0,"Body":100}},{"6":{"Value":"Applications.Connector/daprInvokeHttpRoutes"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/daprInvokeHttpRoutes","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":113,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":114,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":116,"Flags":1,"Description":"DaprInvokeHttpRoute connector properties"},"tags":{"Type":125,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"DaprInvokeHttpRouteProperties","Properties":{"provisioningState":{"Type":124,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"appId":{"Type":4,"Flags":1,"Description":"The Dapr appId used for the route"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[117,118,119,120,121,122,123]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/daprInvokeHttpRoutes@2022-03-15-privatepreview","ScopeType":0,"Body":115}},{"6":{"Value":"Applications.Connector/daprStateStores"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/daprStateStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":127,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":128,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":130,"Flags":1,"Description":"DaprStateStore connector properties"},"tags":{"Type":145,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"7":{"Name":"DaprStateStoreProperties","Discriminator":"kind","BaseProperties":{"provisioningState":{"Type":138,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}},"Elements":{"generic":139,"state.azure.tablestorage":141,"state.sqlserver":143}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[131,132,133,134,135,136,137]}},{"2":{"Name":"DaprStateStoreGenericResourceProperties","Properties":{"metadata":{"Type":0,"Flags":1,"Description":"Any object"},"type":{"Type":4,"Flags":1,"Description":"Dapr StateStore type. These strings match the format used by Dapr Kubernetes configuration format."},"version":{"Type":4,"Flags":1,"Description":"Dapr component version"},"kind":{"Type":140,"Flags":1,"Description":"The Dapr StateStore kind"}}}},{"6":{"Value":"generic"}},{"2":{"Name":"DaprStateStoreAzureTableStorageResourceProperties","Properties":{"resource":{"Type":4,"Flags":1,"Description":"The resource id of the Azure Storage Table the daprStateStore resource is connected to."},"kind":{"Type":142,"Flags":1,"Description":"The Dapr StateStore kind"}}}},{"6":{"Value":"state.azure.tablestorage"}},{"2":{"Name":"DaprStateStoreSqlServerResourceProperties","Properties":{"resource":{"Type":4,"Flags":1,"Description":"The resource id of the Azure SQL Database the daprStateStore resource is connected to."},"kind":{"Type":144,"Flags":1,"Description":"The Dapr StateStore kind"}}}},{"6":{"Value":"state.sqlserver"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/daprStateStores@2022-03-15-privatepreview","ScopeType":0,"Body":129}},{"6":{"Value":"Applications.Connector/extenders"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/extenders","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":147,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":148,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":150,"Flags":1,"Description":"Extender connector properties"},"tags":{"Type":160,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"ExtenderProperties","Properties":{"provisioningState":{"Type":158,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"secrets":{"Type":159,"Flags":0,"Description":"Dictionary of <any>"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}},"AdditionalProperties":0}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[151,152,153,154,155,156,157]}},{"2":{"Name":"ExtenderPropertiesSecrets","Properties":{},"AdditionalProperties":0}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/extenders@2022-03-15-privatepreview","ScopeType":0,"Body":149}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Connector/mongoDatabases","ApiVersion":"2022-03-15-privatepreview","Output":31}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Connector/redisCaches","ApiVersion":"2022-03-15-privatepreview","Output":80}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Connector/rabbitMQMessageQueues","ApiVersion":"2022-03-15-privatepreview","Output":95}}]
\ No newline at end of file
+[{"1":{"Kind":1}},{"1":{"Kind":2}},{"1":{"Kind":3}},{"1":{"Kind":4}},{"1":{"Kind":5}},{"1":{"Kind":6}},{"1":{"Kind":7}},{"1":{"Kind":8}},{"6":{"Value":"Applications.Connector/mongoDatabases"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/mongoDatabases","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":8,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":9,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":22,"Flags":1,"Description":"MongoDatabase connector properties"},"tags":{"Type":34,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":16,"Flags":0,"Description":"The type of identity that created the resource."},"createdAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource creation (UTC)."},"lastModifiedBy":{"Type":4,"Flags":0,"Description":"The identity that last modified the resource."},"lastModifiedByType":{"Type":21,"Flags":0,"Description":"The type of identity that created the resource."},"lastModifiedAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource last modification (UTC)"}}}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[12,13,14,15]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[17,18,19,20]}},{"2":{"Name":"MongoDatabaseProperties","Properties":{"secrets":{"Type":23,"Flags":4,"Description":"The secret values for the given MongoDatabase resource"},"provisioningState":{"Type":31,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"resource":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID of a supported resource with Mongo API to use for this connector"},"host":{"Type":4,"Flags":0,"Description":"Host name of the target Mongo database"},"port":{"Type":3,"Flags":0,"Description":"Port value of the target Mongo database"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"2":{"Name":"MongoDatabaseSecrets","Properties":{"username":{"Type":4,"Flags":4,"Description":"Username to use when connecting to the target Mongo database"},"password":{"Type":4,"Flags":4,"Description":"Password to use when connecting to the target Mongo database"},"connectionString":{"Type":4,"Flags":4,"Description":"Connection string used to connect to the target Mongo database"}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[24,25,26,27,28,29,30]}},{"2":{"Name":"ResourceStatus","Properties":{"outputResources":{"Type":33,"Flags":0,"Description":"Array of AnyObject"}}}},{"3":{"ItemType":0}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/mongoDatabases@2022-03-15-privatepreview","ScopeType":0,"Body":10}},{"6":{"Value":"Applications.Connector/daprPubSubBrokers"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/daprPubSubBrokers","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":36,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":37,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":39,"Flags":1,"Description":"DaprPubSubBroker connector properties"},"tags":{"Type":52,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"7":{"Name":"DaprPubSubBrokerProperties","Discriminator":"kind","BaseProperties":{"provisioningState":{"Type":47,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"environment":{"Type":4,"Flags":1,"Description":"The resource id of the environment linked to the daprPubSubBroker connector"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}},"Elements":{"generic":48,"pubsub.azure.servicebus":50}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[40,41,42,43,44,45,46]}},{"2":{"Name":"DaprPubSubGenericResourceProperties","Properties":{"metadata":{"Type":0,"Flags":1,"Description":"Any object"},"type":{"Type":4,"Flags":1,"Description":"Dapr PubSub type. These strings match the format used by Dapr Kubernetes configuration format."},"version":{"Type":4,"Flags":1,"Description":"Dapr component version"},"kind":{"Type":49,"Flags":1,"Description":"The DaprPubSubProperties kind"}}}},{"6":{"Value":"generic"}},{"2":{"Name":"DaprPubSubAzureServiceBusResourceProperties","Properties":{"resource":{"Type":4,"Flags":1,"Description":"PubSub resource"},"kind":{"Type":51,"Flags":1,"Description":"The DaprPubSubProperties kind"}}}},{"6":{"Value":"pubsub.azure.servicebus"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/daprPubSubBrokers@2022-03-15-privatepreview","ScopeType":0,"Body":38}},{"6":{"Value":"Applications.Connector/sqlDatabases"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/sqlDatabases","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":54,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":55,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":57,"Flags":1,"Description":"SQLDatabse connector properties"},"tags":{"Type":66,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"SQLDatabaseProperties","Properties":{"provisioningState":{"Type":65,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"The resource id of the environment linked to the sqlDatabase connector"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"resource":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID of a supported resource with SQL API to use for this connector"},"database":{"Type":4,"Flags":0,"Description":"The name of the SQL database."},"server":{"Type":4,"Flags":0,"Description":"The fully qualified domain name of the SQL database."},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[58,59,60,61,62,63,64]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/sqlDatabases@2022-03-15-privatepreview","ScopeType":0,"Body":56}},{"6":{"Value":"Applications.Connector/redisCaches"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/redisCaches","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":68,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":69,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":71,"Flags":1,"Description":"RedisCache connector properties"},"tags":{"Type":81,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"RedisCacheProperties","Properties":{"secrets":{"Type":72,"Flags":4,"Description":"The secret values for the given RedisCache resource"},"provisioningState":{"Type":80,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"resource":{"Type":4,"Flags":0,"Description":"Fully qualified resource ID of a supported resource with Redis API to use for this connector"},"host":{"Type":4,"Flags":0,"Description":"The host name of the target redis cache"},"port":{"Type":3,"Flags":0,"Description":"The port value of the target redis cache"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"2":{"Name":"RedisCacheSecrets","Properties":{"connectionString":{"Type":4,"Flags":4,"Description":"The connection string used to connect to the redis cache"},"password":{"Type":4,"Flags":4,"Description":"The password for this Redis instance"}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[73,74,75,76,77,78,79]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/redisCaches@2022-03-15-privatepreview","ScopeType":0,"Body":70}},{"6":{"Value":"Applications.Connector/rabbitMQMessageQueues"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/rabbitMQMessageQueues","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":83,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":84,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":86,"Flags":1,"Description":"RabbitMQMessageQueue connector properties"},"tags":{"Type":96,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"RabbitMQMessageQueueProperties","Properties":{"secrets":{"Type":87,"Flags":4,"Description":"The secret values for the given RabbitMQMessageQueue resource"},"provisioningState":{"Type":95,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"queue":{"Type":4,"Flags":1,"Description":"The name of the queue"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"2":{"Name":"RabbitMQSecrets","Properties":{"connectionString":{"Type":4,"Flags":4,"Description":"The connection string used to connect to this RabbitMQ instance"}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[88,89,90,91,92,93,94]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/rabbitMQMessageQueues@2022-03-15-privatepreview","ScopeType":0,"Body":85}},{"6":{"Value":"Applications.Connector/daprSecretStores"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/daprSecretStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":98,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":99,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":101,"Flags":1,"Description":"DaprSecretStore connector properties"},"tags":{"Type":111,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"DaprSecretStoreProperties","Properties":{"provisioningState":{"Type":109,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"kind":{"Type":110,"Flags":1,"Description":"Radius kind for Dapr Secret Store"},"type":{"Type":4,"Flags":1,"Description":"Dapr Secret Store type. These strings match the types defined in Dapr Component format: https://docs.dapr.io/reference/components-reference/supported-secret-stores/"},"version":{"Type":4,"Flags":1,"Description":"Dapr component version"},"metadata":{"Type":0,"Flags":1,"Description":"Any object"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[102,103,104,105,106,107,108]}},{"6":{"Value":"generic"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/daprSecretStores@2022-03-15-privatepreview","ScopeType":0,"Body":100}},{"6":{"Value":"Applications.Connector/daprInvokeHttpRoutes"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/daprInvokeHttpRoutes","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":113,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":114,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":116,"Flags":1,"Description":"DaprInvokeHttpRoute connector properties"},"tags":{"Type":125,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"DaprInvokeHttpRouteProperties","Properties":{"provisioningState":{"Type":124,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"appId":{"Type":4,"Flags":1,"Description":"The Dapr appId used for the route"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[117,118,119,120,121,122,123]}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/daprInvokeHttpRoutes@2022-03-15-privatepreview","ScopeType":0,"Body":115}},{"6":{"Value":"Applications.Connector/daprStateStores"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/daprStateStores","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":127,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":128,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":130,"Flags":1,"Description":"DaprStateStore connector properties"},"tags":{"Type":145,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"7":{"Name":"DaprStateStoreProperties","Discriminator":"kind","BaseProperties":{"provisioningState":{"Type":138,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}},"Elements":{"generic":139,"state.azure.tablestorage":141,"state.sqlserver":143}}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[131,132,133,134,135,136,137]}},{"2":{"Name":"DaprStateStoreGenericResourceProperties","Properties":{"metadata":{"Type":0,"Flags":1,"Description":"Any object"},"type":{"Type":4,"Flags":1,"Description":"Dapr StateStore type. These strings match the format used by Dapr Kubernetes configuration format."},"version":{"Type":4,"Flags":1,"Description":"Dapr component version"},"kind":{"Type":140,"Flags":1,"Description":"The Dapr StateStore kind"}}}},{"6":{"Value":"generic"}},{"2":{"Name":"DaprStateStoreAzureTableStorageResourceProperties","Properties":{"resource":{"Type":4,"Flags":1,"Description":"The resource id of the Azure Storage Table the daprStateStore resource is connected to."},"kind":{"Type":142,"Flags":1,"Description":"The Dapr StateStore kind"}}}},{"6":{"Value":"state.azure.tablestorage"}},{"2":{"Name":"DaprStateStoreSqlServerResourceProperties","Properties":{"resource":{"Type":4,"Flags":1,"Description":"The resource id of the Azure SQL Database the daprStateStore resource is connected to."},"kind":{"Type":144,"Flags":1,"Description":"The Dapr StateStore kind"}}}},{"6":{"Value":"state.sqlserver"}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/daprStateStores@2022-03-15-privatepreview","ScopeType":0,"Body":129}},{"6":{"Value":"Applications.Connector/extenders"}},{"6":{"Value":"2022-03-15-privatepreview"}},{"2":{"Name":"Applications.Connector/extenders","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":147,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":148,"Flags":10,"Description":"The resource api version"},"systemData":{"Type":11,"Flags":2,"Description":"Metadata pertaining to creation and last modification of the resource."},"properties":{"Type":150,"Flags":1,"Description":"Extender connector properties"},"tags":{"Type":160,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"}}}},{"2":{"Name":"ExtenderProperties","Properties":{"provisioningState":{"Type":158,"Flags":2,"Description":"Provisioning state of the connector at the time the operation was called"},"environment":{"Type":4,"Flags":1,"Description":"Fully qualified resource ID for the environment that the connector is linked to"},"application":{"Type":4,"Flags":2,"Description":"Fully qualified resource ID for the application that the connector is consumed by"},"secrets":{"Type":159,"Flags":0,"Description":"The secret values for the given Extender resource"},"status":{"Type":32,"Flags":0,"Description":"Status of a resource."}},"AdditionalProperties":0}},{"6":{"Value":"Succeeded"}},{"6":{"Value":"Failed"}},{"6":{"Value":"Canceled"}},{"6":{"Value":"Accepted"}},{"6":{"Value":"Updating"}},{"6":{"Value":"Deleting"}},{"6":{"Value":"Provisioning"}},{"5":{"Elements":[151,152,153,154,155,156,157]}},{"2":{"Name":"ExtenderSecrets","Properties":{},"AdditionalProperties":0}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"4":{"Name":"Applications.Connector/extenders@2022-03-15-privatepreview","ScopeType":0,"Body":149}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Connector/mongoDatabases","ApiVersion":"2022-03-15-privatepreview","Output":23}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Connector/redisCaches","ApiVersion":"2022-03-15-privatepreview","Output":72}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Connector/rabbitMQMessageQueues","ApiVersion":"2022-03-15-privatepreview","Output":87}},{"2":{"Name":"ExtenderSecrets","Properties":{},"AdditionalProperties":0}},{"8":{"Name":"listSecrets","ResourceType":"Applications.Connector/extenders","ApiVersion":"2022-03-15-privatepreview","Output":165}}]
\ No newline at end of file
diff --git a/hack/bicep-types-radius/generated/applications/applications.connector/2022-03-15-privatepreview/types.md b/hack/bicep-types-radius/generated/applications/applications.connector/2022-03-15-privatepreview/types.md
index 016fc291c..6da2650d2 100644
--- a/hack/bicep-types-radius/generated/applications/applications.connector/2022-03-15-privatepreview/types.md
+++ b/hack/bicep-types-radius/generated/applications/applications.connector/2022-03-15-privatepreview/types.md
@@ -67,7 +67,7 @@
 * **id**: string (ReadOnly, DeployTimeConstant): The resource id
 * **location**: string (Required): The geo-location where the resource lives
 * **name**: string (Required, DeployTimeConstant): The resource name
-* **properties**: [MongoDatabaseProperties](#mongodatabaseproperties) (Required): MongoDatabse connector properties
+* **properties**: [MongoDatabaseProperties](#mongodatabaseproperties) (Required): MongoDatabase connector properties
 * **systemData**: [SystemData](#systemdata) (ReadOnly): Metadata pertaining to creation and last modification of the resource.
 * **tags**: [TrackedResourceTags](#trackedresourcetags): Resource tags.
 * **type**: 'Applications.Connector/mongoDatabases' (ReadOnly, DeployTimeConstant): The resource type
@@ -123,6 +123,11 @@
 * **ApiVersion**: 2022-03-15-privatepreview
 * **Output**: [RabbitMQSecrets](#rabbitmqsecrets)
 
+## Function listSecrets (Applications.Connector/extenders@2022-03-15-privatepreview)
+* **Resource**: Applications.Connector/extenders
+* **ApiVersion**: 2022-03-15-privatepreview
+* **Output**: [ExtenderSecrets](#extendersecrets)
+
 ## DaprInvokeHttpRouteProperties
 ### Properties
 * **appId**: string (Required): The Dapr appId used for the route
@@ -227,12 +232,12 @@
 * **application**: string (ReadOnly): Fully qualified resource ID for the application that the connector is consumed by
 * **environment**: string (Required): Fully qualified resource ID for the environment that the connector is linked to
 * **provisioningState**: 'Accepted' | 'Canceled' | 'Deleting' | 'Failed' | 'Provisioning' | 'Succeeded' | 'Updating' (ReadOnly): Provisioning state of the connector at the time the operation was called
-* **secrets**: [ExtenderPropertiesSecrets](#extenderpropertiessecrets): Dictionary of <any>
+* **secrets**: [ExtenderSecrets](#extendersecrets): The secret values for the given Extender resource
 * **status**: [ResourceStatus](#resourcestatus): Status of a resource.
 ### Additional Properties
 * **Additional Properties Type**: any
 
-## ExtenderPropertiesSecrets
+## ExtenderSecrets
 ### Properties
 ### Additional Properties
 * **Additional Properties Type**: any
@@ -250,14 +255,14 @@
 * **port**: int: Port value of the target Mongo database
 * **provisioningState**: 'Accepted' | 'Canceled' | 'Deleting' | 'Failed' | 'Provisioning' | 'Succeeded' | 'Updating' (ReadOnly): Provisioning state of the connector at the time the operation was called
 * **resource**: string: Fully qualified resource ID of a supported resource with Mongo API to use for this connector
-* **secrets**: [MongoDatabaseSecrets](#mongodatabasesecrets): The secret values for the given MongoDatabase resource
+* **secrets**: [MongoDatabaseSecrets](#mongodatabasesecrets) (WriteOnly): The secret values for the given MongoDatabase resource
 * **status**: [ResourceStatus](#resourcestatus): Status of a resource.
 
 ## MongoDatabaseSecrets
 ### Properties
-* **connectionString**: string: Connection string used to connect to the target Mongo database
-* **password**: string: Password to use when connecting to the target Mongo database
-* **username**: string: Username to use when connecting to the target Mongo database
+* **connectionString**: string (WriteOnly): Connection string used to connect to the target Mongo database
+* **password**: string (WriteOnly): Password to use when connecting to the target Mongo database
+* **username**: string (WriteOnly): Username to use when connecting to the target Mongo database
 
 ## TrackedResourceTags
 ### Properties
@@ -270,12 +275,12 @@
 * **environment**: string (Required): Fully qualified resource ID for the environment that the connector is linked to
 * **provisioningState**: 'Accepted' | 'Canceled' | 'Deleting' | 'Failed' | 'Provisioning' | 'Succeeded' | 'Updating' (ReadOnly): Provisioning state of the connector at the time the operation was called
 * **queue**: string (Required): The name of the queue
-* **secrets**: [RabbitMQSecrets](#rabbitmqsecrets): The secret values for the given RabbitMQMessageQueue resource
+* **secrets**: [RabbitMQSecrets](#rabbitmqsecrets) (WriteOnly): The secret values for the given RabbitMQMessageQueue resource
 * **status**: [ResourceStatus](#resourcestatus): Status of a resource.
 
 ## RabbitMQSecrets
 ### Properties
-* **connectionString**: string: The connection string used to connect to this RabbitMQ instance
+* **connectionString**: string (WriteOnly): The connection string used to connect to this RabbitMQ instance
 
 ## TrackedResourceTags
 ### Properties
@@ -290,13 +295,13 @@
 * **port**: int: The port value of the target redis cache
 * **provisioningState**: 'Accepted' | 'Canceled' | 'Deleting' | 'Failed' | 'Provisioning' | 'Succeeded' | 'Updating' (ReadOnly): Provisioning state of the connector at the time the operation was called
 * **resource**: string: Fully qualified resource ID of a supported resource with Redis API to use for this connector
-* **secrets**: [RedisCacheSecrets](#rediscachesecrets): The secret values for the given RedisCache resource
+* **secrets**: [RedisCacheSecrets](#rediscachesecrets) (WriteOnly): The secret values for the given RedisCache resource
 * **status**: [ResourceStatus](#resourcestatus): Status of a resource.
 
 ## RedisCacheSecrets
 ### Properties
-* **connectionString**: string: The connection string used to connect to the redis cache
-* **password**: string: The password for this Redis instance
+* **connectionString**: string (WriteOnly): The connection string used to connect to the redis cache
+* **password**: string (WriteOnly): The password for this Redis instance
 
 ## TrackedResourceTags
 ### Properties
@@ -320,16 +325,21 @@
 
 ## MongoDatabaseSecrets
 ### Properties
-* **connectionString**: string: Connection string used to connect to the target Mongo database
-* **password**: string: Password to use when connecting to the target Mongo database
-* **username**: string: Username to use when connecting to the target Mongo database
+* **connectionString**: string (WriteOnly): Connection string used to connect to the target Mongo database
+* **password**: string (WriteOnly): Password to use when connecting to the target Mongo database
+* **username**: string (WriteOnly): Username to use when connecting to the target Mongo database
 
 ## RedisCacheSecrets
 ### Properties
-* **connectionString**: string: The connection string used to connect to the redis cache
-* **password**: string: The password for this Redis instance
+* **connectionString**: string (WriteOnly): The connection string used to connect to the redis cache
+* **password**: string (WriteOnly): The password for this Redis instance
 
 ## RabbitMQSecrets
 ### Properties
-* **connectionString**: string: The connection string used to connect to this RabbitMQ instance
+* **connectionString**: string (WriteOnly): The connection string used to connect to this RabbitMQ instance
+
+## ExtenderSecrets
+### Properties
+### Additional Properties
+* **Additional Properties Type**: any
 
diff --git a/hack/bicep-types-radius/generated/index.json b/hack/bicep-types-radius/generated/index.json
index cbdbef834..13e9855c7 100644
--- a/hack/bicep-types-radius/generated/index.json
+++ b/hack/bicep-types-radius/generated/index.json
@@ -1 +1 @@
-{"Resources":{"Applications.Connector/mongoDatabases@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":35},"Applications.Connector/daprPubSubBrokers@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":53},"Applications.Connector/sqlDatabases@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":67},"Applications.Connector/redisCaches@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":82},"Applications.Connector/rabbitMQMessageQueues@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":97},"Applications.Connector/daprSecretStores@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":112},"Applications.Connector/daprInvokeHttpRoutes@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":126},"Applications.Connector/daprStateStores@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":146},"Applications.Connector/extenders@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":161},"Applications.Core/environments@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":34},"Applications.Core/applications@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":48},"Applications.Core/httpRoutes@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":64},"Applications.Core/gateways@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":81},"Applications.Core/containers@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":140}},"Functions":{"applications.connector/mongodatabases":{"2022-03-15-privatepreview":[{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":162}]},"applications.connector/rediscaches":{"2022-03-15-privatepreview":[{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":163}]},"applications.connector/rabbitmqmessagequeues":{"2022-03-15-privatepreview":[{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":164}]}}}
\ No newline at end of file
+{"Resources":{"Applications.Connector/mongoDatabases@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":35},"Applications.Connector/daprPubSubBrokers@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":53},"Applications.Connector/sqlDatabases@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":67},"Applications.Connector/redisCaches@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":82},"Applications.Connector/rabbitMQMessageQueues@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":97},"Applications.Connector/daprSecretStores@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":112},"Applications.Connector/daprInvokeHttpRoutes@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":126},"Applications.Connector/daprStateStores@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":146},"Applications.Connector/extenders@2022-03-15-privatepreview":{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":161},"Applications.Core/environments@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":34},"Applications.Core/applications@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":48},"Applications.Core/httpRoutes@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":64},"Applications.Core/gateways@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":81},"Applications.Core/containers@2022-03-15-privatepreview":{"RelativePath":"applications/applications.core/2022-03-15-privatepreview/types.json","Index":140}},"Functions":{"applications.connector/mongodatabases":{"2022-03-15-privatepreview":[{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":162}]},"applications.connector/rediscaches":{"2022-03-15-privatepreview":[{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":163}]},"applications.connector/rabbitmqmessagequeues":{"2022-03-15-privatepreview":[{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":164}]},"applications.connector/extenders":{"2022-03-15-privatepreview":[{"RelativePath":"applications/applications.connector/2022-03-15-privatepreview/types.json","Index":166}]}}}
\ No newline at end of file
diff --git a/pkg/armrpc/frontend/server/server.go b/pkg/armrpc/frontend/server/server.go
index f1148e8e9..b197ef418 100644
--- a/pkg/armrpc/frontend/server/server.go
+++ b/pkg/armrpc/frontend/server/server.go
@@ -15,6 +15,7 @@ import (
 	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
 	"github.com/project-radius/radius/pkg/middleware"
 	"github.com/project-radius/radius/pkg/telemetry/metrics"
+	"github.com/project-radius/radius/pkg/validator"
 	"github.com/project-radius/radius/pkg/version"
 )
 
@@ -44,6 +45,9 @@ func New(ctx context.Context, options Options) (*http.Server, error) {
 		}
 	}
 
+	r.NotFoundHandler = validator.APINotFoundHandler()
+	r.MethodNotAllowedHandler = validator.APIMethodNotAllowedHandler()
+
 	r.Use(middleware.Recoverer)
 	r.Use(middleware.AppendLogValues)
 	// add the arm cert validation if EnableAuth is true
diff --git a/pkg/cli/azureresources/azure_resource_operations.go b/pkg/cli/azureresources/azure_resource_operations.go
deleted file mode 100644
index f8c0e6b4f..000000000
--- a/pkg/cli/azureresources/azure_resource_operations.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// ------------------------------------------------------------
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-// ------------------------------------------------------------
-
-package azureresources
-
-import (
-	"context"
-
-	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
-	"github.com/project-radius/radius/pkg/connectorrp/api/v20220315privatepreview"
-	"github.com/project-radius/radius/pkg/ucp/resources"
-)
-
-type AzureResourceType int
-
-const (
-	MongoResource AzureResourceType = iota
-	RabbitMQResource
-	RedisResource
-	SQLResource
-)
-
-type AzureResourceOperationsModel struct {
-	ResourceType       AzureResourceType
-	ResourceOperations AzureResourceOperations
-}
-
-// AzureResourceOperations is used to interface with resource operations like listing resources by app, show details of a resource.
-type AzureResourceOperations interface {
-	GetResourcesByApplication(con *arm.Connection, ctx context.Context, rootScope string, applicationName string) ([]v20220315privatepreview.Resource, error)
-}
-
-var _ AzureResourceOperations = (*MongoResourceOperations)(nil)
-
-type MongoResourceOperations struct {
-}
-
-func (mo *MongoResourceOperations) GetResourcesByApplication(con *arm.Connection, ctx context.Context, rootScope string, applicationName string) ([]v20220315privatepreview.Resource, error) {
-	mongoClient := v20220315privatepreview.NewMongoDatabasesClient(con, rootScope)
-	mongoPager := mongoClient.ListByRootScope(nil)
-	resourceMap := make(map[string]v20220315privatepreview.Resource)
-	for mongoPager.NextPage(ctx) {
-		mongoResourceList := mongoPager.PageResponse().MongoDatabaseList.Value
-		for _, mongoResource := range mongoResourceList {
-			resourceMap[*mongoResource.Properties.Application] = mongoResource.Resource
-		}
-	}
-	return filterByApplicationName(resourceMap, applicationName)
-}
-
-var _ AzureResourceOperations = (*RabbitResourceOperations)(nil)
-
-type RabbitResourceOperations struct {
-}
-
-func (ro *RabbitResourceOperations) GetResourcesByApplication(con *arm.Connection, ctx context.Context, rootScope string, applicationName string) ([]v20220315privatepreview.Resource, error) {
-	rabbitClient := v20220315privatepreview.NewRabbitMQMessageQueuesClient(con, rootScope)
-	rabbitPager := rabbitClient.ListByRootScope(nil)
-	resourceMap := make(map[string]v20220315privatepreview.Resource)
-	for rabbitPager.NextPage(ctx) {
-		mongoResourceList := rabbitPager.PageResponse().RabbitMQMessageQueueList.Value
-		for _, mongoResource := range mongoResourceList {
-			resourceMap[*mongoResource.Properties.Application] = mongoResource.Resource
-		}
-	}
-	return filterByApplicationName(resourceMap, applicationName)
-}
-
-var _ AzureResourceOperations = (*RedisResourceOperations)(nil)
-
-type RedisResourceOperations struct {
-}
-
-func (ro *RedisResourceOperations) GetResourcesByApplication(con *arm.Connection, ctx context.Context, rootScope string, applicationName string) ([]v20220315privatepreview.Resource, error) {
-	redisClient := v20220315privatepreview.NewRedisCachesClient(con, rootScope)
-	redisPager := redisClient.ListByRootScope(nil)
-	resourceMap := make(map[string]v20220315privatepreview.Resource)
-	for redisPager.NextPage(ctx) {
-		mongoResourceList := redisPager.PageResponse().RedisCacheList.Value
-		for _, mongoResource := range mongoResourceList {
-			resourceMap[*mongoResource.Properties.Application] = mongoResource.Resource
-		}
-	}
-	return filterByApplicationName(resourceMap, applicationName)
-}
-
-var _ AzureResourceOperations = (*SQLResourceOperations)(nil)
-
-type SQLResourceOperations struct {
-}
-
-func (ro *SQLResourceOperations) GetResourcesByApplication(con *arm.Connection, ctx context.Context, rootScope string, applicationName string) ([]v20220315privatepreview.Resource, error) {
-	sqlClient := v20220315privatepreview.NewSQLDatabasesClient(con, rootScope)
-	sqlPager := sqlClient.ListByRootScope(nil)
-	resourceMap := make(map[string]v20220315privatepreview.Resource)
-	for sqlPager.NextPage(ctx) {
-		mongoResourceList := sqlPager.PageResponse().SQLDatabaseList.Value
-		for _, mongoResource := range mongoResourceList {
-			resourceMap[*mongoResource.Properties.Application] = mongoResource.Resource
-		}
-	}
-	return filterByApplicationName(resourceMap, applicationName)
-}
-
-func filterByApplicationName(resourceList map[string]v20220315privatepreview.Resource, applicationName string) ([]v20220315privatepreview.Resource, error) {
-	filteredResourceList := []v20220315privatepreview.Resource{}
-	for appId, resource := range resourceList {
-		IdParsed, err := resources.Parse(appId)
-		if err != nil {
-			return nil, err
-		}
-		if IdParsed.Name() == applicationName {
-			filteredResourceList = append(filteredResourceList, resource)
-		}
-	}
-	return filteredResourceList, nil
-}
diff --git a/pkg/cli/clients/clients.go b/pkg/cli/clients/clients.go
index 57ce12fc9..2502e53d2 100644
--- a/pkg/cli/clients/clients.go
+++ b/pkg/cli/clients/clients.go
@@ -12,8 +12,8 @@ import (
 
 	"github.com/project-radius/radius/pkg/azure/azresources"
 	"github.com/project-radius/radius/pkg/azure/radclient"
+	"github.com/project-radius/radius/pkg/cli/clients_new/generated"
 	"github.com/project-radius/radius/pkg/cli/output"
-	"github.com/project-radius/radius/pkg/connectorrp/api/v20220315privatepreview"
 )
 
 // NOTE: parameters in the template engine follow the structure:
@@ -118,7 +118,7 @@ type LegacyManagementClient interface {
 
 // ApplicationsManagementClient is used to interface with management features like listing resources by app, show details of a resource.
 type ApplicationsManagementClient interface {
-	ListAllResourcesByApplication(ctx context.Context, applicationName string) ([]v20220315privatepreview.Resource, error)
+	ListAllResourcesByApplication(ctx context.Context, applicationName string) ([]generated.GenericResource, error)
 }
 
 func ShallowCopy(params DeploymentParameters) DeploymentParameters {
diff --git a/pkg/cli/clients_new/README.md b/pkg/cli/clients_new/README.md
index 621a67092..e8e17f360 100644
--- a/pkg/cli/clients_new/README.md
+++ b/pkg/cli/clients_new/README.md
@@ -1,4 +1,3 @@
-## Generate new models
 ### Prerequisites
 1. Install [NodeJS](https://nodejs.org/)
 2. Install [AutoRest](http://aka.ms/autorest)
@@ -44,3 +43,6 @@ These settings apply only when `--tag=2022-03-15-privatepreview` is specified on
 ```yaml $(tag) == '2022-03-15-privatepreview'
 output-folder: ./generated
 ```
+
+### Adding ResourceTypes:
+All resource types are tracked in resourceTypesList in ucp package. Whenever a new core-rp or connectors type is added this list has to be updated.
diff --git a/pkg/cli/clients_new/generated/zz_generated_models.go b/pkg/cli/clients_new/generated/zz_generated_models.go
index 564ac5d44..62f38da99 100644
--- a/pkg/cli/clients_new/generated/zz_generated_models.go
+++ b/pkg/cli/clients_new/generated/zz_generated_models.go
@@ -71,8 +71,8 @@ func (e ErrorResponse) Error() string {
 // GenericResource - Generic resource
 type GenericResource struct {
 	TrackedResource
-	// Any object
-	ResourceProperties map[string]interface{} `json:"resourceProperties,omitempty"`
+	// REQUIRED; Any object
+	Properties map[string]interface{} `json:"properties,omitempty"`
 
 	// READ-ONLY; Metadata pertaining to creation and last modification of the resource.
 	SystemData *SystemData `json:"systemData,omitempty" azure:"ro"`
@@ -82,7 +82,7 @@ type GenericResource struct {
 func (g GenericResource) MarshalJSON() ([]byte, error) {
 	objectMap := make(map[string]interface{})
 	g.TrackedResource.marshalInternal(objectMap)
-	populate(objectMap, "resourceProperties", g.ResourceProperties)
+	populate(objectMap, "properties", g.Properties)
 	populate(objectMap, "systemData", g.SystemData)
 	return json.Marshal(objectMap)
 }
diff --git a/pkg/cli/environments/azure.go b/pkg/cli/environments/azure.go
index cfaf46b4f..30a38e710 100644
--- a/pkg/cli/environments/azure.go
+++ b/pkg/cli/environments/azure.go
@@ -30,22 +30,10 @@ func RequireAzureCloud(e Environment) (*AzureCloudEnvironment, error) {
 
 // AzureCloudEnvironment represents an Azure Cloud Radius environment.
 type AzureCloudEnvironment struct {
-	Name                     string `mapstructure:"name" validate:"required"`
-	Kind                     string `mapstructure:"kind" validate:"required"`
-	SubscriptionID           string `mapstructure:"subscriptionid" validate:"required"`
-	ResourceGroup            string `mapstructure:"resourcegroup" validate:"required"`
-	ClusterName              string `mapstructure:"clustername" validate:"required"`
-	DefaultApplication       string `mapstructure:"defaultapplication" yaml:",omitempty"`
-	Context                  string `mapstructure:"context" validate:"required"`
-	Namespace                string `mapstructure:"namespace" validate:"required"`
-	RadiusRPLocalURL         string `mapstructure:"radiusrplocalurl,omitempty"`
-	DeploymentEngineLocalURL string `mapstructure:"deploymentenginelocalurl,omitempty"`
-	UCPLocalURL              string `mapstructure:"ucplocalurl,omitempty"`
-	EnableUCP                bool   `mapstructure:"enableucp,omitempty"`
-	UCPResourceGroupName     string `mapstructure:"ucpresourcegroupname,omitempty"`
-
-	// We tolerate and allow extra fields - this helps with forwards compat.
-	Properties map[string]interface{} `mapstructure:",remain" yaml:",omitempty"`
+	RadiusEnvironment `mapstructure:",squash"`
+	ClusterName       string `mapstructure:"clustername" validate:"required"`
+	SubscriptionID    string `mapstructure:"subscriptionid" validate:"required"`
+	ResourceGroup     string `mapstructure:"resourcegroup" validate:"required"`
 }
 
 func (e *AzureCloudEnvironment) GetName() string {
@@ -138,7 +126,7 @@ func (e *AzureCloudEnvironment) CreateDiagnosticsClient(ctx context.Context) (cl
 		return nil, err
 	}
 
-	_, con, err := kubernetes.CreateAPIServerConnection(e.Context, e.RadiusRPLocalURL)
+	_, con, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.RadiusRPLocalURL)
 	if err != nil {
 		return nil, err
 	}
@@ -154,7 +142,7 @@ func (e *AzureCloudEnvironment) CreateDiagnosticsClient(ctx context.Context) (cl
 }
 
 func (e *AzureCloudEnvironment) CreateLegacyManagementClient(ctx context.Context) (clients.LegacyManagementClient, error) {
-	_, connection, err := kubernetes.CreateAPIServerConnection(e.Context, e.RadiusRPLocalURL)
+	_, connection, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.RadiusRPLocalURL)
 	if err != nil {
 		return nil, err
 	}
@@ -168,7 +156,7 @@ func (e *AzureCloudEnvironment) CreateLegacyManagementClient(ctx context.Context
 }
 
 func (e *AzureCloudEnvironment) CreateApplicationsManagementClient(ctx context.Context) (clients.ApplicationsManagementClient, error) {
-	_, connection, err := kubernetes.CreateAPIServerConnection(e.Context, e.UCPLocalURL)
+	_, connection, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.UCPLocalURL)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/cli/environments/dev.go b/pkg/cli/environments/dev.go
index 4742786d8..8379505ae 100644
--- a/pkg/cli/environments/dev.go
+++ b/pkg/cli/environments/dev.go
@@ -24,28 +24,11 @@ import (
 
 // LocalEnvironment represents a local test setup for Azure Cloud Radius environment.
 type LocalEnvironment struct {
-	Name               string `mapstructure:"name" validate:"required"`
-	Kind               string `mapstructure:"kind" validate:"required"`
-	DefaultApplication string `mapstructure:"defaultapplication,omitempty"`
-
-	Context     string `mapstructure:"context" validate:"required"`
-	Namespace   string `mapstructure:"namespace" validate:"required"`
-	ClusterName string `mapstructure:"clustername" validate:"required"`
-
+	RadiusEnvironment `mapstructure:",squash"`
 	// Registry is the docker/OCI registry we're using for images.
-	Registry *Registry `mapstructure:"registry,omitempty"`
-
-	// RadiusRPLocalURL is an override for local debugging. This allows us us to run the controller + API Service outside the
-	// cluster.
-	RadiusRPLocalURL         string     `mapstructure:"radiusrplocalurl,omitempty"`
-	DeploymentEngineLocalURL string     `mapstructure:"deploymentenginelocalurl,omitempty"`
-	UCPLocalURL              string     `mapstructure:"ucplocalurl,omitempty"`
-	Providers                *Providers `mapstructure:"providers"`
-	EnableUCP                bool       `mapstructure:"enableucp,omitempty"`
-	UCPResourceGroupName     string     `mapstructure:"ucpresourcegroupname,omitempty"`
-
-	// We tolerate and allow extra fields - this helps with forwards compat.
-	Properties map[string]interface{} `mapstructure:",remain"`
+	ClusterName string     `mapstructure:"clustername" validate:"required"`
+	Registry    *Registry  `mapstructure:"registry,omitempty"`
+	Providers   *Providers `mapstructure:"providers"`
 }
 
 func (e *LocalEnvironment) GetName() string {
@@ -163,7 +146,7 @@ func (e *LocalEnvironment) CreateDiagnosticsClient(ctx context.Context) (clients
 		return nil, err
 	}
 
-	_, con, err := kubernetes.CreateAPIServerConnection(e.Context, e.RadiusRPLocalURL)
+	_, con, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.RadiusRPLocalURL)
 	if err != nil {
 		return nil, err
 	}
@@ -180,7 +163,7 @@ func (e *LocalEnvironment) CreateDiagnosticsClient(ctx context.Context) (clients
 }
 
 func (e *LocalEnvironment) CreateLegacyManagementClient(ctx context.Context) (clients.LegacyManagementClient, error) {
-	_, connection, err := kubernetes.CreateAPIServerConnection(e.Context, e.RadiusRPLocalURL)
+	_, connection, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.RadiusRPLocalURL)
 	if err != nil {
 		return nil, err
 	}
@@ -202,7 +185,7 @@ func (e *LocalEnvironment) CreateServerLifecycleClient(ctx context.Context) (cli
 }
 
 func (e *LocalEnvironment) CreateApplicationsManagementClient(ctx context.Context) (clients.ApplicationsManagementClient, error) {
-	_, connection, err := kubernetes.CreateAPIServerConnection(e.Context, e.UCPLocalURL)
+	_, connection, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.UCPLocalURL)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/cli/environments/kubernetes.go b/pkg/cli/environments/kubernetes.go
index 10ae6111c..f50d61183 100644
--- a/pkg/cli/environments/kubernetes.go
+++ b/pkg/cli/environments/kubernetes.go
@@ -22,19 +22,7 @@ import (
 
 // KubernetesEnvironment represents a Kubernetes Radius environment.
 type KubernetesEnvironment struct {
-	Name                     string `mapstructure:"name" validate:"required"`
-	Kind                     string `mapstructure:"kind" validate:"required"`
-	Context                  string `mapstructure:"context" validate:"required"`
-	Namespace                string `mapstructure:"namespace" validate:"required"`
-	DefaultApplication       string `mapstructure:"defaultapplication,omitempty"`
-	RadiusRPLocalURL         string `mapstructure:"radiusrplocalurl,omitempty"`
-	DeploymentEngineLocalURL string `mapstructure:"deploymentenginelocalurl,omitempty"`
-	UCPLocalURL              string `mapstructure:"ucplocalurl,omitempty"`
-	EnableUCP                bool   `mapstructure:"enableucp,omitempty"`
-	UCPResourceGroupName     string `mapstructure:"ucpresourcegroupname,omitempty"`
-
-	// We tolerate and allow extra fields - this helps with forwards compat.
-	Properties map[string]interface{} `mapstructure:",remain"`
+	RadiusEnvironment `mapstructure:",squash"`
 }
 
 func (e *KubernetesEnvironment) GetName() string {
@@ -112,7 +100,7 @@ func (e *KubernetesEnvironment) CreateDiagnosticsClient(ctx context.Context) (cl
 		return nil, err
 	}
 
-	_, con, err := kubernetes.CreateAPIServerConnection(e.Context, e.RadiusRPLocalURL)
+	_, con, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.RadiusRPLocalURL)
 	if err != nil {
 		return nil, err
 	}
@@ -128,7 +116,7 @@ func (e *KubernetesEnvironment) CreateDiagnosticsClient(ctx context.Context) (cl
 }
 
 func (e *KubernetesEnvironment) CreateLegacyManagementClient(ctx context.Context) (clients.LegacyManagementClient, error) {
-	_, connection, err := kubernetes.CreateAPIServerConnection(e.Context, e.RadiusRPLocalURL)
+	_, connection, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.RadiusRPLocalURL)
 	if err != nil {
 		return nil, err
 	}
@@ -142,7 +130,7 @@ func (e *KubernetesEnvironment) CreateLegacyManagementClient(ctx context.Context
 }
 
 func (e *KubernetesEnvironment) CreateApplicationsManagementClient(ctx context.Context) (clients.ApplicationsManagementClient, error) {
-	_, connection, err := kubernetes.CreateAPIServerConnection(e.Context, e.UCPLocalURL)
+	_, connection, err := kubernetes.CreateLegacyAPIServerConnection(e.Context, e.UCPLocalURL)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/cli/environments/radius.go b/pkg/cli/environments/radius.go
new file mode 100644
index 000000000..6ee667e4e
--- /dev/null
+++ b/pkg/cli/environments/radius.go
@@ -0,0 +1,24 @@
+package environments
+
+type RadiusEnvironment struct {
+	Name               string `mapstructure:"name" validate:"required"`
+	Kind               string `mapstructure:"kind" validate:"required"`
+	Context            string `mapstructure:"context" validate:"required"`
+	Namespace          string `mapstructure:"namespace" validate:"required"`
+	DefaultApplication string `mapstructure:"defaultapplication" yaml:",omitempty"`
+	Scope              string `mapstructure:"scope,omitempty"`
+	Id                 string `mapstructure:"id,omitempty"`
+
+	// DEBUG STUFF:
+
+	// RadiusRPLocalURL is an override for local debugging. This allows us us to run the controller + API Service outside the cluster.
+	RadiusRPLocalURL         string `mapstructure:"radiusrplocalurl,omitempty"`
+	DeploymentEngineLocalURL string `mapstructure:"deploymentenginelocalurl,omitempty"`
+	UCPLocalURL              string `mapstructure:"ucplocalurl,omitempty"`
+	UCPResourceGroupName     string `mapstructure:"ucpresourcegroupname,omitempty"`
+	EnableUCP                bool   `mapstructure:"enableucp,omitempty"`
+
+	// Capture arbitrary other properties
+	// We tolerate and allow extra fields - this helps with forwards compat.
+	Properties map[string]interface{} `mapstructure:",remain"`
+}
diff --git a/pkg/cli/kubernetes/kubernetes.go b/pkg/cli/kubernetes/kubernetes.go
index fe20b5cac..a0837216d 100644
--- a/pkg/cli/kubernetes/kubernetes.go
+++ b/pkg/cli/kubernetes/kubernetes.go
@@ -43,14 +43,14 @@ import (
 )
 
 const (
-	APIServerBasePath        = "/apis/api.radius.dev/v1alpha3"
+	LegacyAPIServerBasePath  = "/apis/api.radius.dev/v1alpha3"
+	APIServerBasePath        = "/apis/api.ucp.dev/v1alpha3"
 	DeploymentEngineBasePath = "/apis/api.bicep.dev/v1alpha3"
 	Location                 = "Location"
 	AzureAsyncOperation      = "Azure-AsyncOperation"
 	IngressServiceName       = "contour-envoy"
 	RadiusConfigName         = "radius-config"
 	RadiusSystemNamespace    = "radius-system"
-	UCPBasePath              = "/apis/api.ucp.dev/v1alpha3"
 	UCPType                  = "api.ucp.dev"
 	BicepType                = "api.bicep.dev"
 )
@@ -120,9 +120,19 @@ func CreateRestRoundTripper(context string, group string, overrideURL string) (h
 	return NewLocationRewriteRoundTripper(merged.Host, client), err
 }
 
-func CreateAPIServerConnection(context string, overrideURL string) (string, *arm.Connection, error) {
+func CreateLegacyAPIServerConnection(context string, overrideURL string) (string, *arm.Connection, error) {
+	baseURL, roundTripper, err := GetLegacyBaseUrlAndRoundTripper(overrideURL, "api.radius.dev", context)
+	if err != nil {
+		return "", nil, err
+	}
 
-	baseURL, roundTripper, err := GetBaseUrlAndRoundTripper(overrideURL, "api.radius.dev", context)
+	return baseURL, arm.NewConnection(baseURL, &radclient.AnonymousCredential{}, &arm.ConnectionOptions{
+		HTTPClient: &KubernetesTransporter{Client: roundTripper},
+	}), nil
+}
+
+func CreateAPIServerConnection(context string, overrideURL string) (string, *arm.Connection, error) {
+	baseURL, roundTripper, err := GetBaseUrlAndRoundTripper(overrideURL, UCPType, context)
 	if err != nil {
 		return "", nil, err
 	}
@@ -133,7 +143,7 @@ func CreateAPIServerConnection(context string, overrideURL string) (string, *arm
 }
 
 func GetBaseUrlForDeploymentEngine(overrideURL string) string {
-	return strings.TrimSuffix(overrideURL, "/") + UCPBasePath
+	return strings.TrimSuffix(overrideURL, "/") + APIServerBasePath
 }
 
 func GetBaseUrlAndRoundTripperForDeploymentEngine(deploymentEngineURL string, ucpURL string, context string, enableUCP bool) (string, http.RoundTripper, error) {
@@ -141,7 +151,7 @@ func GetBaseUrlAndRoundTripperForDeploymentEngine(deploymentEngineURL string, uc
 	var roundTripper http.RoundTripper
 	var basePath string
 	if enableUCP {
-		basePath = UCPBasePath
+		basePath = APIServerBasePath
 	} else {
 		basePath = DeploymentEngineBasePath
 	}
@@ -175,6 +185,29 @@ func GetBaseUrlAndRoundTripperForDeploymentEngine(deploymentEngineURL string, uc
 	return baseURL, roundTripper, nil
 }
 
+func GetLegacyBaseUrlAndRoundTripper(overrideURL string, group string, context string) (string, http.RoundTripper, error) {
+	var baseURL string
+	var roundTripper http.RoundTripper
+	if overrideURL != "" {
+		baseURL = strings.TrimSuffix(overrideURL, "/") + LegacyAPIServerBasePath
+		roundTripper = NewLocationRewriteRoundTripper(overrideURL, http.DefaultTransport)
+	} else {
+		restConfig, err := GetConfig(context)
+		if err != nil {
+			return "", nil, err
+		}
+
+		roundTripper, err = CreateRestRoundTripper(context, group, overrideURL)
+		if err != nil {
+			return "", nil, err
+		}
+
+		baseURL = strings.TrimSuffix(restConfig.Host+restConfig.APIPath, "/") + LegacyAPIServerBasePath
+		roundTripper = NewLocationRewriteRoundTripper(restConfig.Host, roundTripper)
+	}
+	return baseURL, roundTripper, nil
+}
+
 func GetBaseUrlAndRoundTripper(overrideURL string, group string, context string) (string, http.RoundTripper, error) {
 	var baseURL string
 	var roundTripper http.RoundTripper
diff --git a/pkg/cli/swagger/genericResource.json b/pkg/cli/swagger/genericResource.json
index fb684afb0..bac5d9574 100644
--- a/pkg/cli/swagger/genericResource.json
+++ b/pkg/cli/swagger/genericResource.json
@@ -248,7 +248,7 @@
           "systemData": {
             "$ref": "#/definitions/systemData"
           },
-          "resourceProperties": {
+          "properties": {
             "type": "object"
           }
         }
diff --git a/pkg/cli/ucp/ucp_management.go b/pkg/cli/ucp/ucp_management.go
index 0703560bb..b2843635f 100644
--- a/pkg/cli/ucp/ucp_management.go
+++ b/pkg/cli/ucp/ucp_management.go
@@ -9,9 +9,11 @@ import (
 	"context"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
-	"github.com/project-radius/radius/pkg/cli/azureresources"
+	"github.com/go-logr/logr"
 	"github.com/project-radius/radius/pkg/cli/clients"
-	"github.com/project-radius/radius/pkg/connectorrp/api/v20220315privatepreview"
+	"github.com/project-radius/radius/pkg/cli/clients_new/generated"
+	"github.com/project-radius/radius/pkg/radlogger"
+	"github.com/project-radius/radius/pkg/ucp/resources"
 )
 
 type ARMApplicationsManagementClient struct {
@@ -23,36 +25,63 @@ type ARMApplicationsManagementClient struct {
 var _ clients.ApplicationsManagementClient = (*ARMApplicationsManagementClient)(nil)
 
 var (
-	resourceOperationList = []azureresources.AzureResourceOperationsModel{
-		{
-			ResourceType:       azureresources.MongoResource,
-			ResourceOperations: &azureresources.MongoResourceOperations{},
-		},
-		{
-			ResourceType:       azureresources.RabbitMQResource,
-			ResourceOperations: &azureresources.RabbitResourceOperations{},
-		},
-		{
-			ResourceType:       azureresources.RedisResource,
-			ResourceOperations: &azureresources.RedisResourceOperations{},
-		},
-		{
-			ResourceType:       azureresources.SQLResource,
-			ResourceOperations: &azureresources.SQLResourceOperations{},
-		},
+	resourceTypesList = []string{
+		"Applications.Connector/mongoDatabases",
+		"Applications.Connector/rabbitMQMessageQueues",
+		"Applications.Connector/redisCaches",
+		"Applications.Connector/sqlDatabases",
+		"Applications.Connector/daprStateStores",
+		"Applications.Connector/daprSecretStores",
+		"Applications.Connector/daprPubSubBrokers",
+		"Applications.Connector/daprInvokeHttpRoutes",
+		"Applications.Connector/extenders",
+		"Applications.Core/gateways",
+		"Applications.Core/httpRoutes",
+		"Applications.Core/containers",
 	}
 )
 
 // ListAllResourcesByApplication lists the resources of a particular application
-func (um *ARMApplicationsManagementClient) ListAllResourcesByApplication(ctx context.Context, applicationName string) ([]v20220315privatepreview.Resource, error) {
-	rootScope := um.RootScope
-	resourceListByApplication := make([]v20220315privatepreview.Resource, 0)
-	for _, resourceOperation := range resourceOperationList {
-		resourceList, err := resourceOperation.ResourceOperations.GetResourcesByApplication(um.Connection, ctx, rootScope, applicationName)
-		if err != nil {
-			return nil, err
+func (amc *ARMApplicationsManagementClient) ListAllResourcesByApplication(ctx context.Context, applicationName string) ([]generated.GenericResource, error) {
+	results := []generated.GenericResource{}
+	for _, resourceType := range resourceTypesList {
+		client := generated.NewGenericResourcesClient(amc.Connection, amc.RootScope, resourceType)
+		pager := client.ListByRootScope(nil)
+		for pager.NextPage(ctx) {
+			resourceList := pager.PageResponse().GenericResourcesList.Value
+			for _, resource := range resourceList {
+				isResourceWithApplication, err := isResourceWithApplication(ctx, *resource, applicationName)
+				if err != nil {
+					return nil, err
+				}
+				if isResourceWithApplication {
+					results = append(results, *resource)
+				}
+			}
 		}
-		resourceListByApplication = append(resourceListByApplication, resourceList...)
 	}
-	return resourceListByApplication, nil
+	return results, nil
+}
+
+func isResourceWithApplication(ctx context.Context, resource generated.GenericResource, applicationName string) (bool, error) {
+	log := logr.FromContextOrDiscard(ctx)
+	obj, found := resource.Properties["application"]
+	// A resource may not have an application associated with it.
+	if !found {
+		return false, nil
+	}
+	associatedAppId, ok := obj.(string)
+	if !ok {
+		log.V(radlogger.Warn).Info("Failed to list resources in the application. Resource with invalid application id found.")
+		return false, nil
+	}
+	idParsed, err := resources.Parse(associatedAppId)
+
+	if err != nil {
+		return false, err
+	}
+	if idParsed.Name() == applicationName {
+		return true, nil
+	}
+	return false, nil
 }
diff --git a/pkg/connectorrp/api/v20220315privatepreview/daprinvokehttproute_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/daprinvokehttproute_conversion.go
index 08fc8b10b..4ff2c36cd 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/daprinvokehttproute_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/daprinvokehttproute_conversion.go
@@ -6,8 +6,6 @@
 package v20220315privatepreview
 
 import (
-	"reflect"
-
 	"github.com/project-radius/radius/pkg/armrpc/api/conv"
 	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
@@ -17,10 +15,6 @@ import (
 
 // ConvertTo converts from the versioned DaprInvokeHttpRoute resource to version-agnostic datamodel.
 func (src *DaprInvokeHTTPRouteResource) ConvertTo() (conv.DataModelInterface, error) {
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.Status != nil {
-		outputResources = src.Properties.Status.OutputResources
-	}
 	converted := &datamodel.DaprInvokeHttpRoute{
 		TrackedResource: v1.TrackedResource{
 			ID:       to.String(src.ID),
@@ -32,7 +26,7 @@ func (src *DaprInvokeHTTPRouteResource) ConvertTo() (conv.DataModelInterface, er
 		Properties: datamodel.DaprInvokeHttpRouteProperties{
 			BasicResourceProperties: v1.BasicResourceProperties{
 				Status: v1.ResourceStatus{
-					OutputResources: outputResources,
+					OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
 				},
 			},
 			ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
@@ -60,14 +54,10 @@ func (dst *DaprInvokeHTTPRouteResource) ConvertFrom(src conv.DataModelInterface)
 	dst.SystemData = fromSystemDataModel(daprHttpRoute.SystemData)
 	dst.Location = to.StringPtr(daprHttpRoute.Location)
 	dst.Tags = *to.StringMapPtr(daprHttpRoute.Tags)
-	var outputresources []map[string]interface{}
-	if !(reflect.DeepEqual(daprHttpRoute.Properties.Status, v1.ResourceStatus{})) {
-		outputresources = daprHttpRoute.Properties.Status.OutputResources
-	}
 	dst.Properties = &DaprInvokeHTTPRouteProperties{
 		BasicResourceProperties: BasicResourceProperties{
 			Status: &ResourceStatus{
-				OutputResources: outputresources,
+				OutputResources: GetOutputResourcesForDatamodel(&daprHttpRoute.Properties.Status),
 			},
 		},
 		ProvisioningState: fromProvisioningStateDataModel(daprHttpRoute.Properties.ProvisioningState),
diff --git a/pkg/connectorrp/api/v20220315privatepreview/daprpubsubbroker_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/daprpubsubbroker_conversion.go
index 117226ce8..a4b0b2c24 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/daprpubsubbroker_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/daprpubsubbroker_conversion.go
@@ -18,14 +18,10 @@ import (
 
 // ConvertTo converts from the versioned DaprPubSubBroker resource to version-agnostic datamodel.
 func (src *DaprPubSubBrokerResource) ConvertTo() (conv.DataModelInterface, error) {
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.GetDaprPubSubBrokerProperties().Status != nil {
-		outputResources = src.Properties.GetDaprPubSubBrokerProperties().Status.OutputResources
-	}
 	daprPubSubproperties := datamodel.DaprPubSubBrokerProperties{
 		BasicResourceProperties: v1.BasicResourceProperties{
 			Status: v1.ResourceStatus{
-				OutputResources: outputResources,
+				OutputResources: GetOutputResourcesForVersionedResource(src.Properties.GetDaprPubSubBrokerProperties().Status),
 			},
 		},
 		ProvisioningState: toProvisioningStateDataModel(src.Properties.GetDaprPubSubBrokerProperties().ProvisioningState),
diff --git a/pkg/connectorrp/api/v20220315privatepreview/daprsecretstore_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/daprsecretstore_conversion.go
index 812678c2c..04aa2d943 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/daprsecretstore_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/daprsecretstore_conversion.go
@@ -6,8 +6,6 @@
 package v20220315privatepreview
 
 import (
-	"reflect"
-
 	"github.com/project-radius/radius/pkg/armrpc/api/conv"
 	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
@@ -17,10 +15,6 @@ import (
 
 // ConvertTo converts from the versioned DaprSecretStore resource to version-agnostic datamodel.
 func (src *DaprSecretStoreResource) ConvertTo() (conv.DataModelInterface, error) {
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.Status != nil {
-		outputResources = src.Properties.Status.OutputResources
-	}
 	converted := &datamodel.DaprSecretStore{
 		TrackedResource: v1.TrackedResource{
 			ID:       to.String(src.ID),
@@ -32,7 +26,7 @@ func (src *DaprSecretStoreResource) ConvertTo() (conv.DataModelInterface, error)
 		Properties: datamodel.DaprSecretStoreProperties{
 			BasicResourceProperties: v1.BasicResourceProperties{
 				Status: v1.ResourceStatus{
-					OutputResources: outputResources,
+					OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
 				},
 			},
 			ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
@@ -63,14 +57,10 @@ func (dst *DaprSecretStoreResource) ConvertFrom(src conv.DataModelInterface) err
 	dst.SystemData = fromSystemDataModel(daprSecretStore.SystemData)
 	dst.Location = to.StringPtr(daprSecretStore.Location)
 	dst.Tags = *to.StringMapPtr(daprSecretStore.Tags)
-	var outputresources []map[string]interface{}
-	if !(reflect.DeepEqual(daprSecretStore.Properties.Status, v1.ResourceStatus{})) {
-		outputresources = daprSecretStore.Properties.Status.OutputResources
-	}
 	dst.Properties = &DaprSecretStoreProperties{
 		BasicResourceProperties: BasicResourceProperties{
 			Status: &ResourceStatus{
-				OutputResources: outputresources,
+				OutputResources: GetOutputResourcesForDatamodel(&daprSecretStore.Properties.Status),
 			},
 		},
 		ProvisioningState: fromProvisioningStateDataModel(daprSecretStore.Properties.ProvisioningState),
diff --git a/pkg/connectorrp/api/v20220315privatepreview/extender_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/extender_conversion.go
index ac54923ea..f6eab7219 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/extender_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/extender_conversion.go
@@ -6,8 +6,6 @@
 package v20220315privatepreview
 
 import (
-	"reflect"
-
 	"github.com/project-radius/radius/pkg/armrpc/api/conv"
 	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
@@ -17,10 +15,6 @@ import (
 
 // ConvertTo converts from the versioned Extender resource to version-agnostic datamodel.
 func (src *ExtenderResource) ConvertTo() (conv.DataModelInterface, error) {
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.Status != nil {
-		outputResources = src.Properties.Status.OutputResources
-	}
 	converted := &datamodel.Extender{
 		TrackedResource: v1.TrackedResource{
 			ID:       to.String(src.ID),
@@ -32,7 +26,7 @@ func (src *ExtenderResource) ConvertTo() (conv.DataModelInterface, error) {
 		Properties: datamodel.ExtenderProperties{
 			BasicResourceProperties: v1.BasicResourceProperties{
 				Status: v1.ResourceStatus{
-					OutputResources: outputResources,
+					OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
 				},
 			},
 			ProvisioningState:    toProvisioningStateDataModel(src.Properties.ProvisioningState),
@@ -61,14 +55,10 @@ func (dst *ExtenderResource) ConvertFrom(src conv.DataModelInterface) error {
 	dst.SystemData = fromSystemDataModel(extender.SystemData)
 	dst.Location = to.StringPtr(extender.Location)
 	dst.Tags = *to.StringMapPtr(extender.Tags)
-	var outputresources []map[string]interface{}
-	if !(reflect.DeepEqual(extender.Properties.Status, v1.ResourceStatus{})) {
-		outputresources = extender.Properties.Status.OutputResources
-	}
 	dst.Properties = &ExtenderProperties{
 		BasicResourceProperties: BasicResourceProperties{
 			Status: &ResourceStatus{
-				OutputResources: outputresources,
+				OutputResources: GetOutputResourcesForDatamodel(&extender.Properties.Status),
 			},
 		},
 		ProvisioningState:    fromProvisioningStateDataModel(extender.Properties.ProvisioningState),
diff --git a/pkg/connectorrp/api/v20220315privatepreview/mongodatabase_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/mongodatabase_conversion.go
index 9a0331eca..1c9bd2eaf 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/mongodatabase_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/mongodatabase_conversion.go
@@ -6,8 +6,6 @@
 package v20220315privatepreview
 
 import (
-	"reflect"
-
 	"github.com/project-radius/radius/pkg/armrpc/api/conv"
 	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
@@ -15,6 +13,36 @@ import (
 	"github.com/Azure/go-autorest/autorest/to"
 )
 
+// ConvertTo converts from the versioned MongoDatabaseResponse resource to version-agnostic datamodel.
+func (src *MongoDatabaseResponseResource) ConvertTo() (conv.DataModelInterface, error) {
+	converted := &datamodel.MongoDatabaseResponse{
+		TrackedResource: v1.TrackedResource{
+			ID:       to.String(src.ID),
+			Name:     to.String(src.Name),
+			Type:     to.String(src.Type),
+			Location: to.String(src.Location),
+			Tags:     to.StringMap(src.Tags),
+		},
+		Properties: datamodel.MongoDatabaseResponseProperties{
+			BasicResourceProperties: v1.BasicResourceProperties{
+				Status: v1.ResourceStatus{
+					OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
+				},
+			},
+			ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
+			Environment:       to.String(src.Properties.Environment),
+			Application:       to.String(src.Properties.Application),
+			Resource:          to.String(src.Properties.Resource),
+			Host:              to.String(src.Properties.Host),
+			Port:              to.Int32(src.Properties.Port),
+		},
+		InternalMetadata: v1.InternalMetadata{
+			UpdatedAPIVersion: Version,
+		},
+	}
+	return converted, nil
+}
+
 // ConvertTo converts from the versioned MongoDatabase resource to version-agnostic datamodel.
 func (src *MongoDatabaseResource) ConvertTo() (conv.DataModelInterface, error) {
 	secrets := datamodel.MongoDatabaseSecrets{}
@@ -25,10 +53,6 @@ func (src *MongoDatabaseResource) ConvertTo() (conv.DataModelInterface, error) {
 			Password:         to.String(src.Properties.Secrets.Password),
 		}
 	}
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.Status != nil {
-		outputResources = src.Properties.Status.OutputResources
-	}
 	converted := &datamodel.MongoDatabase{
 		TrackedResource: v1.TrackedResource{
 			ID:       to.String(src.ID),
@@ -38,18 +62,20 @@ func (src *MongoDatabaseResource) ConvertTo() (conv.DataModelInterface, error) {
 			Tags:     to.StringMap(src.Tags),
 		},
 		Properties: datamodel.MongoDatabaseProperties{
-			BasicResourceProperties: v1.BasicResourceProperties{
-				Status: v1.ResourceStatus{
-					OutputResources: outputResources,
+			MongoDatabaseResponseProperties: datamodel.MongoDatabaseResponseProperties{
+				BasicResourceProperties: v1.BasicResourceProperties{
+					Status: v1.ResourceStatus{
+						OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
+					},
 				},
+				ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
+				Environment:       to.String(src.Properties.Environment),
+				Application:       to.String(src.Properties.Application),
+				Resource:          to.String(src.Properties.Resource),
+				Host:              to.String(src.Properties.Host),
+				Port:              to.Int32(src.Properties.Port),
 			},
-			ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
-			Environment:       to.String(src.Properties.Environment),
-			Application:       to.String(src.Properties.Application),
-			Resource:          to.String(src.Properties.Resource),
-			Host:              to.String(src.Properties.Host),
-			Port:              to.Int32(src.Properties.Port),
-			Secrets:           secrets,
+			Secrets: secrets,
 		},
 		InternalMetadata: v1.InternalMetadata{
 			UpdatedAPIVersion: Version,
@@ -58,9 +84,9 @@ func (src *MongoDatabaseResource) ConvertTo() (conv.DataModelInterface, error) {
 	return converted, nil
 }
 
-// ConvertFrom converts from version-agnostic datamodel to the versioned MongoDatabase resource.
-func (dst *MongoDatabaseResource) ConvertFrom(src conv.DataModelInterface) error {
-	mongo, ok := src.(*datamodel.MongoDatabase)
+// ConvertFrom converts from version-agnostic datamodel to the versioned MongoDatabaseResponse resource.
+func (dst *MongoDatabaseResponseResource) ConvertFrom(src conv.DataModelInterface) error {
+	mongo, ok := src.(*datamodel.MongoDatabaseResponse)
 	if !ok {
 		return conv.ErrInvalidModelConversion
 	}
@@ -71,14 +97,10 @@ func (dst *MongoDatabaseResource) ConvertFrom(src conv.DataModelInterface) error
 	dst.SystemData = fromSystemDataModel(mongo.SystemData)
 	dst.Location = to.StringPtr(mongo.Location)
 	dst.Tags = *to.StringMapPtr(mongo.Tags)
-	var outputresources []map[string]interface{}
-	if !(reflect.DeepEqual(mongo.Properties.Status, v1.ResourceStatus{})) {
-		outputresources = mongo.Properties.Status.OutputResources
-	}
-	dst.Properties = &MongoDatabaseProperties{
+	dst.Properties = &MongoDatabaseResponseProperties{
 		BasicResourceProperties: BasicResourceProperties{
 			Status: &ResourceStatus{
-				OutputResources: outputresources,
+				OutputResources: GetOutputResourcesForDatamodel(&mongo.Properties.Status),
 			},
 		},
 		ProvisioningState: fromProvisioningStateDataModel(mongo.Properties.ProvisioningState),
@@ -88,6 +110,37 @@ func (dst *MongoDatabaseResource) ConvertFrom(src conv.DataModelInterface) error
 		Host:              to.StringPtr(mongo.Properties.Host),
 		Port:              to.Int32Ptr(mongo.Properties.Port),
 	}
+	return nil
+}
+
+// ConvertFrom converts from version-agnostic datamodel to the versioned MongoDatabase resource.
+func (dst *MongoDatabaseResource) ConvertFrom(src conv.DataModelInterface) error {
+	mongo, ok := src.(*datamodel.MongoDatabase)
+	if !ok {
+		return conv.ErrInvalidModelConversion
+	}
+
+	dst.ID = to.StringPtr(mongo.ID)
+	dst.Name = to.StringPtr(mongo.Name)
+	dst.Type = to.StringPtr(mongo.Type)
+	dst.SystemData = fromSystemDataModel(mongo.SystemData)
+	dst.Location = to.StringPtr(mongo.Location)
+	dst.Tags = *to.StringMapPtr(mongo.Tags)
+	dst.Properties = &MongoDatabaseProperties{
+		MongoDatabaseResponseProperties: MongoDatabaseResponseProperties{
+			BasicResourceProperties: BasicResourceProperties{
+				Status: &ResourceStatus{
+					OutputResources: GetOutputResourcesForDatamodel(&mongo.Properties.Status),
+				},
+			},
+			ProvisioningState: fromProvisioningStateDataModel(mongo.Properties.ProvisioningState),
+			Environment:       to.StringPtr(mongo.Properties.Environment),
+			Application:       to.StringPtr(mongo.Properties.Application),
+			Resource:          to.StringPtr(mongo.Properties.Resource),
+			Host:              to.StringPtr(mongo.Properties.Host),
+			Port:              to.Int32Ptr(mongo.Properties.Port),
+		},
+	}
 	if (mongo.Properties.Secrets != datamodel.MongoDatabaseSecrets{}) {
 		dst.Properties.Secrets = &MongoDatabaseSecrets{
 			ConnectionString: to.StringPtr(mongo.Properties.Secrets.ConnectionString),
@@ -122,3 +175,19 @@ func (src *MongoDatabaseSecrets) ConvertTo() (conv.DataModelInterface, error) {
 	}
 	return converted, nil
 }
+
+func GetOutputResourcesForVersionedResource(status *ResourceStatus) []map[string]interface{} {
+	var outputResources []map[string]interface{}
+	if status != nil {
+		outputResources = status.OutputResources
+	}
+	return outputResources
+}
+
+func GetOutputResourcesForDatamodel(status *v1.ResourceStatus) []map[string]interface{} {
+	var outputResources []map[string]interface{}
+	if status != nil {
+		outputResources = status.OutputResources
+	}
+	return outputResources
+}
diff --git a/pkg/connectorrp/api/v20220315privatepreview/rabbitmq_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/rabbitmq_conversion.go
index a4824e578..adce70b4b 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/rabbitmq_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/rabbitmq_conversion.go
@@ -6,8 +6,6 @@
 package v20220315privatepreview
 
 import (
-	"reflect"
-
 	"github.com/project-radius/radius/pkg/armrpc/api/conv"
 	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
@@ -23,10 +21,6 @@ func (src *RabbitMQMessageQueueResource) ConvertTo() (conv.DataModelInterface, e
 			ConnectionString: to.String(src.Properties.Secrets.ConnectionString),
 		}
 	}
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.Status != nil {
-		outputResources = src.Properties.Status.OutputResources
-	}
 	converted := &datamodel.RabbitMQMessageQueue{
 		TrackedResource: v1.TrackedResource{
 			ID:       to.String(src.ID),
@@ -36,16 +30,46 @@ func (src *RabbitMQMessageQueueResource) ConvertTo() (conv.DataModelInterface, e
 			Tags:     to.StringMap(src.Tags),
 		},
 		Properties: datamodel.RabbitMQMessageQueueProperties{
+			RabbitMQMessageQueueResponseProperties: datamodel.RabbitMQMessageQueueResponseProperties{
+				BasicResourceProperties: v1.BasicResourceProperties{
+					Status: v1.ResourceStatus{
+						OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
+					},
+				},
+				ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
+				Environment:       to.String(src.Properties.Environment),
+				Application:       to.String(src.Properties.Application),
+				Queue:             to.String(src.Properties.Queue),
+			},
+			Secrets: secrets,
+		},
+		InternalMetadata: v1.InternalMetadata{
+			UpdatedAPIVersion: Version,
+		},
+	}
+	return converted, nil
+}
+
+// ConvertTo converts from the versioned RabbitMQMessageQueue resource to version-agnostic datamodel.
+func (src *RabbitMQMessageQueueResponseResource) ConvertTo() (conv.DataModelInterface, error) {
+	converted := &datamodel.RabbitMQMessageQueueResponse{
+		TrackedResource: v1.TrackedResource{
+			ID:       to.String(src.ID),
+			Name:     to.String(src.Name),
+			Type:     to.String(src.Type),
+			Location: to.String(src.Location),
+			Tags:     to.StringMap(src.Tags),
+		},
+		Properties: datamodel.RabbitMQMessageQueueResponseProperties{
 			BasicResourceProperties: v1.BasicResourceProperties{
 				Status: v1.ResourceStatus{
-					OutputResources: outputResources,
+					OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
 				},
 			},
 			ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
 			Environment:       to.String(src.Properties.Environment),
 			Application:       to.String(src.Properties.Application),
 			Queue:             to.String(src.Properties.Queue),
-			Secrets:           secrets,
 		},
 		InternalMetadata: v1.InternalMetadata{
 			UpdatedAPIVersion: Version,
@@ -67,20 +91,18 @@ func (dst *RabbitMQMessageQueueResource) ConvertFrom(src conv.DataModelInterface
 	dst.SystemData = fromSystemDataModel(rabbitmq.SystemData)
 	dst.Location = to.StringPtr(rabbitmq.Location)
 	dst.Tags = *to.StringMapPtr(rabbitmq.Tags)
-	var outputresources []map[string]interface{}
-	if !(reflect.DeepEqual(rabbitmq.Properties.Status, v1.ResourceStatus{})) {
-		outputresources = rabbitmq.Properties.Status.OutputResources
-	}
 	dst.Properties = &RabbitMQMessageQueueProperties{
-		BasicResourceProperties: BasicResourceProperties{
-			Status: &ResourceStatus{
-				OutputResources: outputresources,
+		RabbitMQMessageQueueResponseProperties: RabbitMQMessageQueueResponseProperties{
+			BasicResourceProperties: BasicResourceProperties{
+				Status: &ResourceStatus{
+					OutputResources: GetOutputResourcesForDatamodel(&rabbitmq.Properties.Status),
+				},
 			},
+			ProvisioningState: fromProvisioningStateDataModel(rabbitmq.Properties.ProvisioningState),
+			Environment:       to.StringPtr(rabbitmq.Properties.Environment),
+			Application:       to.StringPtr(rabbitmq.Properties.Application),
+			Queue:             to.StringPtr(rabbitmq.Properties.Queue),
 		},
-		ProvisioningState: fromProvisioningStateDataModel(rabbitmq.Properties.ProvisioningState),
-		Environment:       to.StringPtr(rabbitmq.Properties.Environment),
-		Application:       to.StringPtr(rabbitmq.Properties.Application),
-		Queue:             to.StringPtr(rabbitmq.Properties.Queue),
 	}
 	if (rabbitmq.Properties.Secrets != datamodel.RabbitMQSecrets{}) {
 		dst.Properties.Secrets = &RabbitMQSecrets{
@@ -91,43 +113,48 @@ func (dst *RabbitMQMessageQueueResource) ConvertFrom(src conv.DataModelInterface
 	return nil
 }
 
-// ConvertFrom converts from version-agnostic datamodel to the versioned RabbitMQSecrets instance.
-func (dst *RabbitMQSecrets) ConvertFrom(src conv.DataModelInterface) error {
-	rabbitMQSecrets, ok := src.(*datamodel.RabbitMQSecrets)
+// ConvertFrom converts from version-agnostic datamodel to the versioned RabbitMQMessageQueue respones resource.
+func (dst *RabbitMQMessageQueueResponseResource) ConvertFrom(src conv.DataModelInterface) error {
+	rabbitmq, ok := src.(*datamodel.RabbitMQMessageQueueResponse)
 	if !ok {
 		return conv.ErrInvalidModelConversion
 	}
 
-	dst.ConnectionString = to.StringPtr(rabbitMQSecrets.ConnectionString)
-	return nil
-}
-
-// ConvertTo converts from the versioned RabbitMQSecrets instance to version-agnostic datamodel.
-func (src *RabbitMQSecrets) ConvertTo() (conv.DataModelInterface, error) {
-	converted := &datamodel.RabbitMQSecrets{
-		ConnectionString: to.String(src.ConnectionString),
+	dst.ID = to.StringPtr(rabbitmq.ID)
+	dst.Name = to.StringPtr(rabbitmq.Name)
+	dst.Type = to.StringPtr(rabbitmq.Type)
+	dst.SystemData = fromSystemDataModel(rabbitmq.SystemData)
+	dst.Location = to.StringPtr(rabbitmq.Location)
+	dst.Tags = *to.StringMapPtr(rabbitmq.Tags)
+	dst.Properties = &RabbitMQMessageQueueResponseProperties{
+		BasicResourceProperties: BasicResourceProperties{
+			Status: &ResourceStatus{
+				OutputResources: GetOutputResourcesForDatamodel(&rabbitmq.Properties.Status),
+			},
+		},
+		ProvisioningState: fromProvisioningStateDataModel(rabbitmq.Properties.ProvisioningState),
+		Environment:       to.StringPtr(rabbitmq.Properties.Environment),
+		Application:       to.StringPtr(rabbitmq.Properties.Application),
+		Queue:             to.StringPtr(rabbitmq.Properties.Queue),
 	}
-	return converted, nil
+	return nil
 }
 
-// ConvertFrom converts from version-agnostic datamodel to the versioned RedisCacheSecrets instance.
-func (dst *RedisCacheSecrets) ConvertFrom(src conv.DataModelInterface) error {
-	redisSecrets, ok := src.(*datamodel.RedisCacheSecrets)
+// ConvertFrom converts from version-agnostic datamodel to the versioned RabbitMQSecrets instance.
+func (dst *RabbitMQSecrets) ConvertFrom(src conv.DataModelInterface) error {
+	rabbitMQSecrets, ok := src.(*datamodel.RabbitMQSecrets)
 	if !ok {
 		return conv.ErrInvalidModelConversion
 	}
 
-	dst.ConnectionString = to.StringPtr(redisSecrets.ConnectionString)
-	dst.Password = to.StringPtr(redisSecrets.Password)
-
+	dst.ConnectionString = to.StringPtr(rabbitMQSecrets.ConnectionString)
 	return nil
 }
 
-// ConvertTo converts from the versioned RedisCacheSecrets instance to version-agnostic datamodel.
-func (src *RedisCacheSecrets) ConvertTo() (conv.DataModelInterface, error) {
-	converted := &datamodel.RedisCacheSecrets{
+// ConvertTo converts from the versioned RabbitMQSecrets instance to version-agnostic datamodel.
+func (src *RabbitMQSecrets) ConvertTo() (conv.DataModelInterface, error) {
+	converted := &datamodel.RabbitMQSecrets{
 		ConnectionString: to.String(src.ConnectionString),
-		Password:         to.String(src.Password),
 	}
 	return converted, nil
 }
diff --git a/pkg/connectorrp/api/v20220315privatepreview/rediscache_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/rediscache_conversion.go
index d48d15990..56ae00a4a 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/rediscache_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/rediscache_conversion.go
@@ -6,8 +6,6 @@
 package v20220315privatepreview
 
 import (
-	"reflect"
-
 	"github.com/project-radius/radius/pkg/armrpc/api/conv"
 	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
@@ -24,10 +22,6 @@ func (src *RedisCacheResource) ConvertTo() (conv.DataModelInterface, error) {
 			Password:         to.String(src.Properties.Secrets.Password),
 		}
 	}
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.Status != nil {
-		outputResources = src.Properties.Status.OutputResources
-	}
 	converted := &datamodel.RedisCache{
 		TrackedResource: v1.TrackedResource{
 			ID:       to.String(src.ID),
@@ -37,9 +31,42 @@ func (src *RedisCacheResource) ConvertTo() (conv.DataModelInterface, error) {
 			Tags:     to.StringMap(src.Tags),
 		},
 		Properties: datamodel.RedisCacheProperties{
+			RedisCacheResponseProperties: datamodel.RedisCacheResponseProperties{
+				BasicResourceProperties: v1.BasicResourceProperties{
+					Status: v1.ResourceStatus{
+						OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
+					},
+				},
+				ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
+				Environment:       to.String(src.Properties.Environment),
+				Application:       to.String(src.Properties.Application),
+				Resource:          to.String(src.Properties.Resource),
+				Host:              to.String(src.Properties.Host),
+				Port:              to.Int32(src.Properties.Port),
+			},
+			Secrets: secrets,
+		},
+		InternalMetadata: v1.InternalMetadata{
+			UpdatedAPIVersion: Version,
+		},
+	}
+	return converted, nil
+}
+
+// ConvertTo converts from the versioned RedisCacheResponse resource to version-agnostic datamodel.
+func (src *RedisCacheResponseResource) ConvertTo() (conv.DataModelInterface, error) {
+	converted := &datamodel.RedisCacheResponse{
+		TrackedResource: v1.TrackedResource{
+			ID:       to.String(src.ID),
+			Name:     to.String(src.Name),
+			Type:     to.String(src.Type),
+			Location: to.String(src.Location),
+			Tags:     to.StringMap(src.Tags),
+		},
+		Properties: datamodel.RedisCacheResponseProperties{
 			BasicResourceProperties: v1.BasicResourceProperties{
 				Status: v1.ResourceStatus{
-					OutputResources: outputResources,
+					OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
 				},
 			},
 			ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
@@ -48,7 +75,6 @@ func (src *RedisCacheResource) ConvertTo() (conv.DataModelInterface, error) {
 			Resource:          to.String(src.Properties.Resource),
 			Host:              to.String(src.Properties.Host),
 			Port:              to.Int32(src.Properties.Port),
-			Secrets:           secrets,
 		},
 		InternalMetadata: v1.InternalMetadata{
 			UpdatedAPIVersion: Version,
@@ -70,14 +96,48 @@ func (dst *RedisCacheResource) ConvertFrom(src conv.DataModelInterface) error {
 	dst.SystemData = fromSystemDataModel(redis.SystemData)
 	dst.Location = to.StringPtr(redis.Location)
 	dst.Tags = *to.StringMapPtr(redis.Tags)
-	var outputresources []map[string]interface{}
-	if !(reflect.DeepEqual(redis.Properties.Status, v1.ResourceStatus{})) {
-		outputresources = redis.Properties.Status.OutputResources
-	}
 	dst.Properties = &RedisCacheProperties{
+		RedisCacheResponseProperties: RedisCacheResponseProperties{
+			BasicResourceProperties: BasicResourceProperties{
+				Status: &ResourceStatus{
+					OutputResources: GetOutputResourcesForDatamodel(&redis.Properties.Status),
+				},
+			},
+			ProvisioningState: fromProvisioningStateDataModel(redis.Properties.ProvisioningState),
+			Environment:       to.StringPtr(redis.Properties.Environment),
+			Application:       to.StringPtr(redis.Properties.Application),
+			Resource:          to.StringPtr(redis.Properties.Resource),
+			Host:              to.StringPtr(redis.Properties.Host),
+			Port:              to.Int32Ptr(redis.Properties.Port),
+		},
+	}
+	if (redis.Properties.Secrets != datamodel.RedisCacheSecrets{}) {
+		dst.Properties.Secrets = &RedisCacheSecrets{
+			ConnectionString: to.StringPtr(redis.Properties.Secrets.ConnectionString),
+			Password:         to.StringPtr(redis.Properties.Secrets.Password),
+		}
+	}
+
+	return nil
+}
+
+// ConvertFrom converts from version-agnostic datamodel to the versioned RedisCache response resource.
+func (dst *RedisCacheResponseResource) ConvertFrom(src conv.DataModelInterface) error {
+	redis, ok := src.(*datamodel.RedisCacheResponse)
+	if !ok {
+		return conv.ErrInvalidModelConversion
+	}
+
+	dst.ID = to.StringPtr(redis.ID)
+	dst.Name = to.StringPtr(redis.Name)
+	dst.Type = to.StringPtr(redis.Type)
+	dst.SystemData = fromSystemDataModel(redis.SystemData)
+	dst.Location = to.StringPtr(redis.Location)
+	dst.Tags = *to.StringMapPtr(redis.Tags)
+	dst.Properties = &RedisCacheResponseProperties{
 		BasicResourceProperties: BasicResourceProperties{
 			Status: &ResourceStatus{
-				OutputResources: outputresources,
+				OutputResources: GetOutputResourcesForDatamodel(&redis.Properties.Status),
 			},
 		},
 		ProvisioningState: fromProvisioningStateDataModel(redis.Properties.ProvisioningState),
@@ -87,12 +147,27 @@ func (dst *RedisCacheResource) ConvertFrom(src conv.DataModelInterface) error {
 		Host:              to.StringPtr(redis.Properties.Host),
 		Port:              to.Int32Ptr(redis.Properties.Port),
 	}
-	if (redis.Properties.Secrets != datamodel.RedisCacheSecrets{}) {
-		dst.Properties.Secrets = &RedisCacheSecrets{
-			ConnectionString: to.StringPtr(redis.Properties.Secrets.ConnectionString),
-			Password:         to.StringPtr(redis.Properties.Secrets.Password),
-		}
+	return nil
+}
+
+// ConvertFrom converts from version-agnostic datamodel to the versioned RedisCacheSecrets instance.
+func (dst *RedisCacheSecrets) ConvertFrom(src conv.DataModelInterface) error {
+	redisSecrets, ok := src.(*datamodel.RedisCacheSecrets)
+	if !ok {
+		return conv.ErrInvalidModelConversion
 	}
 
+	dst.ConnectionString = to.StringPtr(redisSecrets.ConnectionString)
+	dst.Password = to.StringPtr(redisSecrets.Password)
+
 	return nil
 }
+
+// ConvertTo converts from the versioned RedisCacheSecrets instance to version-agnostic datamodel.
+func (src *RedisCacheSecrets) ConvertTo() (conv.DataModelInterface, error) {
+	converted := &datamodel.RedisCacheSecrets{
+		ConnectionString: to.String(src.ConnectionString),
+		Password:         to.String(src.Password),
+	}
+	return converted, nil
+}
diff --git a/pkg/connectorrp/api/v20220315privatepreview/sqldatabase_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/sqldatabase_conversion.go
index 2f36ef0e7..e99aafa6e 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/sqldatabase_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/sqldatabase_conversion.go
@@ -6,8 +6,6 @@
 package v20220315privatepreview
 
 import (
-	"reflect"
-
 	"github.com/project-radius/radius/pkg/armrpc/api/conv"
 	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
@@ -17,10 +15,6 @@ import (
 
 // ConvertTo converts from the versioned SqlDatabase resource to version-agnostic datamodel.
 func (src *SQLDatabaseResource) ConvertTo() (conv.DataModelInterface, error) {
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.Status != nil {
-		outputResources = src.Properties.Status.OutputResources
-	}
 	converted := &datamodel.SqlDatabase{
 		TrackedResource: v1.TrackedResource{
 			ID:       to.String(src.ID),
@@ -32,7 +26,7 @@ func (src *SQLDatabaseResource) ConvertTo() (conv.DataModelInterface, error) {
 		Properties: datamodel.SqlDatabaseProperties{
 			BasicResourceProperties: v1.BasicResourceProperties{
 				Status: v1.ResourceStatus{
-					OutputResources: outputResources,
+					OutputResources: GetOutputResourcesForVersionedResource(src.Properties.Status),
 				},
 			},
 			ProvisioningState: toProvisioningStateDataModel(src.Properties.ProvisioningState),
@@ -62,14 +56,10 @@ func (dst *SQLDatabaseResource) ConvertFrom(src conv.DataModelInterface) error {
 	dst.SystemData = fromSystemDataModel(sql.SystemData)
 	dst.Location = to.StringPtr(sql.Location)
 	dst.Tags = *to.StringMapPtr(sql.Tags)
-	var outputresources []map[string]interface{}
-	if !(reflect.DeepEqual(sql.Properties.Status, v1.ResourceStatus{})) {
-		outputresources = sql.Properties.Status.OutputResources
-	}
 	dst.Properties = &SQLDatabaseProperties{
 		BasicResourceProperties: BasicResourceProperties{
 			Status: &ResourceStatus{
-				OutputResources: outputresources,
+				OutputResources: GetOutputResourcesForDatamodel(&sql.Properties.Status),
 			},
 		},
 		ProvisioningState: fromProvisioningStateDataModel(sql.Properties.ProvisioningState),
diff --git a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_extenders_client.go b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_extenders_client.go
index f8dbccff6..6034fcb9e 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_extenders_client.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_extenders_client.go
@@ -261,3 +261,64 @@ func (client *ExtendersClient) listByRootScopeHandleError(resp *http.Response) e
 	return runtime.NewResponseError(&errType, resp)
 }
 
+// ListSecrets - Lists secrets values for the specified Extender resource
+// If the operation fails it returns the *ErrorResponse error type.
+func (client *ExtendersClient) ListSecrets(ctx context.Context, extenderName string, options *ExtendersListSecretsOptions) (ExtendersListSecretsResponse, error) {
+	req, err := client.listSecretsCreateRequest(ctx, extenderName, options)
+	if err != nil {
+		return ExtendersListSecretsResponse{}, err
+	}
+	resp, err := 	client.pl.Do(req)
+	if err != nil {
+		return ExtendersListSecretsResponse{}, err
+	}
+	if !runtime.HasStatusCode(resp, http.StatusOK) {
+		return ExtendersListSecretsResponse{}, client.listSecretsHandleError(resp)
+	}
+	return client.listSecretsHandleResponse(resp)
+}
+
+// listSecretsCreateRequest creates the ListSecrets request.
+func (client *ExtendersClient) listSecretsCreateRequest(ctx context.Context, extenderName string, options *ExtendersListSecretsOptions) (*policy.Request, error) {
+	urlPath := "/{rootScope}/providers/Applications.Connector/extenders/{extenderName}/listSecrets"
+	if client.rootScope == "" {
+		return nil, errors.New("parameter client.rootScope cannot be empty")
+	}
+	urlPath = strings.ReplaceAll(urlPath, "{rootScope}", url.PathEscape(client.rootScope))
+	if extenderName == "" {
+		return nil, errors.New("parameter extenderName cannot be empty")
+	}
+	urlPath = strings.ReplaceAll(urlPath, "{extenderName}", url.PathEscape(extenderName))
+	req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(	client.ep, urlPath))
+	if err != nil {
+		return nil, err
+	}
+	reqQP := req.Raw().URL.Query()
+	reqQP.Set("api-version", "2022-03-15-privatepreview")
+	req.Raw().URL.RawQuery = reqQP.Encode()
+	req.Raw().Header.Set("Accept", "application/json")
+	return req, nil
+}
+
+// listSecretsHandleResponse handles the ListSecrets response.
+func (client *ExtendersClient) listSecretsHandleResponse(resp *http.Response) (ExtendersListSecretsResponse, error) {
+	result := ExtendersListSecretsResponse{RawResponse: resp}
+	if err := runtime.UnmarshalAsJSON(resp, &result.Value); err != nil {
+		return ExtendersListSecretsResponse{}, err
+	}
+	return result, nil
+}
+
+// listSecretsHandleError handles the ListSecrets error response.
+func (client *ExtendersClient) listSecretsHandleError(resp *http.Response) error {
+	body, err := runtime.Payload(resp)
+	if err != nil {
+		return runtime.NewResponseError(err, resp)
+	}
+		errType := ErrorResponse{raw: string(body)}
+	if err := runtime.UnmarshalAsJSON(resp, &errType); err != nil {
+		return runtime.NewResponseError(fmt.Errorf("%s\n%s", string(body), err), resp)
+	}
+	return runtime.NewResponseError(&errType, resp)
+}
+
diff --git a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_models.go b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_models.go
index 1023c169d..411d72aaf 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_models.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_models.go
@@ -962,7 +962,7 @@ type ExtenderProperties struct {
 	// OPTIONAL; Contains additional key/value pairs not defined in the schema.
 	AdditionalProperties map[string]interface{}
 
-	// Dictionary of
+	// The secret values for the given Extender resource
 	Secrets map[string]interface{} `json:"secrets,omitempty"`
 
 	// READ-ONLY; Fully qualified resource ID for the application that the connector is consumed by
@@ -1100,13 +1100,18 @@ type ExtendersListByRootScopeOptions struct {
 	// placeholder for future optional parameters
 }
 
+// ExtendersListSecretsOptions contains the optional parameters for the Extenders.ListSecrets method.
+type ExtendersListSecretsOptions struct {
+	// placeholder for future optional parameters
+}
+
 // MongoDatabaseList - Object that includes an array of MongoDatabase and a possible link for next set
 type MongoDatabaseList struct {
 	// The link used to fetch the next page of MongoDatabase list.
 	NextLink *string `json:"nextLink,omitempty"`
 
 	// List of MongoDatabase resources
-	Value []*MongoDatabaseResource `json:"value,omitempty"`
+	Value []*MongoDatabaseResponseResource `json:"value,omitempty"`
 }
 
 // MarshalJSON implements the json.Marshaller interface for type MongoDatabaseList.
@@ -1117,8 +1122,91 @@ func (m MongoDatabaseList) MarshalJSON() ([]byte, error) {
 	return json.Marshal(objectMap)
 }
 
-// MongoDatabaseProperties - MongoDatabse connector properties
+// MongoDatabaseProperties - MongoDatabase connector properties
 type MongoDatabaseProperties struct {
+	MongoDatabaseResponseProperties
+	// Secrets values provided for the resource
+	Secrets *MongoDatabaseSecrets `json:"secrets,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaller interface for type MongoDatabaseProperties.
+func (m MongoDatabaseProperties) MarshalJSON() ([]byte, error) {
+	objectMap := make(map[string]interface{})
+	m.MongoDatabaseResponseProperties.marshalInternal(objectMap)
+	populate(objectMap, "secrets", m.Secrets)
+	return json.Marshal(objectMap)
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface for type MongoDatabaseProperties.
+func (m *MongoDatabaseProperties) UnmarshalJSON(data []byte) error {
+	var rawMsg map[string]json.RawMessage
+	if err := json.Unmarshal(data, &rawMsg); err != nil {
+		return err
+	}
+	for key, val := range rawMsg {
+		var err error
+		switch key {
+		case "secrets":
+				err = unpopulate(val, &m.Secrets)
+				delete(rawMsg, key)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	if err := m.MongoDatabaseResponseProperties.unmarshalInternal(rawMsg); err != nil {
+		return err
+	}
+	return nil
+}
+
+// MongoDatabaseResource - MongoDatabase connector
+type MongoDatabaseResource struct {
+	TrackedResource
+	// REQUIRED; MongoDatabase connector properties
+	Properties *MongoDatabaseProperties `json:"properties,omitempty"`
+
+	// READ-ONLY; Metadata pertaining to creation and last modification of the resource.
+	SystemData *SystemData `json:"systemData,omitempty" azure:"ro"`
+}
+
+// MarshalJSON implements the json.Marshaller interface for type MongoDatabaseResource.
+func (m MongoDatabaseResource) MarshalJSON() ([]byte, error) {
+	objectMap := make(map[string]interface{})
+	m.TrackedResource.marshalInternal(objectMap)
+	populate(objectMap, "properties", m.Properties)
+	populate(objectMap, "systemData", m.SystemData)
+	return json.Marshal(objectMap)
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface for type MongoDatabaseResource.
+func (m *MongoDatabaseResource) UnmarshalJSON(data []byte) error {
+	var rawMsg map[string]json.RawMessage
+	if err := json.Unmarshal(data, &rawMsg); err != nil {
+		return err
+	}
+	for key, val := range rawMsg {
+		var err error
+		switch key {
+		case "properties":
+				err = unpopulate(val, &m.Properties)
+				delete(rawMsg, key)
+		case "systemData":
+				err = unpopulate(val, &m.SystemData)
+				delete(rawMsg, key)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	if err := m.TrackedResource.unmarshalInternal(rawMsg); err != nil {
+		return err
+	}
+	return nil
+}
+
+// MongoDatabaseResponseProperties - MongoDatabase connector properties
+type MongoDatabaseResponseProperties struct {
 	BasicResourceProperties
 	// REQUIRED; Fully qualified resource ID for the environment that the connector is linked to
 	Environment *string `json:"environment,omitempty"`
@@ -1132,9 +1220,6 @@ type MongoDatabaseProperties struct {
 	// Fully qualified resource ID of a supported resource with Mongo API to use for this connector
 	Resource *string `json:"resource,omitempty"`
 
-	// Secrets values provided for the resource
-	Secrets *MongoDatabaseSecrets `json:"secrets,omitempty"`
-
 	// READ-ONLY; Fully qualified resource ID for the application that the connector is consumed by
 	Application *string `json:"application,omitempty" azure:"ro"`
 
@@ -1142,9 +1227,23 @@ type MongoDatabaseProperties struct {
 	ProvisioningState *ProvisioningState `json:"provisioningState,omitempty" azure:"ro"`
 }
 
-// MarshalJSON implements the json.Marshaller interface for type MongoDatabaseProperties.
-func (m MongoDatabaseProperties) MarshalJSON() ([]byte, error) {
+// MarshalJSON implements the json.Marshaller interface for type MongoDatabaseResponseProperties.
+func (m MongoDatabaseResponseProperties) MarshalJSON() ([]byte, error) {
 	objectMap := make(map[string]interface{})
+	m.marshalInternal(objectMap)
+	return json.Marshal(objectMap)
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface for type MongoDatabaseResponseProperties.
+func (m *MongoDatabaseResponseProperties) UnmarshalJSON(data []byte) error {
+	var rawMsg map[string]json.RawMessage
+	if err := json.Unmarshal(data, &rawMsg); err != nil {
+		return err
+	}
+	return m.unmarshalInternal(rawMsg)
+}
+
+func (m MongoDatabaseResponseProperties) marshalInternal(objectMap map[string]interface{}) {
 	m.BasicResourceProperties.marshalInternal(objectMap)
 	populate(objectMap, "application", m.Application)
 	populate(objectMap, "environment", m.Environment)
@@ -1152,16 +1251,9 @@ func (m MongoDatabaseProperties) MarshalJSON() ([]byte, error) {
 	populate(objectMap, "port", m.Port)
 	populate(objectMap, "provisioningState", m.ProvisioningState)
 	populate(objectMap, "resource", m.Resource)
-	populate(objectMap, "secrets", m.Secrets)
-	return json.Marshal(objectMap)
 }
 
-// UnmarshalJSON implements the json.Unmarshaller interface for type MongoDatabaseProperties.
-func (m *MongoDatabaseProperties) UnmarshalJSON(data []byte) error {
-	var rawMsg map[string]json.RawMessage
-	if err := json.Unmarshal(data, &rawMsg); err != nil {
-		return err
-	}
+func (m *MongoDatabaseResponseProperties) unmarshalInternal(rawMsg map[string]json.RawMessage) error {
 	for key, val := range rawMsg {
 		var err error
 		switch key {
@@ -1183,9 +1275,6 @@ func (m *MongoDatabaseProperties) UnmarshalJSON(data []byte) error {
 		case "resource":
 				err = unpopulate(val, &m.Resource)
 				delete(rawMsg, key)
-		case "secrets":
-				err = unpopulate(val, &m.Secrets)
-				delete(rawMsg, key)
 		}
 		if err != nil {
 			return err
@@ -1197,18 +1286,18 @@ func (m *MongoDatabaseProperties) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
-// MongoDatabaseResource - MongoDatabse connector
-type MongoDatabaseResource struct {
+// MongoDatabaseResponseResource - MongoDatabase connector
+type MongoDatabaseResponseResource struct {
 	TrackedResource
-	// REQUIRED; MongoDatabse connector properties
-	Properties *MongoDatabaseProperties `json:"properties,omitempty"`
+	// REQUIRED; MongoDatabase connector properties
+	Properties *MongoDatabaseResponseProperties `json:"properties,omitempty"`
 
 	// READ-ONLY; Metadata pertaining to creation and last modification of the resource.
 	SystemData *SystemData `json:"systemData,omitempty" azure:"ro"`
 }
 
-// MarshalJSON implements the json.Marshaller interface for type MongoDatabaseResource.
-func (m MongoDatabaseResource) MarshalJSON() ([]byte, error) {
+// MarshalJSON implements the json.Marshaller interface for type MongoDatabaseResponseResource.
+func (m MongoDatabaseResponseResource) MarshalJSON() ([]byte, error) {
 	objectMap := make(map[string]interface{})
 	m.TrackedResource.marshalInternal(objectMap)
 	populate(objectMap, "properties", m.Properties)
@@ -1216,8 +1305,8 @@ func (m MongoDatabaseResource) MarshalJSON() ([]byte, error) {
 	return json.Marshal(objectMap)
 }
 
-// UnmarshalJSON implements the json.Unmarshaller interface for type MongoDatabaseResource.
-func (m *MongoDatabaseResource) UnmarshalJSON(data []byte) error {
+// UnmarshalJSON implements the json.Unmarshaller interface for type MongoDatabaseResponseResource.
+func (m *MongoDatabaseResponseResource) UnmarshalJSON(data []byte) error {
 	var rawMsg map[string]json.RawMessage
 	if err := json.Unmarshal(data, &rawMsg); err != nil {
 		return err
@@ -1285,7 +1374,7 @@ type RabbitMQMessageQueueList struct {
 	NextLink *string `json:"nextLink,omitempty"`
 
 	// List of RabbitMQMessageQueue resources
-	Value []*RabbitMQMessageQueueResource `json:"value,omitempty"`
+	Value []*RabbitMQMessageQueueResponseResource `json:"value,omitempty"`
 }
 
 // MarshalJSON implements the json.Marshaller interface for type RabbitMQMessageQueueList.
@@ -1298,6 +1387,89 @@ func (r RabbitMQMessageQueueList) MarshalJSON() ([]byte, error) {
 
 // RabbitMQMessageQueueProperties - RabbitMQMessageQueue connector properties
 type RabbitMQMessageQueueProperties struct {
+	RabbitMQMessageQueueResponseProperties
+	// Secrets provided by resources,
+	Secrets *RabbitMQSecrets `json:"secrets,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaller interface for type RabbitMQMessageQueueProperties.
+func (r RabbitMQMessageQueueProperties) MarshalJSON() ([]byte, error) {
+	objectMap := make(map[string]interface{})
+	r.RabbitMQMessageQueueResponseProperties.marshalInternal(objectMap)
+	populate(objectMap, "secrets", r.Secrets)
+	return json.Marshal(objectMap)
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface for type RabbitMQMessageQueueProperties.
+func (r *RabbitMQMessageQueueProperties) UnmarshalJSON(data []byte) error {
+	var rawMsg map[string]json.RawMessage
+	if err := json.Unmarshal(data, &rawMsg); err != nil {
+		return err
+	}
+	for key, val := range rawMsg {
+		var err error
+		switch key {
+		case "secrets":
+				err = unpopulate(val, &r.Secrets)
+				delete(rawMsg, key)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	if err := r.RabbitMQMessageQueueResponseProperties.unmarshalInternal(rawMsg); err != nil {
+		return err
+	}
+	return nil
+}
+
+// RabbitMQMessageQueueResource - RabbitMQMessageQueue connector
+type RabbitMQMessageQueueResource struct {
+	TrackedResource
+	// REQUIRED; RabbitMQMessageQueue connector properties
+	Properties *RabbitMQMessageQueueProperties `json:"properties,omitempty"`
+
+	// READ-ONLY; Metadata pertaining to creation and last modification of the resource.
+	SystemData *SystemData `json:"systemData,omitempty" azure:"ro"`
+}
+
+// MarshalJSON implements the json.Marshaller interface for type RabbitMQMessageQueueResource.
+func (r RabbitMQMessageQueueResource) MarshalJSON() ([]byte, error) {
+	objectMap := make(map[string]interface{})
+	r.TrackedResource.marshalInternal(objectMap)
+	populate(objectMap, "properties", r.Properties)
+	populate(objectMap, "systemData", r.SystemData)
+	return json.Marshal(objectMap)
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface for type RabbitMQMessageQueueResource.
+func (r *RabbitMQMessageQueueResource) UnmarshalJSON(data []byte) error {
+	var rawMsg map[string]json.RawMessage
+	if err := json.Unmarshal(data, &rawMsg); err != nil {
+		return err
+	}
+	for key, val := range rawMsg {
+		var err error
+		switch key {
+		case "properties":
+				err = unpopulate(val, &r.Properties)
+				delete(rawMsg, key)
+		case "systemData":
+				err = unpopulate(val, &r.SystemData)
+				delete(rawMsg, key)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	if err := r.TrackedResource.unmarshalInternal(rawMsg); err != nil {
+		return err
+	}
+	return nil
+}
+
+// RabbitMQMessageQueueResponseProperties - RabbitMQMessageQueue connector response properties
+type RabbitMQMessageQueueResponseProperties struct {
 	BasicResourceProperties
 	// REQUIRED; Fully qualified resource ID for the environment that the connector is linked to
 	Environment *string `json:"environment,omitempty"`
@@ -1305,9 +1477,6 @@ type RabbitMQMessageQueueProperties struct {
 	// REQUIRED; The name of the queue
 	Queue *string `json:"queue,omitempty"`
 
-	// Secrets provided by resources,
-	Secrets *RabbitMQSecrets `json:"secrets,omitempty"`
-
 	// READ-ONLY; Fully qualified resource ID for the application that the connector is consumed by
 	Application *string `json:"application,omitempty" azure:"ro"`
 
@@ -1315,24 +1484,31 @@ type RabbitMQMessageQueueProperties struct {
 	ProvisioningState *ProvisioningState `json:"provisioningState,omitempty" azure:"ro"`
 }
 
-// MarshalJSON implements the json.Marshaller interface for type RabbitMQMessageQueueProperties.
-func (r RabbitMQMessageQueueProperties) MarshalJSON() ([]byte, error) {
+// MarshalJSON implements the json.Marshaller interface for type RabbitMQMessageQueueResponseProperties.
+func (r RabbitMQMessageQueueResponseProperties) MarshalJSON() ([]byte, error) {
 	objectMap := make(map[string]interface{})
-	r.BasicResourceProperties.marshalInternal(objectMap)
-	populate(objectMap, "application", r.Application)
-	populate(objectMap, "environment", r.Environment)
-	populate(objectMap, "provisioningState", r.ProvisioningState)
-	populate(objectMap, "queue", r.Queue)
-	populate(objectMap, "secrets", r.Secrets)
+	r.marshalInternal(objectMap)
 	return json.Marshal(objectMap)
 }
 
-// UnmarshalJSON implements the json.Unmarshaller interface for type RabbitMQMessageQueueProperties.
-func (r *RabbitMQMessageQueueProperties) UnmarshalJSON(data []byte) error {
+// UnmarshalJSON implements the json.Unmarshaller interface for type RabbitMQMessageQueueResponseProperties.
+func (r *RabbitMQMessageQueueResponseProperties) UnmarshalJSON(data []byte) error {
 	var rawMsg map[string]json.RawMessage
 	if err := json.Unmarshal(data, &rawMsg); err != nil {
 		return err
 	}
+	return r.unmarshalInternal(rawMsg)
+}
+
+func (r RabbitMQMessageQueueResponseProperties) marshalInternal(objectMap map[string]interface{}) {
+	r.BasicResourceProperties.marshalInternal(objectMap)
+	populate(objectMap, "application", r.Application)
+	populate(objectMap, "environment", r.Environment)
+	populate(objectMap, "provisioningState", r.ProvisioningState)
+	populate(objectMap, "queue", r.Queue)
+}
+
+func (r *RabbitMQMessageQueueResponseProperties) unmarshalInternal(rawMsg map[string]json.RawMessage) error {
 	for key, val := range rawMsg {
 		var err error
 		switch key {
@@ -1348,9 +1524,6 @@ func (r *RabbitMQMessageQueueProperties) UnmarshalJSON(data []byte) error {
 		case "queue":
 				err = unpopulate(val, &r.Queue)
 				delete(rawMsg, key)
-		case "secrets":
-				err = unpopulate(val, &r.Secrets)
-				delete(rawMsg, key)
 		}
 		if err != nil {
 			return err
@@ -1362,18 +1535,18 @@ func (r *RabbitMQMessageQueueProperties) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
-// RabbitMQMessageQueueResource - RabbitMQMessageQueue connector
-type RabbitMQMessageQueueResource struct {
+// RabbitMQMessageQueueResponseResource - RabbitMQMessageQueue connector
+type RabbitMQMessageQueueResponseResource struct {
 	TrackedResource
-	// REQUIRED; RabbitMQMessageQueue connector properties
-	Properties *RabbitMQMessageQueueProperties `json:"properties,omitempty"`
+	// REQUIRED; RabbitMQMessageQueue connector response properties
+	Properties *RabbitMQMessageQueueResponseProperties `json:"properties,omitempty"`
 
 	// READ-ONLY; Metadata pertaining to creation and last modification of the resource.
 	SystemData *SystemData `json:"systemData,omitempty" azure:"ro"`
 }
 
-// MarshalJSON implements the json.Marshaller interface for type RabbitMQMessageQueueResource.
-func (r RabbitMQMessageQueueResource) MarshalJSON() ([]byte, error) {
+// MarshalJSON implements the json.Marshaller interface for type RabbitMQMessageQueueResponseResource.
+func (r RabbitMQMessageQueueResponseResource) MarshalJSON() ([]byte, error) {
 	objectMap := make(map[string]interface{})
 	r.TrackedResource.marshalInternal(objectMap)
 	populate(objectMap, "properties", r.Properties)
@@ -1381,8 +1554,8 @@ func (r RabbitMQMessageQueueResource) MarshalJSON() ([]byte, error) {
 	return json.Marshal(objectMap)
 }
 
-// UnmarshalJSON implements the json.Unmarshaller interface for type RabbitMQMessageQueueResource.
-func (r *RabbitMQMessageQueueResource) UnmarshalJSON(data []byte) error {
+// UnmarshalJSON implements the json.Unmarshaller interface for type RabbitMQMessageQueueResponseResource.
+func (r *RabbitMQMessageQueueResponseResource) UnmarshalJSON(data []byte) error {
 	var rawMsg map[string]json.RawMessage
 	if err := json.Unmarshal(data, &rawMsg); err != nil {
 		return err
@@ -1444,7 +1617,7 @@ type RedisCacheList struct {
 	NextLink *string `json:"nextLink,omitempty"`
 
 	// List of RedisCache resources
-	Value []*RedisCacheResource `json:"value,omitempty"`
+	Value []*RedisCacheResponseResource `json:"value,omitempty"`
 }
 
 // MarshalJSON implements the json.Marshaller interface for type RedisCacheList.
@@ -1457,6 +1630,89 @@ func (r RedisCacheList) MarshalJSON() ([]byte, error) {
 
 // RedisCacheProperties - RedisCache connector properties
 type RedisCacheProperties struct {
+	RedisCacheResponseProperties
+	// The secret values for the given RedisCache resource
+	Secrets *RedisCacheSecrets `json:"secrets,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaller interface for type RedisCacheProperties.
+func (r RedisCacheProperties) MarshalJSON() ([]byte, error) {
+	objectMap := make(map[string]interface{})
+	r.RedisCacheResponseProperties.marshalInternal(objectMap)
+	populate(objectMap, "secrets", r.Secrets)
+	return json.Marshal(objectMap)
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface for type RedisCacheProperties.
+func (r *RedisCacheProperties) UnmarshalJSON(data []byte) error {
+	var rawMsg map[string]json.RawMessage
+	if err := json.Unmarshal(data, &rawMsg); err != nil {
+		return err
+	}
+	for key, val := range rawMsg {
+		var err error
+		switch key {
+		case "secrets":
+				err = unpopulate(val, &r.Secrets)
+				delete(rawMsg, key)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	if err := r.RedisCacheResponseProperties.unmarshalInternal(rawMsg); err != nil {
+		return err
+	}
+	return nil
+}
+
+// RedisCacheResource - RedisCache connector
+type RedisCacheResource struct {
+	TrackedResource
+	// REQUIRED; RedisCache connector properties
+	Properties *RedisCacheProperties `json:"properties,omitempty"`
+
+	// READ-ONLY; Metadata pertaining to creation and last modification of the resource.
+	SystemData *SystemData `json:"systemData,omitempty" azure:"ro"`
+}
+
+// MarshalJSON implements the json.Marshaller interface for type RedisCacheResource.
+func (r RedisCacheResource) MarshalJSON() ([]byte, error) {
+	objectMap := make(map[string]interface{})
+	r.TrackedResource.marshalInternal(objectMap)
+	populate(objectMap, "properties", r.Properties)
+	populate(objectMap, "systemData", r.SystemData)
+	return json.Marshal(objectMap)
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface for type RedisCacheResource.
+func (r *RedisCacheResource) UnmarshalJSON(data []byte) error {
+	var rawMsg map[string]json.RawMessage
+	if err := json.Unmarshal(data, &rawMsg); err != nil {
+		return err
+	}
+	for key, val := range rawMsg {
+		var err error
+		switch key {
+		case "properties":
+				err = unpopulate(val, &r.Properties)
+				delete(rawMsg, key)
+		case "systemData":
+				err = unpopulate(val, &r.SystemData)
+				delete(rawMsg, key)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	if err := r.TrackedResource.unmarshalInternal(rawMsg); err != nil {
+		return err
+	}
+	return nil
+}
+
+// RedisCacheResponseProperties - RedisCache connector properties
+type RedisCacheResponseProperties struct {
 	BasicResourceProperties
 	// REQUIRED; Fully qualified resource ID for the environment that the connector is linked to
 	Environment *string `json:"environment,omitempty"`
@@ -1470,9 +1726,6 @@ type RedisCacheProperties struct {
 	// Fully qualified resource ID of a supported resource with Redis API to use for this connector
 	Resource *string `json:"resource,omitempty"`
 
-	// The secret values for the given RedisCache resource
-	Secrets *RedisCacheSecrets `json:"secrets,omitempty"`
-
 	// READ-ONLY; Fully qualified resource ID for the application that the connector is consumed by
 	Application *string `json:"application,omitempty" azure:"ro"`
 
@@ -1480,9 +1733,23 @@ type RedisCacheProperties struct {
 	ProvisioningState *ProvisioningState `json:"provisioningState,omitempty" azure:"ro"`
 }
 
-// MarshalJSON implements the json.Marshaller interface for type RedisCacheProperties.
-func (r RedisCacheProperties) MarshalJSON() ([]byte, error) {
+// MarshalJSON implements the json.Marshaller interface for type RedisCacheResponseProperties.
+func (r RedisCacheResponseProperties) MarshalJSON() ([]byte, error) {
 	objectMap := make(map[string]interface{})
+	r.marshalInternal(objectMap)
+	return json.Marshal(objectMap)
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface for type RedisCacheResponseProperties.
+func (r *RedisCacheResponseProperties) UnmarshalJSON(data []byte) error {
+	var rawMsg map[string]json.RawMessage
+	if err := json.Unmarshal(data, &rawMsg); err != nil {
+		return err
+	}
+	return r.unmarshalInternal(rawMsg)
+}
+
+func (r RedisCacheResponseProperties) marshalInternal(objectMap map[string]interface{}) {
 	r.BasicResourceProperties.marshalInternal(objectMap)
 	populate(objectMap, "application", r.Application)
 	populate(objectMap, "environment", r.Environment)
@@ -1490,16 +1757,9 @@ func (r RedisCacheProperties) MarshalJSON() ([]byte, error) {
 	populate(objectMap, "port", r.Port)
 	populate(objectMap, "provisioningState", r.ProvisioningState)
 	populate(objectMap, "resource", r.Resource)
-	populate(objectMap, "secrets", r.Secrets)
-	return json.Marshal(objectMap)
 }
 
-// UnmarshalJSON implements the json.Unmarshaller interface for type RedisCacheProperties.
-func (r *RedisCacheProperties) UnmarshalJSON(data []byte) error {
-	var rawMsg map[string]json.RawMessage
-	if err := json.Unmarshal(data, &rawMsg); err != nil {
-		return err
-	}
+func (r *RedisCacheResponseProperties) unmarshalInternal(rawMsg map[string]json.RawMessage) error {
 	for key, val := range rawMsg {
 		var err error
 		switch key {
@@ -1521,9 +1781,6 @@ func (r *RedisCacheProperties) UnmarshalJSON(data []byte) error {
 		case "resource":
 				err = unpopulate(val, &r.Resource)
 				delete(rawMsg, key)
-		case "secrets":
-				err = unpopulate(val, &r.Secrets)
-				delete(rawMsg, key)
 		}
 		if err != nil {
 			return err
@@ -1535,18 +1792,18 @@ func (r *RedisCacheProperties) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
-// RedisCacheResource - RedisCache connector
-type RedisCacheResource struct {
+// RedisCacheResponseResource - RedisCache connector
+type RedisCacheResponseResource struct {
 	TrackedResource
 	// REQUIRED; RedisCache connector properties
-	Properties *RedisCacheProperties `json:"properties,omitempty"`
+	Properties *RedisCacheResponseProperties `json:"properties,omitempty"`
 
 	// READ-ONLY; Metadata pertaining to creation and last modification of the resource.
 	SystemData *SystemData `json:"systemData,omitempty" azure:"ro"`
 }
 
-// MarshalJSON implements the json.Marshaller interface for type RedisCacheResource.
-func (r RedisCacheResource) MarshalJSON() ([]byte, error) {
+// MarshalJSON implements the json.Marshaller interface for type RedisCacheResponseResource.
+func (r RedisCacheResponseResource) MarshalJSON() ([]byte, error) {
 	objectMap := make(map[string]interface{})
 	r.TrackedResource.marshalInternal(objectMap)
 	populate(objectMap, "properties", r.Properties)
@@ -1554,8 +1811,8 @@ func (r RedisCacheResource) MarshalJSON() ([]byte, error) {
 	return json.Marshal(objectMap)
 }
 
-// UnmarshalJSON implements the json.Unmarshaller interface for type RedisCacheResource.
-func (r *RedisCacheResource) UnmarshalJSON(data []byte) error {
+// UnmarshalJSON implements the json.Unmarshaller interface for type RedisCacheResponseResource.
+func (r *RedisCacheResponseResource) UnmarshalJSON(data []byte) error {
 	var rawMsg map[string]json.RawMessage
 	if err := json.Unmarshal(data, &rawMsg); err != nil {
 		return err
diff --git a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_mongodatabases_client.go b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_mongodatabases_client.go
index 48e0cd518..82e33d2c3 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_mongodatabases_client.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_mongodatabases_client.go
@@ -188,7 +188,7 @@ func (client *MongoDatabasesClient) getCreateRequest(ctx context.Context, mongoD
 // getHandleResponse handles the Get response.
 func (client *MongoDatabasesClient) getHandleResponse(resp *http.Response) (MongoDatabasesGetResponse, error) {
 	result := MongoDatabasesGetResponse{RawResponse: resp}
-	if err := runtime.UnmarshalAsJSON(resp, &result.MongoDatabaseResource); err != nil {
+	if err := runtime.UnmarshalAsJSON(resp, &result.MongoDatabaseResponseResource); err != nil {
 		return MongoDatabasesGetResponse{}, err
 	}
 	return result, nil
diff --git a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_rabbitmqmessagequeues_client.go b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_rabbitmqmessagequeues_client.go
index 5138ccb31..6e9aceece 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_rabbitmqmessagequeues_client.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_rabbitmqmessagequeues_client.go
@@ -188,7 +188,7 @@ func (client *RabbitMQMessageQueuesClient) getCreateRequest(ctx context.Context,
 // getHandleResponse handles the Get response.
 func (client *RabbitMQMessageQueuesClient) getHandleResponse(resp *http.Response) (RabbitMQMessageQueuesGetResponse, error) {
 	result := RabbitMQMessageQueuesGetResponse{RawResponse: resp}
-	if err := runtime.UnmarshalAsJSON(resp, &result.RabbitMQMessageQueueResource); err != nil {
+	if err := runtime.UnmarshalAsJSON(resp, &result.RabbitMQMessageQueueResponseResource); err != nil {
 		return RabbitMQMessageQueuesGetResponse{}, err
 	}
 	return result, nil
diff --git a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_rediscaches_client.go b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_rediscaches_client.go
index 53e7e5f9c..d3518fe8f 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_rediscaches_client.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_rediscaches_client.go
@@ -188,7 +188,7 @@ func (client *RedisCachesClient) getCreateRequest(ctx context.Context, redisCach
 // getHandleResponse handles the Get response.
 func (client *RedisCachesClient) getHandleResponse(resp *http.Response) (RedisCachesGetResponse, error) {
 	result := RedisCachesGetResponse{RawResponse: resp}
-	if err := runtime.UnmarshalAsJSON(resp, &result.RedisCacheResource); err != nil {
+	if err := runtime.UnmarshalAsJSON(resp, &result.RedisCacheResponseResource); err != nil {
 		return RedisCachesGetResponse{}, err
 	}
 	return result, nil
diff --git a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_response_types.go b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_response_types.go
index 8d272696f..8445082a0 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/zz_generated_response_types.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/zz_generated_response_types.go
@@ -220,6 +220,19 @@ type ExtendersListByRootScopeResult struct {
 	ExtenderList
 }
 
+// ExtendersListSecretsResponse contains the response from method Extenders.ListSecrets.
+type ExtendersListSecretsResponse struct {
+	ExtendersListSecretsResult
+	// RawResponse contains the underlying HTTP response.
+	RawResponse *http.Response
+}
+
+// ExtendersListSecretsResult contains the result from method Extenders.ListSecrets.
+type ExtendersListSecretsResult struct {
+	// The secret values for the given Extender resource
+	Value map[string]interface{}
+}
+
 // MongoDatabasesCreateOrUpdateResponse contains the response from method MongoDatabases.CreateOrUpdate.
 type MongoDatabasesCreateOrUpdateResponse struct {
 	MongoDatabasesCreateOrUpdateResult
@@ -247,7 +260,7 @@ type MongoDatabasesGetResponse struct {
 
 // MongoDatabasesGetResult contains the result from method MongoDatabases.Get.
 type MongoDatabasesGetResult struct {
-	MongoDatabaseResource
+	MongoDatabaseResponseResource
 }
 
 // MongoDatabasesListByRootScopeResponse contains the response from method MongoDatabases.ListByRootScope.
@@ -301,7 +314,7 @@ type RabbitMQMessageQueuesGetResponse struct {
 
 // RabbitMQMessageQueuesGetResult contains the result from method RabbitMQMessageQueues.Get.
 type RabbitMQMessageQueuesGetResult struct {
-	RabbitMQMessageQueueResource
+	RabbitMQMessageQueueResponseResource
 }
 
 // RabbitMQMessageQueuesListByRootScopeResponse contains the response from method RabbitMQMessageQueues.ListByRootScope.
@@ -355,7 +368,7 @@ type RedisCachesGetResponse struct {
 
 // RedisCachesGetResult contains the result from method RedisCaches.Get.
 type RedisCachesGetResult struct {
-	RedisCacheResource
+	RedisCacheResponseResource
 }
 
 // RedisCachesListByRootScopeResponse contains the response from method RedisCaches.ListByRootScope.
diff --git a/pkg/connectorrp/datamodel/converter/mongodatabase_converter.go b/pkg/connectorrp/datamodel/converter/mongodatabase_converter.go
index bac30b8bf..852092af9 100644
--- a/pkg/connectorrp/datamodel/converter/mongodatabase_converter.go
+++ b/pkg/connectorrp/datamodel/converter/mongodatabase_converter.go
@@ -15,13 +15,18 @@ import (
 )
 
 // MongoDatabaseDataModelFromVersioned converts version agnostic MongoDatabase datamodel to versioned model.
-func MongoDatabaseDataModelToVersioned(model *datamodel.MongoDatabase, version string) (conv.VersionedModelInterface, error) {
+func MongoDatabaseDataModelToVersioned(model conv.DataModelInterface, version string, includeSecrets bool) (conv.VersionedModelInterface, error) {
 	switch version {
 	case v20220315privatepreview.Version:
-		versioned := &v20220315privatepreview.MongoDatabaseResource{}
-		err := versioned.ConvertFrom(model)
-		return versioned, err
-
+		if includeSecrets {
+			versioned := &v20220315privatepreview.MongoDatabaseResource{}
+			err := versioned.ConvertFrom(model.(*datamodel.MongoDatabase))
+			return versioned, err
+		} else {
+			versioned := &v20220315privatepreview.MongoDatabaseResponseResource{}
+			err := versioned.ConvertFrom(model.(*datamodel.MongoDatabaseResponse))
+			return versioned, err
+		}
 	default:
 		return nil, v1.ErrUnsupportedAPIVersion
 	}
diff --git a/pkg/connectorrp/datamodel/converter/rabbitmq_converter.go b/pkg/connectorrp/datamodel/converter/rabbitmq_converter.go
index b1c25782b..7fab96e7e 100644
--- a/pkg/connectorrp/datamodel/converter/rabbitmq_converter.go
+++ b/pkg/connectorrp/datamodel/converter/rabbitmq_converter.go
@@ -15,13 +15,18 @@ import (
 )
 
 // RabbitMQMessageQueueDataModelFromVersioned converts version agnostic RabbitMQMessageQueue datamodel to versioned model.
-func RabbitMQMessageQueueDataModelToVersioned(model *datamodel.RabbitMQMessageQueue, version string) (conv.VersionedModelInterface, error) {
+func RabbitMQMessageQueueDataModelToVersioned(model conv.DataModelInterface, version string, includeSecrets bool) (conv.VersionedModelInterface, error) {
 	switch version {
 	case v20220315privatepreview.Version:
-		versioned := &v20220315privatepreview.RabbitMQMessageQueueResource{}
-		err := versioned.ConvertFrom(model)
-		return versioned, err
-
+		if includeSecrets {
+			versioned := &v20220315privatepreview.RabbitMQMessageQueueResource{}
+			err := versioned.ConvertFrom(model.(*datamodel.RabbitMQMessageQueue))
+			return versioned, err
+		} else {
+			versioned := &v20220315privatepreview.RabbitMQMessageQueueResponseResource{}
+			err := versioned.ConvertFrom(model.(*datamodel.RabbitMQMessageQueueResponse))
+			return versioned, err
+		}
 	default:
 		return nil, v1.ErrUnsupportedAPIVersion
 	}
diff --git a/pkg/connectorrp/datamodel/converter/rediscache_converter.go b/pkg/connectorrp/datamodel/converter/rediscache_converter.go
index 313b657ca..f2f321dfe 100644
--- a/pkg/connectorrp/datamodel/converter/rediscache_converter.go
+++ b/pkg/connectorrp/datamodel/converter/rediscache_converter.go
@@ -15,13 +15,18 @@ import (
 )
 
 // RedisCacheDataModelFromVersioned converts version agnostic RedisCache datamodel to versioned model.
-func RedisCacheDataModelToVersioned(model *datamodel.RedisCache, version string) (conv.VersionedModelInterface, error) {
+func RedisCacheDataModelToVersioned(model conv.DataModelInterface, version string, includeSecrets bool) (conv.VersionedModelInterface, error) {
 	switch version {
 	case v20220315privatepreview.Version:
-		versioned := &v20220315privatepreview.RedisCacheResource{}
-		err := versioned.ConvertFrom(model)
-		return versioned, err
-
+		if includeSecrets {
+			versioned := &v20220315privatepreview.RedisCacheResource{}
+			err := versioned.ConvertFrom(model.(*datamodel.RedisCache))
+			return versioned, err
+		} else {
+			versioned := &v20220315privatepreview.RedisCacheResponseResource{}
+			err := versioned.ConvertFrom(model.(*datamodel.RedisCacheResponse))
+			return versioned, err
+		}
 	default:
 		return nil, v1.ErrUnsupportedAPIVersion
 	}
diff --git a/pkg/connectorrp/datamodel/mongodatabase.go b/pkg/connectorrp/datamodel/mongodatabase.go
index ecf6e10db..455993f84 100644
--- a/pkg/connectorrp/datamodel/mongodatabase.go
+++ b/pkg/connectorrp/datamodel/mongodatabase.go
@@ -22,12 +22,28 @@ type MongoDatabase struct {
 	v1.InternalMetadata
 }
 
+type MongoDatabaseResponse struct {
+	v1.TrackedResource
+
+	// SystemData is the systemdata which includes creation/modified dates.
+	SystemData v1.SystemData `json:"systemData,omitempty"`
+	// Properties is the properties of the resource.
+	Properties MongoDatabaseResponseProperties `json:"properties"`
+
+	// InternalMetadata is the internal metadata which is used for conversion.
+	v1.InternalMetadata
+}
+
 func (mongo MongoDatabase) ResourceTypeName() string {
 	return "Applications.Connector/mongoDatabases"
 }
 
+func (mongo MongoDatabaseResponse) ResourceTypeName() string {
+	return "Applications.Connector/mongoDatabases"
+}
+
 // MongoDatabaseProperties represents the properties of MongoDatabase resource.
-type MongoDatabaseProperties struct {
+type MongoDatabaseResponseProperties struct {
 	v1.BasicResourceProperties
 	ProvisioningState v1.ProvisioningState `json:"provisioningState,omitempty"`
 	Environment       string               `json:"environment"`
@@ -35,7 +51,11 @@ type MongoDatabaseProperties struct {
 	Resource          string               `json:"resource,omitempty"`
 	Host              string               `json:"host,omitempty"`
 	Port              int32                `json:"port,omitempty"`
-	Secrets           MongoDatabaseSecrets `json:"secrets,omitempty"`
+}
+
+type MongoDatabaseProperties struct {
+	MongoDatabaseResponseProperties
+	Secrets MongoDatabaseSecrets `json:"secrets,omitempty"`
 }
 
 // Secrets values consisting of secrets provided for the resource
diff --git a/pkg/connectorrp/datamodel/rabbitmq.go b/pkg/connectorrp/datamodel/rabbitmq.go
index 29ab21267..dc179610e 100644
--- a/pkg/connectorrp/datamodel/rabbitmq.go
+++ b/pkg/connectorrp/datamodel/rabbitmq.go
@@ -22,18 +22,39 @@ type RabbitMQMessageQueue struct {
 	v1.InternalMetadata
 }
 
+type RabbitMQMessageQueueResponse struct {
+	v1.TrackedResource
+
+	// SystemData is the systemdata which includes creation/modified dates.
+	SystemData v1.SystemData `json:"systemData,omitempty"`
+	// Properties is the properties of the resource.
+	Properties RabbitMQMessageQueueResponseProperties `json:"properties"`
+
+	// InternalMetadata is the internal metadata which is used for conversion.
+	v1.InternalMetadata
+}
+
 func (rabbitmq RabbitMQMessageQueue) ResourceTypeName() string {
 	return "Applications.Connector/rabbitMQMessageQueues"
 }
 
-// RabbitMQMessageQueueProperties represents the properties of RabbitMQMessageQueue resource.
-type RabbitMQMessageQueueProperties struct {
+func (rabbitmq RabbitMQMessageQueueResponse) ResourceTypeName() string {
+	return "Applications.Connector/rabbitMQMessageQueues"
+}
+
+// RabbitMQMessageQueueProperties represents the properties of RabbitMQMessageQueue response resource.
+type RabbitMQMessageQueueResponseProperties struct {
 	v1.BasicResourceProperties
 	ProvisioningState v1.ProvisioningState `json:"provisioningState,omitempty"`
 	Environment       string               `json:"environment"`
 	Application       string               `json:"application,omitempty"`
 	Queue             string               `json:"queue"`
-	Secrets           RabbitMQSecrets      `json:"secrets,omitempty"`
+}
+
+// RabbitMQMessageQueueProperties represents the properties of RabbitMQMessageQueue resource.
+type RabbitMQMessageQueueProperties struct {
+	RabbitMQMessageQueueResponseProperties
+	Secrets RabbitMQSecrets `json:"secrets,omitempty"`
 }
 
 // Secrets values consisting of secrets provided for the resource
diff --git a/pkg/connectorrp/datamodel/rediscache.go b/pkg/connectorrp/datamodel/rediscache.go
index 6e31753bb..b8d275f52 100644
--- a/pkg/connectorrp/datamodel/rediscache.go
+++ b/pkg/connectorrp/datamodel/rediscache.go
@@ -22,12 +22,28 @@ type RedisCache struct {
 	v1.InternalMetadata
 }
 
+type RedisCacheResponse struct {
+	v1.TrackedResource
+
+	// SystemData is the systemdata which includes creation/modified dates.
+	SystemData v1.SystemData `json:"systemData,omitempty"`
+	// Properties is the properties of the response resource.
+	Properties RedisCacheResponseProperties `json:"properties"`
+
+	// InternalMetadata is the internal metadata which is used for conversion.
+	v1.InternalMetadata
+}
+
 func (redis RedisCache) ResourceTypeName() string {
 	return "Applications.Connector/redisCaches"
 }
 
+func (redis RedisCacheResponse) ResourceTypeName() string {
+	return "Applications.Connector/redisCaches"
+}
+
 // RedisCacheProperties represents the properties of RedisCache resource.
-type RedisCacheProperties struct {
+type RedisCacheResponseProperties struct {
 	v1.BasicResourceProperties
 	ProvisioningState v1.ProvisioningState `json:"provisioningState,omitempty"`
 	Environment       string               `json:"environment"`
@@ -35,7 +51,11 @@ type RedisCacheProperties struct {
 	Resource          string               `json:"resource,omitempty"`
 	Host              string               `json:"host,omitempty"`
 	Port              int32                `json:"port,omitempty"`
-	Secrets           RedisCacheSecrets    `json:"secrets,omitempty"`
+}
+
+type RedisCacheProperties struct {
+	RedisCacheResponseProperties
+	Secrets RedisCacheSecrets `json:"secrets,omitempty"`
 }
 
 // Secrets values consisting of secrets provided for the resource
diff --git a/pkg/connectorrp/frontend/controller/extenders/createorupdateextender.go b/pkg/connectorrp/frontend/controller/extenders/createorupdateextender.go
new file mode 100644
index 000000000..287544008
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/createorupdateextender.go
@@ -0,0 +1,99 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"errors"
+	"net/http"
+
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
+	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel/converter"
+	"github.com/project-radius/radius/pkg/radrp/rest"
+	"github.com/project-radius/radius/pkg/ucp/store"
+)
+
+var _ ctrl.Controller = (*CreateOrUpdateExtender)(nil)
+
+// CreateOrUpdateExtender is the controller implementation to create or update Extender connector resource.
+type CreateOrUpdateExtender struct {
+	ctrl.BaseController
+}
+
+// NewCreateOrUpdateExtender creates a new instance of CreateOrUpdateExtender.
+func NewCreateOrUpdateExtender(ds store.StorageClient, sm manager.StatusManager) (ctrl.Controller, error) {
+	return &CreateOrUpdateExtender{ctrl.NewBaseController(ds, sm)}, nil
+}
+
+// Run executes CreateOrUpdateExtender operation.
+func (extender *CreateOrUpdateExtender) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+	newResource, err := extender.Validate(ctx, req, serviceCtx.APIVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	// TODO Integrate with renderer/deployment processor to validate associated resource existence (if fromResource is defined)
+	// and store resource properties and secrets reference
+
+	// Read existing resource info from the data store
+	existingResource := &datamodel.Extender{}
+	etag, err := extender.GetResource(ctx, serviceCtx.ResourceID.String(), existingResource)
+	if req.Method == http.MethodPatch && err != nil && !errors.Is(&store.ErrNotFound{}, err) {
+		return nil, err
+	}
+
+	err = ctrl.ValidateETag(*serviceCtx, etag)
+	if err != nil {
+		return rest.NewPreconditionFailedResponse(serviceCtx.ResourceID.String(), err.Error()), nil
+	}
+
+	// Add system metadata to requested resource
+	newResource.SystemData = ctrl.UpdateSystemData(existingResource.SystemData, *serviceCtx.SystemData())
+	if existingResource.CreatedAPIVersion != "" {
+		newResource.CreatedAPIVersion = existingResource.CreatedAPIVersion
+	}
+	newResource.TenantID = serviceCtx.HomeTenantID
+
+	// Add/update resource in the data store
+	savedResource, err := extender.SaveResource(ctx, serviceCtx.ResourceID.String(), newResource, etag)
+	if err != nil {
+		return nil, err
+	}
+
+	versioned, err := converter.ExtenderDataModelToVersioned(newResource, serviceCtx.APIVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	headers := map[string]string{"ETag": savedResource.ETag}
+
+	return rest.NewOKResponseWithHeaders(versioned, headers), nil
+}
+
+// Validate extracts versioned resource from request and validates the properties.
+func (extender *CreateOrUpdateExtender) Validate(ctx context.Context, req *http.Request, apiVersion string) (*datamodel.Extender, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+	content, err := ctrl.ReadJSONBody(req)
+	if err != nil {
+		return nil, err
+	}
+
+	dm, err := converter.ExtenderDataModelFromVersioned(content, apiVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	dm.ID = serviceCtx.ResourceID.String()
+	dm.TrackedResource = ctrl.BuildTrackedResource(ctx)
+	dm.Properties.ProvisioningState = v1.ProvisioningStateSucceeded
+
+	return dm, nil
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/deleteextender.go b/pkg/connectorrp/frontend/controller/extenders/deleteextender.go
new file mode 100644
index 000000000..859580d06
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/deleteextender.go
@@ -0,0 +1,64 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"errors"
+	"net/http"
+
+	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
+	"github.com/project-radius/radius/pkg/radrp/rest"
+	"github.com/project-radius/radius/pkg/ucp/store"
+)
+
+var _ ctrl.Controller = (*DeleteExtender)(nil)
+
+// DeleteExtender is the controller implementation to delete extender connector resource.
+type DeleteExtender struct {
+	ctrl.BaseController
+}
+
+// NewDeleteExtender creates a new instance DeleteExtender.
+func NewDeleteExtender(ds store.StorageClient, sm manager.StatusManager) (ctrl.Controller, error) {
+	return &DeleteExtender{ctrl.NewBaseController(ds, sm)}, nil
+}
+
+func (extender *DeleteExtender) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+	// Read resource metadata from the storage
+	existingResource := &datamodel.Extender{}
+	etag, err := extender.GetResource(ctx, serviceCtx.ResourceID.String(), existingResource)
+	if err != nil {
+		if errors.Is(&store.ErrNotFound{}, err) {
+			return rest.NewNoContentResponse(), nil
+		}
+		return nil, err
+	}
+
+	if etag == "" {
+		return rest.NewNoContentResponse(), nil
+	}
+
+	err = ctrl.ValidateETag(*serviceCtx, etag)
+	if err != nil {
+		return rest.NewPreconditionFailedResponse(serviceCtx.ResourceID.String(), err.Error()), nil
+	}
+
+	err = extender.DataStore.Delete(ctx, serviceCtx.ResourceID.String())
+	if err != nil {
+		if errors.Is(&store.ErrNotFound{}, err) {
+			return rest.NewNoContentResponse(), nil
+		}
+		return nil, err
+	}
+
+	return rest.NewOKResponse(nil), nil
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/getextender.go b/pkg/connectorrp/frontend/controller/extenders/getextender.go
new file mode 100644
index 000000000..61ccc91a5
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/getextender.go
@@ -0,0 +1,48 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"errors"
+	"net/http"
+
+	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel/converter"
+	"github.com/project-radius/radius/pkg/radrp/rest"
+	"github.com/project-radius/radius/pkg/ucp/store"
+)
+
+var _ ctrl.Controller = (*GetExtender)(nil)
+
+// GetExtender is the controller implementation to get the extender conenctor resource.
+type GetExtender struct {
+	ctrl.BaseController
+}
+
+// NewGetExtender creates a new instance of GetExtender.
+func NewGetExtender(ds store.StorageClient, sm manager.StatusManager) (ctrl.Controller, error) {
+	return &GetExtender{ctrl.NewBaseController(ds, sm)}, nil
+}
+
+func (extender *GetExtender) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+	existingResource := &datamodel.Extender{}
+	_, err := extender.GetResource(ctx, serviceCtx.ResourceID.String(), existingResource)
+	if err != nil {
+		if errors.Is(&store.ErrNotFound{}, err) {
+			return rest.NewNotFoundResponse(serviceCtx.ResourceID), nil
+		}
+		return nil, err
+	}
+
+	versioned, _ := converter.ExtenderDataModelToVersioned(existingResource, serviceCtx.APIVersion)
+	return rest.NewOKResponse(versioned), nil
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/listextenders.go b/pkg/connectorrp/frontend/controller/extenders/listextenders.go
new file mode 100644
index 000000000..92c5d6a85
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/listextenders.go
@@ -0,0 +1,75 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"net/http"
+
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
+	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel/converter"
+
+	"github.com/project-radius/radius/pkg/radrp/rest"
+	"github.com/project-radius/radius/pkg/ucp/store"
+)
+
+var _ ctrl.Controller = (*ListExtenders)(nil)
+
+// ListExtenders is the controller implementation to get the list of extender connector resources in the resource group.
+type ListExtenders struct {
+	ctrl.BaseController
+}
+
+// NewListExtenders creates a new instance of ListExtenders.
+func NewListExtenders(ds store.StorageClient, sm manager.StatusManager) (ctrl.Controller, error) {
+	return &ListExtenders{ctrl.NewBaseController(ds, sm)}, nil
+}
+
+func (extender *ListExtenders) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+	query := store.Query{
+		RootScope:    serviceCtx.ResourceID.RootScope(),
+		ResourceType: serviceCtx.ResourceID.Type(),
+	}
+
+	result, err := extender.DataStore.Query(ctx, query, store.WithPaginationToken(serviceCtx.SkipToken), store.WithMaxQueryItemCount(serviceCtx.Top))
+	if err != nil {
+		return nil, err
+	}
+
+	paginatedList, err := extender.createPaginatedList(ctx, req, result)
+
+	return rest.NewOKResponse(paginatedList), err
+}
+
+func (extender *ListExtenders) createPaginatedList(ctx context.Context, req *http.Request, result *store.ObjectQueryResult) (*v1.PaginatedList, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+	items := []interface{}{}
+	for _, item := range result.Items {
+		dm := &datamodel.Extender{}
+		if err := item.As(dm); err != nil {
+			return nil, err
+		}
+
+		versioned, err := converter.ExtenderDataModelToVersioned(dm, serviceCtx.APIVersion)
+		if err != nil {
+			return nil, err
+		}
+
+		items = append(items, versioned)
+	}
+
+	return &v1.PaginatedList{
+		Value:    items,
+		NextLink: ctrl.GetNextLinkURL(ctx, req, result.PaginationToken),
+	}, nil
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/listsecretsextender.go b/pkg/connectorrp/frontend/controller/extenders/listsecretsextender.go
new file mode 100644
index 000000000..564bccd65
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/listsecretsextender.go
@@ -0,0 +1,54 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"errors"
+	"net/http"
+
+	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
+	"github.com/project-radius/radius/pkg/radrp/rest"
+	"github.com/project-radius/radius/pkg/ucp/store"
+)
+
+var _ ctrl.Controller = (*ListSecretsExtender)(nil)
+
+// ListSecretsExtender is the controller implementation to list secrets for the to access the connected extender resource resource id passed in the request body.
+type ListSecretsExtender struct {
+	ctrl.BaseController
+}
+
+// NewListSecretsExtender creates a new instance of ListSecretsExtender.
+func NewListSecretsExtender(ds store.StorageClient, sm manager.StatusManager) (ctrl.Controller, error) {
+	return &ListSecretsExtender{ctrl.NewBaseController(ds, sm)}, nil
+}
+
+// Run returns secrets values for the specified Extender resource
+func (ctrl *ListSecretsExtender) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
+	sCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+	resource := &datamodel.Extender{}
+	parsedResourceID := sCtx.ResourceID.Truncate()
+	_, err := ctrl.GetResource(ctx, parsedResourceID.String(), resource)
+	if err != nil {
+		if errors.Is(&store.ErrNotFound{}, err) {
+			return rest.NewNotFoundResponse(sCtx.ResourceID), nil
+		}
+		return nil, err
+	}
+
+	// TODO integrate with deploymentprocessor
+	// output, err := ctrl.JobEngine.FetchSecrets(ctx, sCtx.ResourceID, resource)
+	// if err != nil {
+	// 	return nil, err
+	// }
+
+	return rest.NewOKResponse(resource.Properties.Secrets), nil
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/types.go b/pkg/connectorrp/frontend/controller/extenders/types.go
new file mode 100644
index 000000000..fcb6c9c72
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/types.go
@@ -0,0 +1,13 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+const (
+	ResourceTypeName = "Applications.Connector/extenders"
+
+	// User defined operation names
+	OperationListSecret = "LISTSECRETS"
+)
diff --git a/pkg/connectorrp/frontend/controller/mongodatabases/createorupdatemongodatabase.go b/pkg/connectorrp/frontend/controller/mongodatabases/createorupdatemongodatabase.go
index 1a7121624..e7e925359 100644
--- a/pkg/connectorrp/frontend/controller/mongodatabases/createorupdatemongodatabase.go
+++ b/pkg/connectorrp/frontend/controller/mongodatabases/createorupdatemongodatabase.go
@@ -68,7 +68,7 @@ func (mongo *CreateOrUpdateMongoDatabase) Run(ctx context.Context, req *http.Req
 		return nil, err
 	}
 
-	versioned, err := converter.MongoDatabaseDataModelToVersioned(newResource, serviceCtx.APIVersion)
+	versioned, err := converter.MongoDatabaseDataModelToVersioned(newResource, serviceCtx.APIVersion, true)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/connectorrp/frontend/controller/mongodatabases/getmongodatabase.go b/pkg/connectorrp/frontend/controller/mongodatabases/getmongodatabase.go
index 57359f6aa..b6776fcbc 100644
--- a/pkg/connectorrp/frontend/controller/mongodatabases/getmongodatabase.go
+++ b/pkg/connectorrp/frontend/controller/mongodatabases/getmongodatabase.go
@@ -21,7 +21,7 @@ import (
 
 var _ ctrl.Controller = (*GetMongoDatabase)(nil)
 
-// GetMongoDatabase is the controller implementation to get the mongoDatabse conenctor resource.
+// GetMongoDatabase is the controller implementation to get the mongoDatabase conenctor resource.
 type GetMongoDatabase struct {
 	ctrl.BaseController
 }
@@ -34,7 +34,7 @@ func NewGetMongoDatabase(ds store.StorageClient, sm manager.StatusManager) (ctrl
 func (mongo *GetMongoDatabase) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
 	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
 
-	existingResource := &datamodel.MongoDatabase{}
+	existingResource := &datamodel.MongoDatabaseResponse{}
 	_, err := mongo.GetResource(ctx, serviceCtx.ResourceID.String(), existingResource)
 	if err != nil {
 		if errors.Is(&store.ErrNotFound{}, err) {
@@ -43,6 +43,6 @@ func (mongo *GetMongoDatabase) Run(ctx context.Context, req *http.Request) (rest
 		return nil, err
 	}
 
-	versioned, _ := converter.MongoDatabaseDataModelToVersioned(existingResource, serviceCtx.APIVersion)
+	versioned, _ := converter.MongoDatabaseDataModelToVersioned(existingResource, serviceCtx.APIVersion, false)
 	return rest.NewOKResponse(versioned), nil
 }
diff --git a/pkg/connectorrp/frontend/controller/mongodatabases/listmongodatabases.go b/pkg/connectorrp/frontend/controller/mongodatabases/listmongodatabases.go
index 6369667e9..784774df7 100644
--- a/pkg/connectorrp/frontend/controller/mongodatabases/listmongodatabases.go
+++ b/pkg/connectorrp/frontend/controller/mongodatabases/listmongodatabases.go
@@ -55,12 +55,12 @@ func (mongo *ListMongoDatabases) createPaginatedList(ctx context.Context, req *h
 
 	items := []interface{}{}
 	for _, item := range result.Items {
-		dm := &datamodel.MongoDatabase{}
+		dm := &datamodel.MongoDatabaseResponse{}
 		if err := item.As(dm); err != nil {
 			return nil, err
 		}
 
-		versioned, err := converter.MongoDatabaseDataModelToVersioned(dm, serviceCtx.APIVersion)
+		versioned, err := converter.MongoDatabaseDataModelToVersioned(dm, serviceCtx.APIVersion, false)
 		if err != nil {
 			return nil, err
 		}
diff --git a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/createorupdaterabbitmq.go b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/createorupdaterabbitmq.go
index 01908b45a..4290d4434 100644
--- a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/createorupdaterabbitmq.go
+++ b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/createorupdaterabbitmq.go
@@ -68,7 +68,7 @@ func (rabbitmq *CreateOrUpdateRabbitMQMessageQueue) Run(ctx context.Context, req
 		return nil, err
 	}
 
-	versioned, err := converter.RabbitMQMessageQueueDataModelToVersioned(newResource, serviceCtx.APIVersion)
+	versioned, err := converter.RabbitMQMessageQueueDataModelToVersioned(newResource, serviceCtx.APIVersion, true)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/getrabbitmq.go b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/getrabbitmq.go
index ad7402d91..e9f6ea361 100644
--- a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/getrabbitmq.go
+++ b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/getrabbitmq.go
@@ -34,7 +34,7 @@ func NewGetRabbitMQMessageQueue(ds store.StorageClient, sm manager.StatusManager
 func (rabbitmq *GetRabbitMQMessageQueue) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
 	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
 
-	existingResource := &datamodel.RabbitMQMessageQueue{}
+	existingResource := &datamodel.RabbitMQMessageQueueResponse{}
 	_, err := rabbitmq.GetResource(ctx, serviceCtx.ResourceID.String(), existingResource)
 	if err != nil {
 		if errors.Is(&store.ErrNotFound{}, err) {
@@ -43,6 +43,6 @@ func (rabbitmq *GetRabbitMQMessageQueue) Run(ctx context.Context, req *http.Requ
 		return nil, err
 	}
 
-	versioned, _ := converter.RabbitMQMessageQueueDataModelToVersioned(existingResource, serviceCtx.APIVersion)
+	versioned, _ := converter.RabbitMQMessageQueueDataModelToVersioned(existingResource, serviceCtx.APIVersion, false)
 	return rest.NewOKResponse(versioned), nil
 }
diff --git a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/listrabbitmqs.go b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/listrabbitmqs.go
index 14e302a5d..ae61f9216 100644
--- a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/listrabbitmqs.go
+++ b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/listrabbitmqs.go
@@ -55,12 +55,12 @@ func (rabbitmq *ListRabbitMQMessageQueues) createPaginatedList(ctx context.Conte
 
 	items := []interface{}{}
 	for _, item := range result.Items {
-		dm := &datamodel.RabbitMQMessageQueue{}
+		dm := &datamodel.RabbitMQMessageQueueResponse{}
 		if err := item.As(dm); err != nil {
 			return nil, err
 		}
 
-		versioned, err := converter.RabbitMQMessageQueueDataModelToVersioned(dm, serviceCtx.APIVersion)
+		versioned, err := converter.RabbitMQMessageQueueDataModelToVersioned(dm, serviceCtx.APIVersion, false)
 		if err != nil {
 			return nil, err
 		}
diff --git a/pkg/connectorrp/frontend/controller/rediscaches/createorupdaterediscache.go b/pkg/connectorrp/frontend/controller/rediscaches/createorupdaterediscache.go
index c271d119d..d194bcc6d 100644
--- a/pkg/connectorrp/frontend/controller/rediscaches/createorupdaterediscache.go
+++ b/pkg/connectorrp/frontend/controller/rediscaches/createorupdaterediscache.go
@@ -68,7 +68,7 @@ func (redis *CreateOrUpdateRedisCache) Run(ctx context.Context, req *http.Reques
 		return nil, err
 	}
 
-	versioned, err := converter.RedisCacheDataModelToVersioned(newResource, serviceCtx.APIVersion)
+	versioned, err := converter.RedisCacheDataModelToVersioned(newResource, serviceCtx.APIVersion, true)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/connectorrp/frontend/controller/rediscaches/getrediscache.go b/pkg/connectorrp/frontend/controller/rediscaches/getrediscache.go
index c963bbcd7..6ef2a58a3 100644
--- a/pkg/connectorrp/frontend/controller/rediscaches/getrediscache.go
+++ b/pkg/connectorrp/frontend/controller/rediscaches/getrediscache.go
@@ -34,7 +34,7 @@ func NewGetRedisCache(ds store.StorageClient, sm manager.StatusManager) (ctrl.Co
 func (redis *GetRedisCache) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
 	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
 
-	existingResource := &datamodel.RedisCache{}
+	existingResource := &datamodel.RedisCacheResponse{}
 	_, err := redis.GetResource(ctx, serviceCtx.ResourceID.String(), existingResource)
 	if err != nil {
 		if errors.Is(&store.ErrNotFound{}, err) {
@@ -43,6 +43,6 @@ func (redis *GetRedisCache) Run(ctx context.Context, req *http.Request) (rest.Re
 		return nil, err
 	}
 
-	versioned, _ := converter.RedisCacheDataModelToVersioned(existingResource, serviceCtx.APIVersion)
+	versioned, _ := converter.RedisCacheDataModelToVersioned(existingResource, serviceCtx.APIVersion, false)
 	return rest.NewOKResponse(versioned), nil
 }
diff --git a/pkg/connectorrp/frontend/controller/rediscaches/listrediscaches.go b/pkg/connectorrp/frontend/controller/rediscaches/listrediscaches.go
index efff2acc6..616703483 100644
--- a/pkg/connectorrp/frontend/controller/rediscaches/listrediscaches.go
+++ b/pkg/connectorrp/frontend/controller/rediscaches/listrediscaches.go
@@ -55,12 +55,12 @@ func (redis *ListRedisCaches) createPaginatedList(ctx context.Context, req *http
 
 	items := []interface{}{}
 	for _, item := range result.Items {
-		dm := &datamodel.RedisCache{}
+		dm := &datamodel.RedisCacheResponse{}
 		if err := item.As(dm); err != nil {
 			return nil, err
 		}
 
-		versioned, err := converter.RedisCacheDataModelToVersioned(dm, serviceCtx.APIVersion)
+		versioned, err := converter.RedisCacheDataModelToVersioned(dm, serviceCtx.APIVersion, false)
 		if err != nil {
 			return nil, err
 		}
diff --git a/pkg/connectorrp/frontend/handler/getoperations.go b/pkg/connectorrp/frontend/handler/getoperations.go
index 21aeb640d..f338ec491 100644
--- a/pkg/connectorrp/frontend/handler/getoperations.go
+++ b/pkg/connectorrp/frontend/handler/getoperations.go
@@ -86,6 +86,16 @@ func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList {
 				},
 				IsDataAction: false,
 			},
+			&v1.Operation{
+				Name: "Applications.Connector/mongoDatabases/listsecrets/action",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "mongoDatabases",
+					Operation:   "List secrets",
+					Description: "Lists mongoDatabase secrets.",
+				},
+				IsDataAction: false,
+			},
 			&v1.Operation{
 				Name: "Applications.Connector/register/action",
 				Display: &v1.OperationDisplayProperties{
@@ -166,6 +176,16 @@ func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList {
 				},
 				IsDataAction: false,
 			},
+			&v1.Operation{
+				Name: "Applications.Connector/redisCaches/listsecrets/action",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "redisCaches",
+					Operation:   "List secrets",
+					Description: "Lists redisCache secrets.",
+				},
+				IsDataAction: false,
+			},
 			&v1.Operation{
 				Name: "Applications.Connector/rabbitMQMessageQueues/read",
 				Display: &v1.OperationDisplayProperties{
@@ -196,6 +216,56 @@ func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList {
 				},
 				IsDataAction: false,
 			},
+			&v1.Operation{
+				Name: "Applications.Connector/rabbitMQMessageQueues/listsecrets/action",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "rabbitMQMessageQueues",
+					Operation:   "List secrets",
+					Description: "Lists rabbitMQMessageQueue secrets.",
+				},
+				IsDataAction: false,
+			},
+			&v1.Operation{
+				Name: "Applications.Connector/extenders/read",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "extenders",
+					Operation:   "Get/List extenders",
+					Description: "Gets/Lists extender connector(s).",
+				},
+				IsDataAction: false,
+			},
+			&v1.Operation{
+				Name: "Applications.Connector/extenders/write",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "extenders",
+					Operation:   "Create/Update extenders",
+					Description: "Creates or updates a extender connector.",
+				},
+				IsDataAction: false,
+			},
+			&v1.Operation{
+				Name: "Applications.Connector/extenders/delete",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "extenders",
+					Operation:   "Delete extender",
+					Description: "Deletes a extender connector.",
+				},
+				IsDataAction: false,
+			},
+			&v1.Operation{
+				Name: "Applications.Connector/extenders/listsecrets/action",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "extenders",
+					Operation:   "List secrets",
+					Description: "Lists extender secrets.",
+				},
+				IsDataAction: false,
+			},
 			&v1.Operation{
 				Name: "Applications.Connector/daprInvokeHttpRoutes/read",
 				Display: &v1.OperationDisplayProperties{
diff --git a/pkg/connectorrp/frontend/handler/routes.go b/pkg/connectorrp/frontend/handler/routes.go
index 8a584305f..ce9124c8c 100644
--- a/pkg/connectorrp/frontend/handler/routes.go
+++ b/pkg/connectorrp/frontend/handler/routes.go
@@ -13,11 +13,14 @@ import (
 	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
 	"github.com/project-radius/radius/pkg/armrpc/frontend/server"
 	"github.com/project-radius/radius/pkg/ucp/dataprovider"
+	"github.com/project-radius/radius/pkg/validator"
+	"github.com/project-radius/radius/swagger"
 
 	daprHttpRoute_ctrl "github.com/project-radius/radius/pkg/connectorrp/frontend/controller/daprinvokehttproutes"
 	daprPubSub_ctrl "github.com/project-radius/radius/pkg/connectorrp/frontend/controller/daprpubsubbrokers"
 	daprSecretStore_ctrl "github.com/project-radius/radius/pkg/connectorrp/frontend/controller/daprsecretstores"
 	daprStateStore_ctrl "github.com/project-radius/radius/pkg/connectorrp/frontend/controller/daprstatestores"
+	extender_ctrl "github.com/project-radius/radius/pkg/connectorrp/frontend/controller/extenders"
 	mongo_ctrl "github.com/project-radius/radius/pkg/connectorrp/frontend/controller/mongodatabases"
 	rabbitmq_ctrl "github.com/project-radius/radius/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues"
 	redis_ctrl "github.com/project-radius/radius/pkg/connectorrp/frontend/controller/rediscaches"
@@ -31,7 +34,10 @@ const (
 func AddRoutes(ctx context.Context, sp dataprovider.DataStorageProvider, sm manager.StatusManager, router *mux.Router, pathBase string, isARM bool) error {
 	if isARM {
 		pathBase += "/subscriptions/{subscriptionID}"
+	} else {
+		pathBase += "/planes/radius/{planeName}"
 	}
+	resourceGroupPath := "/resourcegroups/{resourceGroupName}"
 
 	// Configure the default ARM handlers.
 	err := server.ConfigureDefaultHandlers(ctx, sp, sm, router, pathBase, isARM, ProviderNamespaceName, NewGetOperations)
@@ -39,37 +45,41 @@ func AddRoutes(ctx context.Context, sp dataprovider.DataStorageProvider, sm mana
 		return err
 	}
 
-	mongoRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.connector/mongodatabases").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	mongoResourceRouter := mongoRTSubrouter.PathPrefix("/{mongoDatabases}").Subrouter()
+	specLoader, err := validator.LoadSpec(ctx, ProviderNamespaceName, swagger.SpecFiles, pathBase+resourceGroupPath)
+	if err != nil {
+		return err
+	}
+
+	rootScopeRouter := router.PathPrefix(pathBase + resourceGroupPath).Subrouter()
+	rootScopeRouter.Use(validator.APIValidator(specLoader))
+
+	mongoRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/mongodatabases").Subrouter()
+	mongoResourceRouter := mongoRTSubrouter.PathPrefix("/{mongoDatabaseName}").Subrouter()
+
+	daprHttpRouteRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/daprinvokehttproutes").Subrouter()
+	daprHttpRouteResourceRouter := daprHttpRouteRTSubrouter.PathPrefix("/{daprInvokeHttpRouteName}").Subrouter()
 
-	daprHttpRouteRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.connector/daprinvokehttproutes").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	daprHttpRouteResourceRouter := daprHttpRouteRTSubrouter.PathPrefix("/{daprInvokeHttpRoutes}").Subrouter()
+	daprPubSubRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/daprpubsubbrokers").Subrouter()
+	daprPubSubResourceRouter := daprPubSubRTSubrouter.PathPrefix("/{daprPubSubBrokerName}").Subrouter()
 
-	daprPubSubRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.connector/daprpubsubbrokers").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	daprPubSubResourceRouter := daprPubSubRTSubrouter.PathPrefix("/{daprPubSubBrokers}").Subrouter()
+	daprSecretStoreRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/daprsecretstores").Subrouter()
+	daprSecretStoreResourceRouter := daprSecretStoreRTSubrouter.PathPrefix("/{daprSecretStoreName}").Subrouter()
 
-	daprSecretStoreRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.connector/daprsecretstores").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	daprSecretStoreResourceRouter := daprSecretStoreRTSubrouter.PathPrefix("/{daprSecretStores}").Subrouter()
+	daprStateStoreRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/daprstatestores").Subrouter()
+	daprStateStoreResourceRouter := daprStateStoreRTSubrouter.PathPrefix("/{daprStateStoreName}").Subrouter()
 
-	daprStateStoreRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.connector/daprstatestores").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	daprStateStoreResourceRouter := daprStateStoreRTSubrouter.PathPrefix("/{daprStateStores}").Subrouter()
+	extenderRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/extenders").Subrouter()
+	extenderResourceRouter := extenderRTSubrouter.PathPrefix("/{extenderName}").Subrouter()
 
-	redisRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.connector/rediscaches").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	redisResourceRouter := redisRTSubrouter.PathPrefix("/{redisDatabases}").Subrouter()
+	redisRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/rediscaches").Subrouter()
+	redisResourceRouter := redisRTSubrouter.PathPrefix("/{redisCacheName}").Subrouter()
 
-	rabbitmqRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.connector/rabbitmqmessagequeues").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	rabbitmqResourceRouter := rabbitmqRTSubrouter.PathPrefix("/{rabbitmqmessagequeues}").Subrouter()
+	rabbitmqRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/rabbitmqmessagequeues").Subrouter()
+	rabbitmqResourceRouter := rabbitmqRTSubrouter.PathPrefix("/{rabbitMQMessageQueueName}").Subrouter()
+
+	sqlRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.connector/sqldatabases").Subrouter()
+	sqlResourceRouter := sqlRTSubrouter.PathPrefix("/{sqlDatabaseName}").Subrouter()
 
-	sqlRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.connector/sqldatabases").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	sqlResourceRouter := sqlRTSubrouter.PathPrefix("/{sqlDatabases}").Subrouter()
 	handlerOptions := []server.HandlerOptions{
 		{
 			ParentRouter:   mongoRTSubrouter,
@@ -328,6 +338,42 @@ func AddRoutes(ctx context.Context, sp dataprovider.DataStorageProvider, sm mana
 			Method:         v1.OperationDelete,
 			HandlerFactory: sql_ctrl.NewDeleteSqlDatabase,
 		},
+		{
+			ParentRouter:   extenderRTSubrouter,
+			ResourceType:   extender_ctrl.ResourceTypeName,
+			Method:         v1.OperationList,
+			HandlerFactory: extender_ctrl.NewListExtenders,
+		},
+		{
+			ParentRouter:   extenderResourceRouter,
+			ResourceType:   extender_ctrl.ResourceTypeName,
+			Method:         v1.OperationGet,
+			HandlerFactory: extender_ctrl.NewGetExtender,
+		},
+		{
+			ParentRouter:   extenderResourceRouter,
+			ResourceType:   extender_ctrl.ResourceTypeName,
+			Method:         v1.OperationPut,
+			HandlerFactory: extender_ctrl.NewCreateOrUpdateExtender,
+		},
+		{
+			ParentRouter:   extenderResourceRouter,
+			ResourceType:   extender_ctrl.ResourceTypeName,
+			Method:         v1.OperationPatch,
+			HandlerFactory: extender_ctrl.NewCreateOrUpdateExtender,
+		},
+		{
+			ParentRouter:   extenderResourceRouter,
+			ResourceType:   extender_ctrl.ResourceTypeName,
+			Method:         v1.OperationDelete,
+			HandlerFactory: extender_ctrl.NewDeleteExtender,
+		},
+		{
+			ParentRouter:   extenderResourceRouter.PathPrefix("/listsecrets").Subrouter(),
+			ResourceType:   extender_ctrl.ResourceTypeName,
+			Method:         extender_ctrl.OperationListSecret,
+			HandlerFactory: extender_ctrl.NewListSecretsExtender,
+		},
 	}
 
 	for _, h := range handlerOptions {
diff --git a/pkg/connectorrp/renderers/mock_secretvalueclient.go b/pkg/connectorrp/renderers/mock_secretvalueclient.go
new file mode 100644
index 000000000..05436a9be
--- /dev/null
+++ b/pkg/connectorrp/renderers/mock_secretvalueclient.go
@@ -0,0 +1,51 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/project-radius/radius/pkg/renderers (interfaces: SecretValueClient)
+
+// Package renderers is a generated GoMock package.
+package renderers
+
+import (
+	context "context"
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	resourcemodel "github.com/project-radius/radius/pkg/resourcemodel"
+)
+
+// MockSecretValueClient is a mock of SecretValueClient interface.
+type MockSecretValueClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockSecretValueClientMockRecorder
+}
+
+// MockSecretValueClientMockRecorder is the mock recorder for MockSecretValueClient.
+type MockSecretValueClientMockRecorder struct {
+	mock *MockSecretValueClient
+}
+
+// NewMockSecretValueClient creates a new mock instance.
+func NewMockSecretValueClient(ctrl *gomock.Controller) *MockSecretValueClient {
+	mock := &MockSecretValueClient{ctrl: ctrl}
+	mock.recorder = &MockSecretValueClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockSecretValueClient) EXPECT() *MockSecretValueClientMockRecorder {
+	return m.recorder
+}
+
+// FetchSecret mocks base method.
+func (m *MockSecretValueClient) FetchSecret(arg0 context.Context, arg1 resourcemodel.ResourceIdentity, arg2, arg3 string) (interface{}, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "FetchSecret", arg0, arg1, arg2, arg3)
+	ret0, _ := ret[0].(interface{})
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// FetchSecret indicates an expected call of FetchSecret.
+func (mr *MockSecretValueClientMockRecorder) FetchSecret(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchSecret", reflect.TypeOf((*MockSecretValueClient)(nil).FetchSecret), arg0, arg1, arg2, arg3)
+}
diff --git a/pkg/corerp/frontend/controller/containers/createorupdatecontainer.go b/pkg/corerp/frontend/controller/containers/createorupdatecontainer.go
index 10be00db2..b72382c4f 100644
--- a/pkg/corerp/frontend/controller/containers/createorupdatecontainer.go
+++ b/pkg/corerp/frontend/controller/containers/createorupdatecontainer.go
@@ -17,6 +17,7 @@ import (
 	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
 	"github.com/project-radius/radius/pkg/corerp/datamodel"
 	"github.com/project-radius/radius/pkg/corerp/datamodel/converter"
+	"github.com/project-radius/radius/pkg/corerp/frontend/controller"
 	"github.com/project-radius/radius/pkg/radrp/rest"
 	"github.com/project-radius/radius/pkg/ucp/store"
 )
@@ -63,7 +64,7 @@ func (e *CreateOrUpdateContainer) Run(ctx context.Context, req *http.Request) (r
 	}
 
 	if exists && !existingResource.Properties.ProvisioningState.IsTerminal() {
-		return rest.NewConflictResponse(OngoingAsyncOperationOnResourceMessage), nil
+		return rest.NewConflictResponse(controller.OngoingAsyncOperationOnResourceMessage), nil
 	}
 
 	err = ctrl.ValidateETag(*serviceCtx, etag)
diff --git a/pkg/corerp/frontend/controller/containers/deletecontainer.go b/pkg/corerp/frontend/controller/containers/deletecontainer.go
index 98d17204d..1180afbd5 100644
--- a/pkg/corerp/frontend/controller/containers/deletecontainer.go
+++ b/pkg/corerp/frontend/controller/containers/deletecontainer.go
@@ -16,6 +16,7 @@ import (
 	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
 	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
 	"github.com/project-radius/radius/pkg/corerp/datamodel"
+	"github.com/project-radius/radius/pkg/corerp/frontend/controller"
 	"github.com/project-radius/radius/pkg/radrp/rest"
 	"github.com/project-radius/radius/pkg/ucp/store"
 )
@@ -51,7 +52,7 @@ func (dc *DeleteContainer) Run(ctx context.Context, req *http.Request) (rest.Res
 	}
 
 	if !existingContainer.Properties.ProvisioningState.IsTerminal() {
-		return rest.NewConflictResponse(OngoingAsyncOperationOnResourceMessage), nil
+		return rest.NewConflictResponse(controller.OngoingAsyncOperationOnResourceMessage), nil
 	}
 
 	err = ctrl.ValidateETag(*serviceCtx, etag)
diff --git a/pkg/corerp/frontend/controller/containers/types.go b/pkg/corerp/frontend/controller/containers/types.go
index ffba8f44c..a9415c4b8 100644
--- a/pkg/corerp/frontend/controller/containers/types.go
+++ b/pkg/corerp/frontend/controller/containers/types.go
@@ -7,6 +7,4 @@ package containers
 
 const (
 	ResourceTypeName = "Applications.Core/containers"
-
-	OngoingAsyncOperationOnResourceMessage = "the source or target resource group is locked (e.g. move already in progress, resource group is being deleted)"
 )
diff --git a/pkg/corerp/frontend/controller/gateway/createorupdategateway.go b/pkg/corerp/frontend/controller/gateway/createorupdategateway.go
new file mode 100644
index 000000000..db4401571
--- /dev/null
+++ b/pkg/corerp/frontend/controller/gateway/createorupdategateway.go
@@ -0,0 +1,127 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package gateway
+
+import (
+	"context"
+	"errors"
+	"net/http"
+	"time"
+
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
+	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
+	"github.com/project-radius/radius/pkg/corerp/datamodel"
+	"github.com/project-radius/radius/pkg/corerp/datamodel/converter"
+	"github.com/project-radius/radius/pkg/corerp/frontend/controller"
+	"github.com/project-radius/radius/pkg/radrp/rest"
+	"github.com/project-radius/radius/pkg/ucp/store"
+)
+
+var _ ctrl.Controller = (*CreateOrUpdateGateway)(nil)
+
+// AsyncPutGatewayOperationTimeout is the default timeout duration of async put gateway operation.
+var AsyncPutGatewayOperationTimeout = time.Duration(120) * time.Second
+
+// CreateOrUpdateGateway is the controller implementation to create or update a gateway resource.
+type CreateOrUpdateGateway struct {
+	ctrl.BaseController
+}
+
+// NewCreateOrUpdateGateway creates a new CreateOrUpdateGateway.
+func NewCreateOrUpdateGateway(ds store.StorageClient, sm manager.StatusManager) (ctrl.Controller, error) {
+	return &CreateOrUpdateGateway{ctrl.NewBaseController(ds, sm)}, nil
+}
+
+// Run executes CreateOrUpdateGateway operation.
+func (e *CreateOrUpdateGateway) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+	newResource, err := e.Validate(ctx, req, serviceCtx.APIVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	existingResource := &datamodel.Gateway{}
+	etag, err := e.GetResource(ctx, serviceCtx.ResourceID.String(), existingResource)
+	if err != nil && !errors.Is(&store.ErrNotFound{}, err) {
+		return nil, err
+	}
+
+	exists := true
+	if err != nil && errors.Is(&store.ErrNotFound{}, err) {
+		exists = false
+	}
+
+	if req.Method == http.MethodPatch && !exists {
+		return rest.NewNotFoundResponse(serviceCtx.ResourceID), nil
+	}
+
+	if exists && !existingResource.Properties.ProvisioningState.IsTerminal() {
+		return rest.NewConflictResponse(controller.OngoingAsyncOperationOnResourceMessage), nil
+	}
+
+	err = ctrl.ValidateETag(*serviceCtx, etag)
+	if err != nil {
+		return rest.NewPreconditionFailedResponse(serviceCtx.ResourceID.String(), err.Error()), nil
+	}
+
+	enrichMetadata(serviceCtx, existingResource, newResource)
+
+	obj, err := e.SaveResource(ctx, serviceCtx.ResourceID.String(), newResource, etag)
+	if err != nil {
+		return nil, err
+	}
+
+	err = e.AsyncOperation.QueueAsyncOperation(ctx, serviceCtx, AsyncPutGatewayOperationTimeout)
+	if err != nil {
+		newResource.Properties.ProvisioningState = v1.ProvisioningStateFailed
+		_, rbErr := e.SaveResource(ctx, serviceCtx.ResourceID.String(), newResource, obj.ETag)
+		if rbErr != nil {
+			return nil, rbErr
+		}
+		return nil, err
+	}
+
+	respCode := http.StatusCreated
+	if req.Method == http.MethodPatch {
+		respCode = http.StatusAccepted
+	}
+
+	return rest.NewAsyncOperationResponse(newResource, newResource.TrackedResource.Location, respCode, serviceCtx.ResourceID, serviceCtx.OperationID), nil
+
+}
+
+// Validate extracts versioned resource from request and validate the properties.
+func (e *CreateOrUpdateGateway) Validate(ctx context.Context, req *http.Request, apiVersion string) (*datamodel.Gateway, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+	content, err := ctrl.ReadJSONBody(req)
+	if err != nil {
+		return nil, err
+	}
+
+	dm, err := converter.GatewayDataModelFromVersioned(content, apiVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	dm.ID = serviceCtx.ResourceID.String()
+	dm.TrackedResource = ctrl.BuildTrackedResource(ctx)
+
+	return dm, err
+}
+
+// updateExistingResourceData updates the gateway resource before it is saved to the DB.
+func enrichMetadata(serviceCtx *servicecontext.ARMRequestContext, er *datamodel.Gateway, nr *datamodel.Gateway) {
+	nr.SystemData = ctrl.UpdateSystemData(er.SystemData, *serviceCtx.SystemData())
+	if er.InternalMetadata.CreatedAPIVersion != "" {
+		nr.InternalMetadata.CreatedAPIVersion = er.InternalMetadata.CreatedAPIVersion
+	}
+	nr.InternalMetadata.TenantID = serviceCtx.HomeTenantID
+	nr.Properties.ProvisioningState = v1.ProvisioningStateAccepted
+}
diff --git a/pkg/corerp/frontend/controller/gateway/deletegateway.go b/pkg/corerp/frontend/controller/gateway/deletegateway.go
new file mode 100644
index 000000000..911d3dbb3
--- /dev/null
+++ b/pkg/corerp/frontend/controller/gateway/deletegateway.go
@@ -0,0 +1,77 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package gateway
+
+import (
+	"context"
+	"errors"
+	"net/http"
+	"time"
+
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
+	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
+	"github.com/project-radius/radius/pkg/corerp/datamodel"
+	"github.com/project-radius/radius/pkg/corerp/frontend/controller"
+	"github.com/project-radius/radius/pkg/radrp/rest"
+	"github.com/project-radius/radius/pkg/ucp/store"
+)
+
+var _ ctrl.Controller = (*DeleteGateway)(nil)
+
+var (
+	// AsyncDeleteGatewayOperationTimeout is the default timeout duration of async delete gateway operation.
+	AsyncDeleteGatewayOperationTimeout = time.Duration(120) * time.Second
+)
+
+// DeleteGateway is the controller implementation to delete gateway resource.
+type DeleteGateway struct {
+	ctrl.BaseController
+}
+
+// NewDeleteGateway creates a new DeleteGateway.
+func NewDeleteGateway(ds store.StorageClient, sm manager.StatusManager) (ctrl.Controller, error) {
+	return &DeleteGateway{ctrl.NewBaseController(ds, sm)}, nil
+}
+
+func (dc *DeleteGateway) Run(ctx context.Context, req *http.Request) (rest.Response, error) {
+	serviceCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+	existingGateway := &datamodel.Gateway{}
+	etag, err := dc.GetResource(ctx, serviceCtx.ResourceID.String(), existingGateway)
+	if err != nil && !errors.Is(&store.ErrNotFound{}, err) {
+		return nil, err
+	}
+
+	if err != nil && errors.Is(&store.ErrNotFound{}, err) {
+		return rest.NewNoContentResponse(), nil
+	}
+
+	if !existingGateway.Properties.ProvisioningState.IsTerminal() {
+		return rest.NewConflictResponse(controller.OngoingAsyncOperationOnResourceMessage), nil
+	}
+
+	err = ctrl.ValidateETag(*serviceCtx, etag)
+	if err != nil {
+		return rest.NewPreconditionFailedResponse(serviceCtx.ResourceID.String(), err.Error()), nil
+	}
+
+	err = dc.AsyncOperation.QueueAsyncOperation(ctx, serviceCtx, AsyncDeleteGatewayOperationTimeout)
+	if err != nil {
+		existingGateway.Properties.ProvisioningState = v1.ProvisioningStateFailed
+		_, rbErr := dc.SaveResource(ctx, serviceCtx.ResourceID.String(), existingGateway, etag)
+		if rbErr != nil {
+			return nil, rbErr
+		}
+		return nil, err
+	}
+
+	existingGateway.Properties.ProvisioningState = v1.ProvisioningStateDeleting
+
+	return rest.NewAsyncOperationResponse(existingGateway, existingGateway.TrackedResource.Location, http.StatusAccepted,
+		serviceCtx.ResourceID, serviceCtx.OperationID), nil
+}
diff --git a/pkg/corerp/frontend/controller/httproutes/createorupdatehttproute.go b/pkg/corerp/frontend/controller/httproutes/createorupdatehttproute.go
index 6c4bfa05c..5c7e601f0 100644
--- a/pkg/corerp/frontend/controller/httproutes/createorupdatehttproute.go
+++ b/pkg/corerp/frontend/controller/httproutes/createorupdatehttproute.go
@@ -9,6 +9,7 @@ import (
 	"context"
 	"errors"
 	"net/http"
+	"time"
 
 	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
@@ -16,11 +17,17 @@ import (
 	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
 	"github.com/project-radius/radius/pkg/corerp/datamodel"
 	"github.com/project-radius/radius/pkg/corerp/datamodel/converter"
+	"github.com/project-radius/radius/pkg/corerp/frontend/controller"
 	"github.com/project-radius/radius/pkg/radrp/rest"
 	"github.com/project-radius/radius/pkg/ucp/store"
 )
 
-var _ ctrl.Controller = (*CreateOrUpdateHTTPRoute)(nil)
+var (
+	_ ctrl.Controller = (*CreateOrUpdateHTTPRoute)(nil)
+
+	// AsyncPutHTTPRouteOperationTimeout is the default timeout duration of async put httproute operation.
+	AsyncPutHTTPRouteOperationTimeout = time.Duration(120) * time.Second
+)
 
 // CreateOrUpdateHTTPRoute is the controller implementation to create or update HTTPRoute resource.
 type CreateOrUpdateHTTPRoute struct {
@@ -42,11 +49,21 @@ func (e *CreateOrUpdateHTTPRoute) Run(ctx context.Context, req *http.Request) (r
 
 	existingResource := &datamodel.HTTPRoute{}
 	etag, err := e.GetResource(ctx, serviceCtx.ResourceID.String(), existingResource)
-	if req.Method == http.MethodPatch && errors.Is(&store.ErrNotFound{}, err) {
-		return rest.NewNotFoundResponse(serviceCtx.ResourceID), nil
-	}
 	if err != nil && !errors.Is(&store.ErrNotFound{}, err) {
 		return nil, err
+
+	}
+	exists := true
+	if err != nil && errors.Is(&store.ErrNotFound{}, err) {
+		exists = false
+	}
+
+	if req.Method == http.MethodPatch && !exists {
+		return rest.NewNotFoundResponse(serviceCtx.ResourceID), nil
+	}
+
+	if exists && !existingResource.Properties.ProvisioningState.IsTerminal() {
+		return rest.NewConflictResponse(controller.OngoingAsyncOperationOnResourceMessage), nil
 	}
 
 	err = ctrl.ValidateETag(*serviceCtx, etag)
@@ -54,21 +71,29 @@ func (e *CreateOrUpdateHTTPRoute) Run(ctx context.Context, req *http.Request) (r
 		return rest.NewPreconditionFailedResponse(serviceCtx.ResourceID.String(), err.Error()), nil
 	}
 
-	UpdateExistingResourceData(ctx, existingResource, newResource)
+	enrichMetadata(ctx, existingResource, newResource)
 
 	nr, err := e.SaveResource(ctx, serviceCtx.ResourceID.String(), newResource, etag)
 	if err != nil {
 		return nil, err
 	}
 
-	versioned, err := converter.HTTPRouteDataModelToVersioned(newResource, serviceCtx.APIVersion)
+	err = e.AsyncOperation.QueueAsyncOperation(ctx, serviceCtx, AsyncPutHTTPRouteOperationTimeout)
 	if err != nil {
+		newResource.Properties.ProvisioningState = v1.ProvisioningStateFailed
+		_, rbErr := e.SaveResource(ctx, serviceCtx.ResourceID.String(), newResource, nr.ETag)
+		if rbErr != nil {
+			return nil, rbErr
+		}
 		return nil, err
 	}
 
-	headers := map[string]string{"ETag": nr.ETag}
+	respCode := http.StatusCreated
+	if req.Method == http.MethodPatch {
+		respCode = http.StatusAccepted
+	}
 
-	return rest.NewOKResponseWithHeaders(versioned, headers), nil
+	return rest.NewAsyncOperationResponse(newResource, newResource.TrackedResource.Location, respCode, serviceCtx.ResourceID, serviceCtx.OperationID), nil
 }
 
 // Validate extracts versioned resource from request and validate the properties.
@@ -86,18 +111,17 @@ func (e *CreateOrUpdateHTTPRoute) Validate(ctx context.Context, req *http.Reques
 
 	dm.ID = serviceCtx.ResourceID.String()
 	dm.TrackedResource = ctrl.BuildTrackedResource(ctx)
-	// TODO: Update the state.
-	dm.Properties.ProvisioningState = v1.ProvisioningStateSucceeded
 
 	return dm, err
 }
 
-// UpdateExistingResourceData updates the HTTPRoute resource before it is saved to the DB.
-func UpdateExistingResourceData(ctx context.Context, er *datamodel.HTTPRoute, nr *datamodel.HTTPRoute) {
+// enrichMetadata updates the HTTPRoute resource before it is saved to the DB.
+func enrichMetadata(ctx context.Context, er *datamodel.HTTPRoute, nr *datamodel.HTTPRoute) {
 	sc := servicecontext.ARMRequestContextFromContext(ctx)
 	nr.SystemData = ctrl.UpdateSystemData(er.SystemData, *sc.SystemData())
 	if er.CreatedAPIVersion != "" {
 		nr.CreatedAPIVersion = er.CreatedAPIVersion
 	}
 	nr.TenantID = sc.HomeTenantID
+	nr.Properties.ProvisioningState = v1.ProvisioningStateAccepted
 }
diff --git a/pkg/corerp/frontend/controller/httproutes/deletehttproute.go b/pkg/corerp/frontend/controller/httproutes/deletehttproute.go
index 99082e3fc..9f0fbe716 100644
--- a/pkg/corerp/frontend/controller/httproutes/deletehttproute.go
+++ b/pkg/corerp/frontend/controller/httproutes/deletehttproute.go
@@ -9,16 +9,23 @@ import (
 	"context"
 	"errors"
 	"net/http"
+	"time"
 
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
 	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
 	ctrl "github.com/project-radius/radius/pkg/armrpc/frontend/controller"
 	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
 	"github.com/project-radius/radius/pkg/corerp/datamodel"
+	"github.com/project-radius/radius/pkg/corerp/frontend/controller"
 	"github.com/project-radius/radius/pkg/radrp/rest"
 	"github.com/project-radius/radius/pkg/ucp/store"
 )
 
-var _ ctrl.Controller = (*DeleteHTTPRoute)(nil)
+var (
+	_ ctrl.Controller = (*DeleteHTTPRoute)(nil)
+	// AsyncDeleteHTTPRouteOperationTimeout is the default timeout duration of async delete httproute operation.
+	AsyncDeleteHTTPRouteOperationTimeout = time.Duration(120) * time.Second
+)
 
 // DeleteHTTPRoute is the controller implementation to delete HTTPRoute resource.
 type DeleteHTTPRoute struct {
@@ -40,23 +47,31 @@ func (e *DeleteHTTPRoute) Run(ctx context.Context, req *http.Request) (rest.Resp
 		return nil, err
 	}
 
-	if etag == "" {
+	if err != nil && errors.Is(&store.ErrNotFound{}, err) {
 		return rest.NewNoContentResponse(), nil
 	}
 
+	if !existingResource.Properties.ProvisioningState.IsTerminal() {
+		return rest.NewConflictResponse(controller.OngoingAsyncOperationOnResourceMessage), nil
+	}
+
 	err = ctrl.ValidateETag(*serviceCtx, etag)
 	if err != nil {
 		return rest.NewPreconditionFailedResponse(serviceCtx.ResourceID.String(), err.Error()), nil
 	}
 
-	// TODO: handle async deletion later.
-	err = e.DataStore.Delete(ctx, serviceCtx.ResourceID.String())
+	err = e.AsyncOperation.QueueAsyncOperation(ctx, serviceCtx, AsyncDeleteHTTPRouteOperationTimeout)
 	if err != nil {
-		if errors.Is(&store.ErrNotFound{}, err) {
-			return rest.NewNoContentResponse(), nil
+		existingResource.Properties.ProvisioningState = v1.ProvisioningStateFailed
+		_, rbErr := e.SaveResource(ctx, serviceCtx.ResourceID.String(), existingResource, etag)
+		if rbErr != nil {
+			return nil, rbErr
 		}
 		return nil, err
 	}
 
-	return rest.NewOKResponse(nil), nil
+	existingResource.Properties.ProvisioningState = v1.ProvisioningStateDeleting
+
+	return rest.NewAsyncOperationResponse(existingResource, existingResource.TrackedResource.Location, http.StatusAccepted,
+		serviceCtx.ResourceID, serviceCtx.OperationID), nil
 }
diff --git a/pkg/corerp/frontend/controller/types.go b/pkg/corerp/frontend/controller/types.go
new file mode 100644
index 000000000..901060ee1
--- /dev/null
+++ b/pkg/corerp/frontend/controller/types.go
@@ -0,0 +1,10 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package controller
+
+const (
+	OngoingAsyncOperationOnResourceMessage = "the source or target resource group is locked (e.g. move already in progress, resource group is being deleted)"
+)
diff --git a/pkg/corerp/frontend/handler/getoperations.go b/pkg/corerp/frontend/handler/getoperations.go
index 1b6d30e74..956ba44f6 100644
--- a/pkg/corerp/frontend/handler/getoperations.go
+++ b/pkg/corerp/frontend/handler/getoperations.go
@@ -176,7 +176,6 @@ func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList {
 				},
 				IsDataAction: false,
 			},
-			// TODO: add CREATE, UPDATE and DELETE operations for gateway resource after async implementation
 			&v1.Operation{
 				Name: "Applications.Core/gateways/read",
 				Display: &v1.OperationDisplayProperties{
@@ -187,6 +186,26 @@ func (opctrl *GetOperations) availableOperationsV1() *v1.PaginatedList {
 				},
 				IsDataAction: false,
 			},
+			&v1.Operation{
+				Name: "Applications.Core/gateways/write",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "gateways",
+					Operation:   "Create/Update gateway",
+					Description: "Create or Updateg a gateway.",
+				},
+				IsDataAction: false,
+			},
+			&v1.Operation{
+				Name: "Applications.Core/gateways/delete",
+				Display: &v1.OperationDisplayProperties{
+					Provider:    ProviderNamespaceName,
+					Resource:    "gateways",
+					Operation:   "delete gateway",
+					Description: "Delete a gateway.",
+				},
+				IsDataAction: false,
+			},
 			&v1.Operation{
 				Name: "Applications.Core/containers/read",
 				Display: &v1.OperationDisplayProperties{
diff --git a/pkg/corerp/frontend/handler/routes.go b/pkg/corerp/frontend/handler/routes.go
index 7eb70e8ef..ad194540b 100644
--- a/pkg/corerp/frontend/handler/routes.go
+++ b/pkg/corerp/frontend/handler/routes.go
@@ -13,6 +13,8 @@ import (
 	manager "github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
 	"github.com/project-radius/radius/pkg/armrpc/frontend/server"
 	"github.com/project-radius/radius/pkg/ucp/dataprovider"
+	"github.com/project-radius/radius/pkg/validator"
+	"github.com/project-radius/radius/swagger"
 
 	app_ctrl "github.com/project-radius/radius/pkg/corerp/frontend/controller/applications"
 	ctr_ctrl "github.com/project-radius/radius/pkg/corerp/frontend/controller/containers"
@@ -28,35 +30,42 @@ const (
 func AddRoutes(ctx context.Context, sp dataprovider.DataStorageProvider, sm manager.StatusManager, router *mux.Router, pathBase string, isARM bool) error {
 	if isARM {
 		pathBase += "/subscriptions/{subscriptionID}"
+	} else {
+		pathBase += "/planes/radius/{planeName}"
 	}
 
+	resourceGroupPath := "/resourcegroups/{resourceGroupName}"
+
 	// Configure the default ARM handlers.
 	err := server.ConfigureDefaultHandlers(ctx, sp, sm, router, pathBase, isARM, ProviderNamespaceName, NewGetOperations)
 	if err != nil {
 		return err
 	}
 
-	envRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.core/environments").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	envResourceRouter := envRTSubrouter.PathPrefix("/{environment}").Subrouter()
+	specLoader, err := validator.LoadSpec(ctx, ProviderNamespaceName, swagger.SpecFiles, pathBase+resourceGroupPath)
+	if err != nil {
+		return err
+	}
+
+	rootScopeRouter := router.PathPrefix(pathBase + resourceGroupPath).Subrouter()
+	rootScopeRouter.Use(validator.APIValidator(specLoader))
+
+	envRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.core/environments").Subrouter()
+	envResourceRouter := envRTSubrouter.Path("/{environmentName}").Subrouter()
 
-	hrtSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.core/httproutes").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	hrtResourceRouter := hrtSubrouter.PathPrefix("/{httproute}").Subrouter()
+	hrtSubrouter := rootScopeRouter.PathPrefix("/providers/applications.core/httproutes").Subrouter()
+	hrtResourceRouter := hrtSubrouter.Path("/{httpRouteName}").Subrouter()
 
-	ctrRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.core/containers").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	ctrResourceRouter := ctrRTSubrouter.PathPrefix("/{container}").Subrouter()
+	ctrRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.core/containers").Subrouter()
+	ctrResourceRouter := ctrRTSubrouter.Path("/{containerName}").Subrouter()
 
 	// Adds application resource type routes
-	appRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.core/applications").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	appResourceRouter := appRTSubrouter.PathPrefix("/{application}").Subrouter()
+	appRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.core/applications").Subrouter()
+	appResourceRouter := appRTSubrouter.Path("/{applicationName}").Subrouter()
 
 	// Adds gateway resource type routes
-	gtwyRTSubrouter := router.NewRoute().PathPrefix(pathBase+"/resourcegroups/{resourceGroup}/providers/applications.core/gateways").
-		Queries(server.APIVersionParam, "{"+server.APIVersionParam+"}").Subrouter()
-	gtwyResourceRouter := gtwyRTSubrouter.PathPrefix("/{application}").Subrouter()
+	gtwyRTSubrouter := rootScopeRouter.PathPrefix("/providers/applications.core/gateways").Subrouter()
+	gtwyResourceRouter := gtwyRTSubrouter.Path("/{gatewayName}").Subrouter()
 
 	handlerOptions := []server.HandlerOptions{
 		// Environments resource handler registration.
@@ -183,7 +192,6 @@ func AddRoutes(ctx context.Context, sp dataprovider.DataStorageProvider, sm mana
 			HandlerFactory: app_ctrl.NewDeleteApplication,
 		},
 		// Gateway resource handler registration.
-		// TODO: Add async registration for createorupdate and delete handler
 		{
 			ParentRouter:   gtwyRTSubrouter,
 			ResourceType:   gtwy_ctrl.ResourceTypeName,
@@ -196,6 +204,24 @@ func AddRoutes(ctx context.Context, sp dataprovider.DataStorageProvider, sm mana
 			Method:         v1.OperationGet,
 			HandlerFactory: gtwy_ctrl.NewGetGateway,
 		},
+		{
+			ParentRouter:   gtwyResourceRouter,
+			ResourceType:   gtwy_ctrl.ResourceTypeName,
+			Method:         v1.OperationPatch,
+			HandlerFactory: gtwy_ctrl.NewCreateOrUpdateGateway,
+		},
+		{
+			ParentRouter:   gtwyResourceRouter,
+			ResourceType:   gtwy_ctrl.ResourceTypeName,
+			Method:         v1.OperationPut,
+			HandlerFactory: gtwy_ctrl.NewCreateOrUpdateGateway,
+		},
+		{
+			ParentRouter:   gtwyResourceRouter,
+			ResourceType:   gtwy_ctrl.ResourceTypeName,
+			Method:         v1.OperationDelete,
+			HandlerFactory: gtwy_ctrl.NewDeleteGateway,
+		},
 	}
 	for _, h := range handlerOptions {
 		if err := server.RegisterHandler(ctx, sp, sm, h); err != nil {
diff --git a/pkg/ucp/frontend/ucphandler/planes/planes.go b/pkg/ucp/frontend/ucphandler/planes/planes.go
index 186d3d734..0d62c8e41 100644
--- a/pkg/ucp/frontend/ucphandler/planes/planes.go
+++ b/pkg/ucp/frontend/ucphandler/planes/planes.go
@@ -71,6 +71,17 @@ func (ucp *ucpHandler) CreateOrUpdate(ctx context.Context, db store.StorageClien
 	}
 
 	// At least one provider needs to be configured
+	if plane.Properties.Kind == rest.PlaneKindUCPNative {
+		if plane.Properties.ResourceProviders == nil || len(plane.Properties.ResourceProviders) == 0 {
+			err = fmt.Errorf("At least one resource provider must be configured for UCP native plane: %s", plane.Name)
+			return rest.NewBadRequestResponse(err.Error()), nil
+		}
+	} else {
+		if plane.Properties.URL == "" {
+			err = fmt.Errorf("URL must be specified for plane: %s", plane.Name)
+			return rest.NewBadRequestResponse(err.Error()), nil
+		}
+	}
 
 	_, err = planesdb.GetByID(ctx, db, ID)
 	if err != nil {
@@ -185,11 +196,17 @@ func (ucp *ucpHandler) ProxyRequest(ctx context.Context, db store.StorageClient,
 	// We need to preserve the case while storing data in DB and therefore iterating for case
 	// insensitive comparisons
 	var proxyURL string
-	for k, v := range plane.Properties.ResourceProviders {
-		if strings.EqualFold(k, resourceID.ProviderNamespace()) {
-			proxyURL = v
-			break
+	if plane.Properties.Kind == rest.PlaneKindUCPNative {
+		for k, v := range plane.Properties.ResourceProviders {
+			if strings.EqualFold(k, resourceID.ProviderNamespace()) {
+				proxyURL = v
+				break
+			}
 		}
+	} else {
+		// For a non UCP-native plane, the configuration should have a URL to which
+		// all the requests will be forwarded
+		proxyURL = plane.Properties.URL
 	}
 
 	downstream, err := url.Parse(proxyURL)
@@ -198,8 +215,9 @@ func (ucp *ucpHandler) ProxyRequest(ctx context.Context, db store.StorageClient,
 	}
 
 	options := proxy.ReverseProxyOptions{
-		RoundTripper: http.DefaultTransport,
-		ProxyAddress: ucp.options.Address,
+		RoundTripper:     http.DefaultTransport,
+		ProxyAddress:     ucp.options.Address,
+		TrimPlanesPrefix: (plane.Properties.Kind != rest.PlaneKindUCPNative),
 	}
 
 	// As per https://github.com/golang/go/issues/28940#issuecomment-441749380, the way to check
@@ -211,6 +229,7 @@ func (ucp *ucpHandler) ProxyRequest(ctx context.Context, db store.StorageClient,
 
 	requestInfo := proxy.UCPRequestInfo{
 		PlaneURL:   proxyURL,
+		PlaneKind:  plane.Properties.Kind,
 		PlaneID:    planePath,
 		HTTPScheme: httpScheme,
 		// The Host field in the request that the client makes to UCP contains the UCP Host address
@@ -218,10 +237,7 @@ func (ucp *ucpHandler) ProxyRequest(ctx context.Context, db store.StorageClient,
 		UCPHost: r.Host + ucp.options.BasePath,
 	}
 
-	// Remove the /planes/<plane-type>/<plane-name> prefix
-	segments := strings.Split(incomingURL.Path, "/")
-	p := strings.Join(segments[4:], "/")
-	url, err := url.Parse(p)
+	url, err := url.Parse(incomingURL.Path)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/ucp/proxy/arm.go b/pkg/ucp/proxy/arm.go
index 3dec3b316..f00e4942e 100644
--- a/pkg/ucp/proxy/arm.go
+++ b/pkg/ucp/proxy/arm.go
@@ -20,10 +20,18 @@ func NewARMProxy(options ReverseProxyOptions, downstream *url.URL, configure fun
 	p := armProxy{
 		ProxyAddress: options.ProxyAddress,
 	}
+
+	directors := []DirectorFunc{}
+	if options.TrimPlanesPrefix {
+		// Remove the UCP Planes prefix for non-native planes that do not
+		// understand UCP IDs
+		directors = []DirectorFunc{trimPlanesPrefix}
+	}
+
 	builder := ReverseProxyBuilder{
 		Downstream:    downstream,
 		EnableLogging: true,
-		Directors:     []DirectorFunc{trimPlanesPrefix},
+		Directors:     directors,
 		Transport: Transport{
 			roundTripper: options.RoundTripper,
 		},
diff --git a/pkg/ucp/proxy/types.go b/pkg/ucp/proxy/types.go
index fbcfc6719..fcffb34e0 100644
--- a/pkg/ucp/proxy/types.go
+++ b/pkg/ucp/proxy/types.go
@@ -12,10 +12,13 @@ import (
 	"net/http/httputil"
 	"net/url"
 	"strings"
+
+	"github.com/project-radius/radius/pkg/ucp/rest"
 )
 
 type UCPRequestInfo struct {
 	PlaneURL   string
+	PlaneKind  string
 	PlaneID    string
 	HTTPScheme string
 	UCPHost    string
@@ -42,8 +45,9 @@ type ReverseProxy interface {
 }
 
 type ReverseProxyOptions struct {
-	RoundTripper http.RoundTripper
-	ProxyAddress string
+	RoundTripper     http.RoundTripper
+	ProxyAddress     string
+	TrimPlanesPrefix bool
 }
 
 type ReverseProxyBuilder struct {
@@ -142,17 +146,28 @@ func convertHeaderToUCPIDs(ctx context.Context, headerName string, header []stri
 	if requestInfo.UCPHost == "" {
 		return fmt.Errorf("UCP Host Address unknown. Cannot convert response header")
 	}
-	// Make sure we only have the base URL here
-	if requestInfo.PlaneID == "" {
-		return fmt.Errorf("Could not find plane ID data in %s header", headerName)
+
+	if requestInfo.PlaneKind == "" {
+		return fmt.Errorf("Plane Kind unknown. Cannot convert response header")
+	}
+
+	var planeID string
+	if requestInfo.PlaneKind != rest.PlaneKindUCPNative {
+		if requestInfo.PlaneID == "" {
+			return fmt.Errorf("Could not find plane ID data in %s header", headerName)
+		}
+		// Doing this only for non UCP Native planes. For UCP Native planes, the request URL will have the plane ID in it and therefore no need to
+		// add the plane ID
+		planeID = requestInfo.PlaneID
 	}
 
 	if requestInfo.HTTPScheme == "" {
 		return fmt.Errorf("Could not find http scheme data in %s header", headerName)
 	}
+
 	// Found a plane matching the URL in the location header
 	// Convert to UCP ID using the planeID corresponding to the URL of the server from where the response was received
-	val := requestInfo.HTTPScheme + "://" + requestInfo.UCPHost + requestInfo.PlaneID + "/" + strings.Join(segments[3:], "/")
+	val := requestInfo.HTTPScheme + "://" + requestInfo.UCPHost + planeID + "/" + strings.Join(segments[3:], "/")
 
 	// Replace the header with the computed value.
 	// Do not use the Del/Set methods on header as it can change the header casing to canonical form
diff --git a/pkg/ucp/rest/objects.go b/pkg/ucp/rest/objects.go
index 7a6956674..e86aade77 100644
--- a/pkg/ucp/rest/objects.go
+++ b/pkg/ucp/rest/objects.go
@@ -6,9 +6,17 @@
 package rest
 
 type PlaneProperties struct {
-	ResourceProviders map[string]string `json:"resourceProviders" yaml:"resourceProviders"`
+	ResourceProviders map[string]string `json:"resourceProviders" yaml:"resourceProviders"` // Used only for UCP native planes
 	Kind              string            `json:"kind" yaml:"kind"`
+	URL               string            `json:"url" yaml:"url"` // Used only for non UCP native planes
 }
+
+// Plane kinds
+const (
+	PlaneKindUCPNative = "UCPNative"
+	PlaneKindAzure     = "Azure"
+)
+
 type Plane struct {
 	ID         string          `json:"id" yaml:"id"`
 	Type       string          `json:"type" yaml:"type"`
diff --git a/pkg/validator/apivalidator.go b/pkg/validator/apivalidator.go
index 568b18547..79deb4852 100644
--- a/pkg/validator/apivalidator.go
+++ b/pkg/validator/apivalidator.go
@@ -48,7 +48,6 @@ func APIValidator(loader *Loader) func(h http.Handler) http.Handler {
 				}
 				return
 			}
-
 			h.ServeHTTP(w, r)
 		}
 
diff --git a/pkg/validator/loader.go b/pkg/validator/loader.go
index 9bbe9acc4..0305dbf9a 100644
--- a/pkg/validator/loader.go
+++ b/pkg/validator/loader.go
@@ -30,6 +30,7 @@ type Loader struct {
 	validators        map[string]validator
 	supportedVersions map[string][]string
 	providerName      string
+	rootScopePrefix   string
 	specFiles         fs.FS
 }
 
@@ -57,12 +58,13 @@ func (l *Loader) GetValidator(resourceType, version string) (Validator, bool) {
 }
 
 // LoadSpec loads the swagger files and caches the validator.
-func LoadSpec(ctx context.Context, providerName string, specs fs.FS) (*Loader, error) {
+func LoadSpec(ctx context.Context, providerName string, specs fs.FS, rootScopePrefix string) (*Loader, error) {
 	log := logr.FromContextOrDiscard(ctx)
 	l := &Loader{
 		providerName:      providerName,
 		validators:        map[string]validator{},
 		supportedVersions: map[string][]string{},
+		rootScopePrefix:   rootScopePrefix,
 		specFiles:         specs,
 	}
 
@@ -116,11 +118,12 @@ func LoadSpec(ctx context.Context, providerName string, specs fs.FS) (*Loader, e
 		qualifiedType := parsed["provider"] + "/" + parsed["resourcetype"]
 		key := getValidatorKey(qualifiedType, parsed["version"])
 		l.validators[key] = validator{
-			TypeName:     qualifiedType,
-			APIVersion:   parsed["version"],
-			specDoc:      wDoc,
-			paramCache:   make(map[string]map[string]spec.Parameter),
-			paramCacheMu: &sync.RWMutex{},
+			TypeName:        qualifiedType,
+			APIVersion:      parsed["version"],
+			specDoc:         wDoc,
+			rootScopePrefix: l.rootScopePrefix,
+			paramCache:      make(map[string]map[string]spec.Parameter),
+			paramCacheMu:    &sync.RWMutex{},
 		}
 		l.supportedVersions[qualifiedType] = append(l.supportedVersions[qualifiedType], parsed["version"])
 
diff --git a/pkg/validator/validator.go b/pkg/validator/validator.go
index 8fc08d0e9..6b10ccd76 100644
--- a/pkg/validator/validator.go
+++ b/pkg/validator/validator.go
@@ -6,7 +6,10 @@
 package validator
 
 import (
+	"bytes"
+	"encoding/json"
 	"errors"
+	"io"
 	"net/http"
 	"strings"
 	"sync"
@@ -19,10 +22,13 @@ import (
 	"github.com/go-openapi/strfmt"
 	"github.com/gorilla/mux"
 	"github.com/project-radius/radius/pkg/radrp/armerrors"
+	"github.com/project-radius/radius/pkg/ucp/resources"
 )
 
 const (
 	APIVersionQueryKey = "api-version"
+
+	rootScopeParam = "rootScope"
 )
 
 var (
@@ -48,9 +54,10 @@ type validator struct {
 	TypeName   string
 	APIVersion string
 
-	specDoc      *loads.Document
-	paramCache   map[string]map[string]spec.Parameter
-	paramCacheMu *sync.RWMutex
+	rootScopePrefix string
+	specDoc         *loads.Document
+	paramCache      map[string]map[string]spec.Parameter
+	paramCacheMu    *sync.RWMutex
 }
 
 // findParam looks up the correct spec.Parameter which a unique parameter is defined by a combination
@@ -85,18 +92,15 @@ func (v *validator) findParam(req *http.Request) (map[string]spec.Parameter, err
 	}
 
 	// Gorilla mux route path should start with {rootScope:.*} to handle UCP and Azure root scope.
-	scopePath := strings.Replace(pathTemplate, "{rootScope:.*}", "{rootScope}", 1)
-	var param map[string]spec.Parameter = nil
+	scopePath := strings.Replace(pathTemplate, v.rootScopePrefix, "/{"+rootScopeParam+"}", 1)
+
 	// Iterate loaded paths to find the matched route.
 	for k := range v.specDoc.Analyzer.AllPaths() {
 		if strings.EqualFold(k, scopePath) {
-			param = v.specDoc.Analyzer.ParamsFor(req.Method, k)
+			v.paramCache[templateKey] = v.specDoc.Analyzer.ParamsFor(req.Method, k)
+			return v.paramCache[templateKey], nil
 		}
 	}
-	if param != nil {
-		v.paramCache[templateKey] = param
-		return v.paramCache[templateKey], nil
-	}
 	return nil, ErrUndefinedRoute
 }
 
@@ -104,6 +108,9 @@ func (v *validator) findParam(req *http.Request) (map[string]spec.Parameter, err
 func (v *validator) toRouteParams(req *http.Request) middleware.RouteParams {
 	routeParams := middleware.RouteParams{}
 
+	if rID, err := resources.Parse(req.URL.Path); err == nil {
+		routeParams = append(routeParams, middleware.RouteParam{Name: rootScopeParam, Value: rID.RootScope()})
+	}
 	for k := range req.URL.Query() {
 		routeParams = append(routeParams, middleware.RouteParam{Name: k, Value: req.URL.Query().Get(k)})
 	}
@@ -123,25 +130,45 @@ func (v *validator) ValidateRequest(req *http.Request) []ValidationError {
 	routeParams := v.toRouteParams(req)
 	params, err := v.findParam(req)
 	if err != nil {
-		return routePathParseError(err)
+		return []ValidationError{{
+			Code:    armerrors.InvalidRequestContent,
+			Message: "failed to parse route: " + err.Error(),
+		}}
 	}
 
 	binder := middleware.NewUntypedRequestBinder(params, v.specDoc.Spec(), strfmt.Default)
-	data := map[string]interface{}{}
 	var errs []ValidationError
-	result := binder.Bind(req, middleware.RouteParams(routeParams), runtime.JSONConsumer(), &data)
+
+	// Read content for validation and recover later.
+	content, err := io.ReadAll(req.Body)
+	if err != nil {
+		return []ValidationError{{
+			Code:    armerrors.InvalidRequestContent,
+			Message: "failed to read body content: " + err.Error(),
+		}}
+	}
+
+	// WORKAROUND: https://github.com/project-radius/radius/issues/2683
+	// UCP or DE sends the invalid request which has -1 ContentLength header so validator treats it as empty content.
+	if req.ContentLength < 0 && len(content) > 0 {
+		req.ContentLength = (int64)(len(content))
+	}
+
+	bindData := make(map[string]interface{})
+	result := binder.Bind(
+		req, middleware.RouteParams(routeParams),
+		// Pass content to the validator marshaler to prevent from reading body from buffer.
+		runtime.ConsumerFunc(func(reader io.Reader, data interface{}) error {
+			return json.Unmarshal(content, data)
+		}), bindData)
 	if result != nil {
 		errs = parseResult(result)
 	}
 
-	return errs
-}
+	// Recover body after validation is done.
+	req.Body = io.NopCloser(bytes.NewBuffer(content))
 
-func routePathParseError(err error) []ValidationError {
-	return []ValidationError{{
-		Code:    armerrors.InvalidRequestContent,
-		Message: "failed to parse route: " + err.Error(),
-	}}
+	return errs
 }
 
 func parseResult(result error) []ValidationError {
diff --git a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/examples/ExtendersListSecrets.json b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/examples/ExtendersListSecrets.json
new file mode 100644
index 000000000..3358db052
--- /dev/null
+++ b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/examples/ExtendersListSecrets.json
@@ -0,0 +1,18 @@
+{
+    "parameters": {
+      "subscriptionId": "00000000-0000-0000-0000-000000000000",
+      "resourceGroupName": "testGroup",
+      "api-version": "2022-03-15-privatepreview",
+      "extenderName": "extender0"
+    },
+    "responses": {
+      "200": {
+        "body": {
+          "properties": {
+            "accountSid": "sid",
+            "authToken:": "token"
+          }
+        }
+      }
+    }
+}
\ No newline at end of file
diff --git a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/extenders.json b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/extenders.json
index dd2fd7595..527a411cb 100644
--- a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/extenders.json
+++ b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/extenders.json
@@ -216,6 +216,48 @@
             }
           }
         }
+      },
+      "/{rootScope}/providers/Applications.Connector/extenders/{extenderName}/listSecrets": {
+        "post": {
+          "description": "Lists secrets values for the specified Extender resource",
+          "operationId": "Extenders_listSecrets",
+          "produces": [
+            "application/json"
+          ],
+          "x-ms-examples": {
+            "ExtendersGet": {
+              "$ref": "./examples/ExtendersListSecrets.json"
+            }
+          },
+          "tags": [
+            "Extenders"
+          ],
+          "parameters": [
+            {
+              "$ref": "../../../../../common-types/resource-management/v2/types.json#/parameters/ApiVersionParameter"
+            },
+            {
+              "$ref": "global.json#/parameters/RootScopeParameter"
+            },
+            {
+              "$ref": "#/parameters/ExtenderNameParameter"
+            }
+          ],
+          "responses": {
+            "200": {
+              "description": "Extender secrets",
+              "schema": {
+                "$ref": "#/definitions/ExtenderListSecretsResult"
+              }
+            },
+            "default": {
+              "description": "Error response describing the reason for operation failure",
+              "schema": {
+                "$ref": "../../../../../common-types/resource-management/v2/types.json#/definitions/ErrorResponse"
+              }
+            }
+          }
+        }
       }
     },
     "definitions": {
@@ -257,6 +299,15 @@
           }
         }
       },
+      "ExtenderListSecretsResult": {
+        "description": "The secret values for the given Extender resource",
+        "$ref": "#/definitions/ExtenderSecrets"
+      },
+      "ExtenderSecrets": {
+        "description": "The secret values for the given Extender resource",
+        "additionalProperties": true,
+        "properties": {}
+      },
       "ExtenderProperties": {
         "description": "Extender connector properties",
         "type": "object",
@@ -281,8 +332,7 @@
           },
           "secrets": {
             "additionalProperties": true,
-            "properties": {},
-            "type": "object"
+            "$ref": "#/definitions/ExtenderSecrets"
           }
         },
         "required": ["environment"]
diff --git a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/mongoDatabases.json b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/mongoDatabases.json
index 9bbfae19c..7fe4b5406 100644
--- a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/mongoDatabases.json
+++ b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/mongoDatabases.json
@@ -107,7 +107,7 @@
           "200": {
             "description": "MongoDatabase resource",
             "schema": {
-              "$ref": "#/definitions/MongoDatabaseResource"
+              "$ref": "#/definitions/MongoDatabaseResponseResource"
             }
           },
           "default": {
@@ -269,7 +269,7 @@
           "description": "List of MongoDatabase resources",
           "type": "array",
           "items": {
-            "$ref": "#/definitions/MongoDatabaseResource"
+            "$ref": "#/definitions/MongoDatabaseResponseResource"
           }
         },
         "nextLink": {
@@ -279,7 +279,7 @@
       }
     },
     "MongoDatabaseResource": {
-      "description": "MongoDatabse connector",
+      "description": "MongoDatabase connector",
       "type": "object",
       "allOf": [
         {
@@ -299,8 +299,29 @@
         }
       }
     },
-    "MongoDatabaseProperties": {
-      "description": "MongoDatabse connector properties",
+    "MongoDatabaseResponseResource": {
+      "description": "MongoDatabase connector",
+      "type": "object",
+      "allOf": [
+        {
+          "$ref": "../../../../../common-types/resource-management/v2/types.json#/definitions/TrackedResource"
+        }
+      ],
+      "required": [
+        "properties"
+      ],
+      "properties": {
+        "systemData": {
+          "$ref": "../../../../../common-types/resource-management/v2/types.json#/definitions/systemData"
+        },
+        "properties": {
+          "x-ms-client-flatten": true,
+          "$ref": "#/definitions/MongoDatabaseResponseProperties"
+        }
+      }
+    },
+    "MongoDatabaseResponseProperties":{
+      "description": "MongoDatabase connector properties",
       "type": "object",
       "allOf": [
         {
@@ -340,7 +361,18 @@
           "example": [
             27017
           ]
-        },
+        }
+      }
+    },
+    "MongoDatabaseProperties": {
+      "description": "MongoDatabase connector properties",
+      "type": "object",
+      "allOf": [
+        {
+          "$ref": "#/definitions/MongoDatabaseResponseProperties"
+        }
+      ],
+      "properties": {
         "secrets": {
           "type": "object",
           "description": "Secrets values provided for the resource",
diff --git a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/rabbitMQMessageQueues.json b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/rabbitMQMessageQueues.json
index c8376c6df..1e0cd5546 100644
--- a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/rabbitMQMessageQueues.json
+++ b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/rabbitMQMessageQueues.json
@@ -107,7 +107,7 @@
           "200": {
             "description": "RabbitMQMessageQueue resource",
             "schema": {
-              "$ref": "#/definitions/RabbitMQMessageQueueResource"
+              "$ref": "#/definitions/RabbitMQMessageQueueResponseResource"
             }
           },
           "default": {
@@ -269,7 +269,7 @@
           "description": "List of RabbitMQMessageQueue resources",
           "type": "array",
           "items": {
-            "$ref": "#/definitions/RabbitMQMessageQueueResource"
+            "$ref": "#/definitions/RabbitMQMessageQueueResponseResource"
           }
         },
         "nextLink": {
@@ -299,6 +299,27 @@
         }
       }
     },
+    "RabbitMQMessageQueueResponseResource": {
+      "description": "RabbitMQMessageQueue connector",
+      "type": "object",
+      "allOf": [
+        {
+          "$ref": "../../../../../common-types/resource-management/v2/types.json#/definitions/TrackedResource"
+        }
+      ],
+      "required": [
+        "properties"
+      ],
+      "properties": {
+        "systemData": {
+          "$ref": "../../../../../common-types/resource-management/v2/types.json#/definitions/systemData"
+        },
+        "properties": {
+          "x-ms-client-flatten": true,
+          "$ref": "#/definitions/RabbitMQMessageQueueResponseProperties"
+        }
+      }
+    },
     "RabbitMQListSecretsResult" :{
       "description": "The secret values for the given RabbitMQMessageQueue resource",
       "$ref": "#/definitions/RabbitMQSecrets"
@@ -312,8 +333,8 @@
         }
       }
     },
-    "RabbitMQMessageQueueProperties": {
-      "description": "RabbitMQMessageQueue connector properties",
+    "RabbitMQMessageQueueResponseProperties": {
+      "description": "RabbitMQMessageQueue connector response properties",
       "type": "object",
       "allOf": [
         {
@@ -336,7 +357,19 @@
         "queue": {
           "description": "The name of the queue",
           "type": "string"
-        },
+        }
+      },
+      "required": ["environment","queue"]
+    },
+    "RabbitMQMessageQueueProperties": {
+      "description": "RabbitMQMessageQueue connector properties",
+      "type": "object",
+      "allOf": [
+        {
+          "$ref": "#/definitions/RabbitMQMessageQueueResponseProperties"
+        }
+      ],
+      "properties": {
         "secrets": {
           "type": "object",
           "description": "Secrets provided by resources,",
diff --git a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/redisCaches.json b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/redisCaches.json
index 52e07ebf7..c7d77201d 100644
--- a/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/redisCaches.json
+++ b/swagger/specification/applications/resource-manager/Applications.Connector/preview/2022-03-15-privatepreview/redisCaches.json
@@ -107,7 +107,7 @@
           "200": {
             "description": "RedisCache resource",
             "schema": {
-              "$ref": "#/definitions/RedisCacheResource"
+              "$ref": "#/definitions/RedisCacheResponseResource"
             }
           },
           "default": {
@@ -269,7 +269,7 @@
           "description": "List of RedisCache resources",
           "type": "array",
           "items": {
-            "$ref": "#/definitions/RedisCacheResource"
+            "$ref": "#/definitions/RedisCacheResponseResource"
           }
         },
         "nextLink": {
@@ -299,6 +299,27 @@
         }
       }
     },
+    "RedisCacheResponseResource": {
+      "description": "RedisCache connector",
+      "type": "object",
+      "allOf": [
+        {
+          "$ref": "../../../../../common-types/resource-management/v2/types.json#/definitions/TrackedResource"
+        }
+      ],
+      "required": [
+        "properties"
+      ],
+      "properties": {
+        "systemData": {
+          "$ref": "../../../../../common-types/resource-management/v2/types.json#/definitions/systemData"
+        },
+        "properties": {
+          "x-ms-client-flatten": true,
+          "$ref": "#/definitions/RedisCacheResponseProperties"
+        }
+      }
+    },
     "RedisCacheListSecretsResult": {
       "description": "The secret values for the given RedisCache resource",
       "$ref": "#/definitions/RedisCacheSecrets"
@@ -320,7 +341,7 @@
         }
       }
     },
-    "RedisCacheProperties": {
+    "RedisCacheResponseProperties": {
       "description": "RedisCache connector properties",
       "type": "object",
       "allOf": [
@@ -363,14 +384,25 @@
             6380,
             6379
           ]
-        },
+        }
+      },
+      "required": ["environment"]
+    },
+    "RedisCacheProperties": {
+      "description": "RedisCache connector properties",
+      "type": "object",
+      "allOf": [
+        {
+          "$ref": "#/definitions/RedisCacheResponseProperties"
+        }
+      ],
+      "properties": {
         "secrets": {
           "type": "object",
           "additionalProperties": false,
           "$ref": "#/definitions/RedisCacheSecrets"
         }
-      },
-      "required": ["environment"]
+      }
     }
   },
   "parameters": {



Test patch:
diff --git a/pkg/cli/config_test.go b/pkg/cli/config_test.go
index d7fedfa31..bd29a4a13 100644
--- a/pkg/cli/config_test.go
+++ b/pkg/cli/config_test.go
@@ -9,9 +9,10 @@ import (
 	"bytes"
 	"testing"
 
-	"github.com/project-radius/radius/pkg/cli/environments"
 	"github.com/spf13/viper"
 	"github.com/stretchr/testify/require"
+
+	"github.com/project-radius/radius/pkg/cli/environments"
 )
 
 func Test_ReadEnvironmentSection_NoContent(t *testing.T) {
diff --git a/pkg/connectorrp/api/v20220315privatepreview/daprstatestore_conversion.go b/pkg/connectorrp/api/v20220315privatepreview/daprstatestore_conversion.go
index 050641bdb..9b1a10cc2 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/daprstatestore_conversion.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/daprstatestore_conversion.go
@@ -13,14 +13,10 @@ import (
 
 // ConvertTo converts from the versioned DaprStateStore resource to version-agnostic datamodel.
 func (src *DaprStateStoreResource) ConvertTo() (conv.DataModelInterface, error) {
-	outputResources := v1.ResourceStatus{}.OutputResources
-	if src.Properties.GetDaprStateStoreProperties().Status != nil {
-		outputResources = src.Properties.GetDaprStateStoreProperties().Status.OutputResources
-	}
 	daprStateStoreProperties := datamodel.DaprStateStoreProperties{
 		BasicResourceProperties: v1.BasicResourceProperties{
 			Status: v1.ResourceStatus{
-				OutputResources: outputResources,
+				OutputResources: GetOutputResourcesForVersionedResource(src.Properties.GetDaprStateStoreProperties().Status),
 			},
 		},
 		ProvisioningState: toProvisioningStateDataModel(src.Properties.GetDaprStateStoreProperties().ProvisioningState),
diff --git a/pkg/connectorrp/api/v20220315privatepreview/mongodatabase_conversion_test.go b/pkg/connectorrp/api/v20220315privatepreview/mongodatabase_conversion_test.go
index 0340c9a18..5cdfcb355 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/mongodatabase_conversion_test.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/mongodatabase_conversion_test.go
@@ -98,6 +98,59 @@ func TestMongoDatabase_ConvertDataModelToVersioned(t *testing.T) {
 	}
 }
 
+func TestMongoDatabaseResponse_ConvertVersionedToDataModel(t *testing.T) {
+	// arrange
+	rawPayload := loadTestData("mongodatabaseresource.json")
+	versionedResource := &MongoDatabaseResource{}
+	err := json.Unmarshal(rawPayload, versionedResource)
+	require.NoError(t, err)
+
+	// act
+	dm, err := versionedResource.ConvertTo()
+
+	resourceType := map[string]interface{}{"Provider": "azure", "Type": "azure.cosmosdb.mongo"}
+	// assert
+	require.NoError(t, err)
+	convertedResource := dm.(*datamodel.MongoDatabase)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/mongoDatabases/mongo0", convertedResource.ID)
+	require.Equal(t, "mongo0", convertedResource.Name)
+	require.Equal(t, "Applications.Connector/mongoDatabases", convertedResource.Type)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", convertedResource.Properties.Application)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", convertedResource.Properties.Environment)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Microsoft.DocumentDB/databaseAccounts/testAccount/mongodbDatabases/db", convertedResource.Properties.Resource)
+	require.Equal(t, "testAccount1.mongo.cosmos.azure.com", convertedResource.Properties.Host)
+	require.Equal(t, int32(10255), convertedResource.Properties.Port)
+	require.Equal(t, "2022-03-15-privatepreview", convertedResource.InternalMetadata.UpdatedAPIVersion)
+	require.Equal(t, "Deployment", convertedResource.Properties.Status.OutputResources[0]["LocalID"])
+	require.Equal(t, resourceType, convertedResource.Properties.Status.OutputResources[0]["ResourceType"])
+}
+
+func TestMongoDatabaseResponse_ConvertDataModelToVersioned(t *testing.T) {
+	// arrange
+	rawPayload := loadTestData("mongodatabaseresponseresourcedatamodel.json")
+	resource := &datamodel.MongoDatabase{}
+	err := json.Unmarshal(rawPayload, resource)
+	require.NoError(t, err)
+
+	// act
+	versionedResource := &MongoDatabaseResource{}
+	err = versionedResource.ConvertFrom(resource)
+
+	resourceType := map[string]interface{}{"Provider": "azure", "Type": "azure.cosmosdb.mongo"}
+	// assert
+	require.NoError(t, err)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/mongoDatabases/mongo0", resource.ID)
+	require.Equal(t, "mongo0", resource.Name)
+	require.Equal(t, "Applications.Connector/mongoDatabases", resource.Type)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", resource.Properties.Application)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", resource.Properties.Environment)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Microsoft.DocumentDB/databaseAccounts/testAccount/mongodbDatabases/db", resource.Properties.Resource)
+	require.Equal(t, "testAccount1.mongo.cosmos.azure.com", resource.Properties.Host)
+	require.Equal(t, int32(10255), resource.Properties.Port)
+	require.Equal(t, "Deployment", resource.Properties.Status.OutputResources[0]["LocalID"])
+	require.Equal(t, resourceType, resource.Properties.Status.OutputResources[0]["ResourceType"])
+}
+
 func TestMongoDatabase_ConvertFromValidation(t *testing.T) {
 	validationTests := []struct {
 		src conv.DataModelInterface
diff --git a/pkg/connectorrp/api/v20220315privatepreview/rabbitmq_conversion_test.go b/pkg/connectorrp/api/v20220315privatepreview/rabbitmq_conversion_test.go
index 7b0ca392f..1c1adf142 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/rabbitmq_conversion_test.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/rabbitmq_conversion_test.go
@@ -75,6 +75,66 @@ func TestRabbitMQMessageQueue_ConvertDataModelToVersioned(t *testing.T) {
 		}
 	}
 }
+
+func TestRabbitMQMessageQueueResponse_ConvertVersionedToDataModel(t *testing.T) {
+	testset := []string{"rabbitmqresource.json", "rabbitmqresource2.json"}
+	for _, payload := range testset {
+
+		// arrange
+		rawPayload := loadTestData(payload)
+		versionedResource := &RabbitMQMessageQueueResource{}
+		err := json.Unmarshal(rawPayload, versionedResource)
+		require.NoError(t, err)
+
+		// act
+		dm, err := versionedResource.ConvertTo()
+		resourceType := map[string]interface{}{"Provider": "rabbitmqProvider", "Type": "rabbitmq"}
+
+		// assert
+		require.NoError(t, err)
+		convertedResource := dm.(*datamodel.RabbitMQMessageQueue)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/rabbitMQMessageQueues/rabbitmq0", convertedResource.ID)
+		require.Equal(t, "rabbitmq0", convertedResource.Name)
+		require.Equal(t, "Applications.Connector/rabbitMQMessageQueues", convertedResource.Type)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", convertedResource.Properties.Application)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", convertedResource.Properties.Environment)
+		require.Equal(t, "testQueue", convertedResource.Properties.Queue)
+		require.Equal(t, "2022-03-15-privatepreview", convertedResource.InternalMetadata.UpdatedAPIVersion)
+		if payload == "rabbitmqresource.json" {
+			require.Equal(t, "Deployment", convertedResource.Properties.Status.OutputResources[0]["LocalID"])
+			require.Equal(t, resourceType, convertedResource.Properties.Status.OutputResources[0]["ResourceType"])
+		}
+	}
+}
+
+func TestRabbitMQMessageQueueResponse_ConvertDataModelToVersioned(t *testing.T) {
+	testset := []string{"rabbitmqresponseresourcedatamodel.json", "rabbitmqresourcedatamodel2.json"}
+	for _, payload := range testset {
+		// arrange
+		rawPayload := loadTestData(payload)
+		resource := &datamodel.RabbitMQMessageQueue{}
+		err := json.Unmarshal(rawPayload, resource)
+		require.NoError(t, err)
+
+		// act
+		versionedResource := &RabbitMQMessageQueueResource{}
+		err = versionedResource.ConvertFrom(resource)
+
+		resourceType := map[string]interface{}{"Provider": "rabbitmqProvider", "Type": "rabbitmq"}
+		// assert
+		require.NoError(t, err)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/rabbitMQMessageQueues/rabbitmq0", resource.ID)
+		require.Equal(t, "rabbitmq0", resource.Name)
+		require.Equal(t, "Applications.Connector/rabbitMQMessageQueues", resource.Type)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", resource.Properties.Application)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", resource.Properties.Environment)
+		require.Equal(t, "testQueue", resource.Properties.Queue)
+		if payload == "rabbitmqresponseresourcedatamodel.json" {
+			require.Equal(t, "Deployment", resource.Properties.Status.OutputResources[0]["LocalID"])
+			require.Equal(t, resourceType, resource.Properties.Status.OutputResources[0]["ResourceType"])
+		}
+	}
+}
 func TestRabbitMQMessageQueue_ConvertFromValidation(t *testing.T) {
 	validationTests := []struct {
 		src conv.DataModelInterface
diff --git a/pkg/connectorrp/api/v20220315privatepreview/rediscache_conversion_test.go b/pkg/connectorrp/api/v20220315privatepreview/rediscache_conversion_test.go
index 48430f0fa..c3c865d5a 100644
--- a/pkg/connectorrp/api/v20220315privatepreview/rediscache_conversion_test.go
+++ b/pkg/connectorrp/api/v20220315privatepreview/rediscache_conversion_test.go
@@ -81,6 +81,69 @@ func TestRedisCache_ConvertDataModelToVersioned(t *testing.T) {
 	}
 }
 
+func TestRedisCacheResponse_ConvertVersionedToDataModel(t *testing.T) {
+	testset := []string{"rediscacheresource.json", "rediscacheresource2.json"}
+	for _, payload := range testset {
+		// arrange
+		rawPayload := loadTestData(payload)
+		versionedResource := &RedisCacheResource{}
+		err := json.Unmarshal(rawPayload, versionedResource)
+		require.NoError(t, err)
+
+		// act
+		dm, err := versionedResource.ConvertTo()
+
+		resourceType := map[string]interface{}{"Provider": "azure", "Type": "azure.redis"}
+		// assert
+		require.NoError(t, err)
+		convertedResource := dm.(*datamodel.RedisCache)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/redisCaches/redis0", convertedResource.ID)
+		require.Equal(t, "redis0", convertedResource.Name)
+		require.Equal(t, "Applications.Connector/redisCaches", convertedResource.Type)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", convertedResource.Properties.Application)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", convertedResource.Properties.Environment)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Microsoft.Cache/Redis/testCache", convertedResource.Properties.Resource)
+		require.Equal(t, "myrediscache.redis.cache.windows.net", convertedResource.Properties.Host)
+		require.Equal(t, int32(10255), convertedResource.Properties.Port)
+		require.Equal(t, "2022-03-15-privatepreview", convertedResource.InternalMetadata.UpdatedAPIVersion)
+		if payload == "rediscacheresource.json" {
+			require.Equal(t, "Deployment", convertedResource.Properties.Status.OutputResources[0]["LocalID"])
+			require.Equal(t, resourceType, convertedResource.Properties.Status.OutputResources[0]["ResourceType"])
+		}
+	}
+}
+
+func TestRedisCacheResponse_ConvertDataModelToVersioned(t *testing.T) {
+	testset := []string{"rediscacheresourcedatamodel.json", "rediscacheresourcedatamodel2.json"}
+	for _, payload := range testset {
+		// arrange
+		rawPayload := loadTestData(payload)
+		resource := &datamodel.RedisCache{}
+		err := json.Unmarshal(rawPayload, resource)
+		require.NoError(t, err)
+
+		// act
+		versionedResource := &RedisCacheResource{}
+		err = versionedResource.ConvertFrom(resource)
+
+		resourceType := map[string]interface{}{"Provider": "azure", "Type": "azure.redis"}
+		// assert
+		require.NoError(t, err)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/redisCaches/redis0", resource.ID)
+		require.Equal(t, "redis0", resource.Name)
+		require.Equal(t, "Applications.Connector/redisCaches", resource.Type)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication", resource.Properties.Application)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0", resource.Properties.Environment)
+		require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Microsoft.Cache/Redis/testCache", resource.Properties.Resource)
+		require.Equal(t, "myrediscache.redis.cache.windows.net", resource.Properties.Host)
+		require.Equal(t, int32(10255), resource.Properties.Port)
+		if payload == "rediscacheresourcedatamodel.json" {
+			require.Equal(t, "Deployment", resource.Properties.Status.OutputResources[0]["LocalID"])
+			require.Equal(t, resourceType, resource.Properties.Status.OutputResources[0]["ResourceType"])
+		}
+	}
+}
+
 func TestRedisCache_ConvertFromValidation(t *testing.T) {
 	validationTests := []struct {
 		src conv.DataModelInterface
diff --git a/pkg/connectorrp/api/v20220315privatepreview/testdata/mongodatabaseresponseresourcedatamodel.json b/pkg/connectorrp/api/v20220315privatepreview/testdata/mongodatabaseresponseresourcedatamodel.json
new file mode 100644
index 000000000..11ceef142
--- /dev/null
+++ b/pkg/connectorrp/api/v20220315privatepreview/testdata/mongodatabaseresponseresourcedatamodel.json
@@ -0,0 +1,32 @@
+{
+    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/mongoDatabases/mongo0",
+    "name": "mongo0",
+    "type": "Applications.Connector/mongoDatabases",
+    "systemData": {
+        "createdBy": "fakeid@live.com",
+        "createdByType": "User",
+        "createdAt": "2021-09-24T19:09:54.2403864Z",
+        "lastModifiedBy": "fakeid@live.com",
+        "lastModifiedByType": "User",
+        "lastModifiedAt": "2021-09-24T20:09:54.2403864Z"
+    },
+    "tags": {
+        "env": "dev"
+    },
+    "properties": {
+        "status": {
+            "outputResources": [{
+              "LocalID": "Deployment",
+              "ResourceType": {
+                "Type": "azure.cosmosdb.mongo",
+                "Provider": "azure"
+              }
+            }]
+        },
+        "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0",
+        "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication",
+        "resource": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Microsoft.DocumentDB/databaseAccounts/testAccount/mongodbDatabases/db",
+        "host": "testAccount1.mongo.cosmos.azure.com",
+        "port": 10255
+    }
+}
diff --git a/pkg/connectorrp/api/v20220315privatepreview/testdata/rabbitmqresponseresourcedatamodel.json b/pkg/connectorrp/api/v20220315privatepreview/testdata/rabbitmqresponseresourcedatamodel.json
new file mode 100644
index 000000000..5d4bc60e7
--- /dev/null
+++ b/pkg/connectorrp/api/v20220315privatepreview/testdata/rabbitmqresponseresourcedatamodel.json
@@ -0,0 +1,30 @@
+{
+    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/rabbitMQMessageQueues/rabbitmq0",
+    "name": "rabbitmq0",
+    "type": "Applications.Connector/rabbitMQMessageQueues",
+    "systemData": {
+        "createdBy": "fakeid@live.com",
+        "createdByType": "User",
+        "createdAt": "2021-09-24T19:09:54.2403864Z",
+        "lastModifiedBy": "fakeid@live.com",
+        "lastModifiedByType": "User",
+        "lastModifiedAt": "2021-09-24T20:09:54.2403864Z"
+    },
+    "tags": {
+        "env": "dev"
+    },
+    "properties": {
+        "status": {
+            "outputResources": [{
+              "LocalID": "Deployment",
+              "ResourceType": {
+                "Type": "rabbitmq",
+                "Provider": "rabbitmqProvider"
+              }
+            }]
+        },
+        "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0",
+        "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication",
+        "queue": "testQueue"
+    }
+}
diff --git a/pkg/connectorrp/api/v20220315privatepreview/testdata/rediscacheresponseresourcedatamodel.json b/pkg/connectorrp/api/v20220315privatepreview/testdata/rediscacheresponseresourcedatamodel.json
new file mode 100644
index 000000000..519268569
--- /dev/null
+++ b/pkg/connectorrp/api/v20220315privatepreview/testdata/rediscacheresponseresourcedatamodel.json
@@ -0,0 +1,32 @@
+{
+    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/redisCaches/redis0",
+    "name": "redis0",
+    "type": "Applications.Connector/redisCaches",
+    "systemData": {
+        "createdBy": "fakeid@live.com",
+        "createdByType": "User",
+        "createdAt": "2021-09-24T19:09:54.2403864Z",
+        "lastModifiedBy": "fakeid@live.com",
+        "lastModifiedByType": "User",
+        "lastModifiedAt": "2021-09-24T20:09:54.2403864Z"
+    },
+    "tags": {
+        "env": "dev"
+    },
+    "properties": {
+        "status": {
+            "outputResources": [{
+              "LocalID": "Deployment",
+              "ResourceType": {
+                "Type": "azure.redis",
+                "Provider": "azure"
+              }
+            }]
+        },
+        "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/env0",
+        "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/testApplication",
+        "resource": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Microsoft.Cache/Redis/testCache",
+        "host": "myrediscache.redis.cache.windows.net",
+        "port": 10255
+    }
+}
diff --git a/pkg/connectorrp/datamodel/converter/mongodatabase_converter_test.go b/pkg/connectorrp/datamodel/converter/mongodatabase_converter_test.go
index 3ae425bb4..b788a1dd4 100644
--- a/pkg/connectorrp/datamodel/converter/mongodatabase_converter_test.go
+++ b/pkg/connectorrp/datamodel/converter/mongodatabase_converter_test.go
@@ -52,7 +52,7 @@ func TestMongoDatabaseDataModelToVersioned(t *testing.T) {
 			c := loadTestData(tc.dataModelFile)
 			dm := &datamodel.MongoDatabase{}
 			_ = json.Unmarshal(c, dm)
-			am, err := MongoDatabaseDataModelToVersioned(dm, tc.apiVersion)
+			am, err := MongoDatabaseDataModelToVersioned(dm, tc.apiVersion, true)
 			if tc.err != nil {
 				require.ErrorAs(t, tc.err, &err)
 			} else {
@@ -100,6 +100,42 @@ func TestMongoDatabaseDataModelFromVersioned(t *testing.T) {
 	}
 }
 
+func TestMongoDatabaseResponseDataModelToVersioned(t *testing.T) {
+	testset := []struct {
+		dataModelFile string
+		apiVersion    string
+		apiModelType  interface{}
+		err           error
+	}{
+		{
+			"../../api/v20220315privatepreview/testdata/mongodatabaseresponseresourcedatamodel.json",
+			"2022-03-15-privatepreview",
+			&v20220315privatepreview.MongoDatabaseResponseResource{},
+			nil,
+		},
+		{
+			"",
+			"unsupported",
+			nil,
+			v1.ErrUnsupportedAPIVersion,
+		},
+	}
+
+	for _, tc := range testset {
+		t.Run(tc.apiVersion, func(t *testing.T) {
+			c := loadTestData(tc.dataModelFile)
+			dm := &datamodel.MongoDatabaseResponse{}
+			_ = json.Unmarshal(c, dm)
+			am, err := MongoDatabaseDataModelToVersioned(dm, tc.apiVersion, false)
+			if tc.err != nil {
+				require.ErrorAs(t, tc.err, &err)
+			} else {
+				require.NoError(t, err)
+				require.IsType(t, tc.apiModelType, am)
+			}
+		})
+	}
+}
 func TestMongoDatabaseSecretsDataModelToVersioned(t *testing.T) {
 	testset := []struct {
 		dataModelFile string
diff --git a/pkg/connectorrp/datamodel/converter/rabbitmq_converter_test.go b/pkg/connectorrp/datamodel/converter/rabbitmq_converter_test.go
index 6366c9a57..6a53f37c0 100644
--- a/pkg/connectorrp/datamodel/converter/rabbitmq_converter_test.go
+++ b/pkg/connectorrp/datamodel/converter/rabbitmq_converter_test.go
@@ -43,7 +43,44 @@ func TestRabbitMQMessageQueueDataModelToVersioned(t *testing.T) {
 			c := loadTestData(tc.dataModelFile)
 			dm := &datamodel.RabbitMQMessageQueue{}
 			_ = json.Unmarshal(c, dm)
-			am, err := RabbitMQMessageQueueDataModelToVersioned(dm, tc.apiVersion)
+			am, err := RabbitMQMessageQueueDataModelToVersioned(dm, tc.apiVersion, true)
+			if tc.err != nil {
+				require.ErrorAs(t, tc.err, &err)
+			} else {
+				require.NoError(t, err)
+				require.IsType(t, tc.apiModelType, am)
+			}
+		})
+	}
+}
+
+func TestRabbitMQMessageQueueResponseDataModelToVersioned(t *testing.T) {
+	testset := []struct {
+		dataModelFile string
+		apiVersion    string
+		apiModelType  interface{}
+		err           error
+	}{
+		{
+			"../../api/v20220315privatepreview/testdata/rabbitmqresponseresourcedatamodel.json",
+			"2022-03-15-privatepreview",
+			&v20220315privatepreview.RabbitMQMessageQueueResponseResource{},
+			nil,
+		},
+		{
+			"",
+			"unsupported",
+			nil,
+			v1.ErrUnsupportedAPIVersion,
+		},
+	}
+
+	for _, tc := range testset {
+		t.Run(tc.apiVersion, func(t *testing.T) {
+			c := loadTestData(tc.dataModelFile)
+			dm := &datamodel.RabbitMQMessageQueueResponse{}
+			_ = json.Unmarshal(c, dm)
+			am, err := RabbitMQMessageQueueDataModelToVersioned(dm, tc.apiVersion, false)
 			if tc.err != nil {
 				require.ErrorAs(t, tc.err, &err)
 			} else {
diff --git a/pkg/connectorrp/datamodel/converter/rediscache_converter_test.go b/pkg/connectorrp/datamodel/converter/rediscache_converter_test.go
index c49c0e2a7..9a11e24cc 100644
--- a/pkg/connectorrp/datamodel/converter/rediscache_converter_test.go
+++ b/pkg/connectorrp/datamodel/converter/rediscache_converter_test.go
@@ -43,7 +43,44 @@ func TestRedisCacheDataModelToVersioned(t *testing.T) {
 			c := loadTestData(tc.dataModelFile)
 			dm := &datamodel.RedisCache{}
 			_ = json.Unmarshal(c, dm)
-			am, err := RedisCacheDataModelToVersioned(dm, tc.apiVersion)
+			am, err := RedisCacheDataModelToVersioned(dm, tc.apiVersion, true)
+			if tc.err != nil {
+				require.ErrorAs(t, tc.err, &err)
+			} else {
+				require.NoError(t, err)
+				require.IsType(t, tc.apiModelType, am)
+			}
+		})
+	}
+}
+
+func TestRedisCacheResponseDataModelToVersioned(t *testing.T) {
+	testset := []struct {
+		dataModelFile string
+		apiVersion    string
+		apiModelType  interface{}
+		err           error
+	}{
+		{
+			"../../api/v20220315privatepreview/testdata/rediscacheresponseresourcedatamodel.json",
+			"2022-03-15-privatepreview",
+			&v20220315privatepreview.RedisCacheResponseResource{},
+			nil,
+		},
+		{
+			"",
+			"unsupported",
+			nil,
+			v1.ErrUnsupportedAPIVersion,
+		},
+	}
+
+	for _, tc := range testset {
+		t.Run(tc.apiVersion, func(t *testing.T) {
+			c := loadTestData(tc.dataModelFile)
+			dm := &datamodel.RedisCacheResponse{}
+			_ = json.Unmarshal(c, dm)
+			am, err := RedisCacheDataModelToVersioned(dm, tc.apiVersion, false)
 			if tc.err != nil {
 				require.ErrorAs(t, tc.err, &err)
 			} else {
diff --git a/pkg/connectorrp/frontend/controller/daprinvokehttproutes/testdata.go b/pkg/connectorrp/frontend/controller/daprinvokehttproutes/v20220315privatepreview_test.go
similarity index 100%
rename from pkg/connectorrp/frontend/controller/daprinvokehttproutes/testdata.go
rename to pkg/connectorrp/frontend/controller/daprinvokehttproutes/v20220315privatepreview_test.go
diff --git a/pkg/connectorrp/frontend/controller/daprpubsubbrokers/testdata.go b/pkg/connectorrp/frontend/controller/daprpubsubbrokers/v20220315privatepreview_test.go
similarity index 100%
rename from pkg/connectorrp/frontend/controller/daprpubsubbrokers/testdata.go
rename to pkg/connectorrp/frontend/controller/daprpubsubbrokers/v20220315privatepreview_test.go
diff --git a/pkg/connectorrp/frontend/controller/daprsecretstores/testdata.go b/pkg/connectorrp/frontend/controller/daprsecretstores/v20220315privatepreview_test.go
similarity index 100%
rename from pkg/connectorrp/frontend/controller/daprsecretstores/testdata.go
rename to pkg/connectorrp/frontend/controller/daprsecretstores/v20220315privatepreview_test.go
diff --git a/pkg/connectorrp/frontend/controller/daprstatestores/testdata.go b/pkg/connectorrp/frontend/controller/daprstatestores/v20220315privatepreview_test.go
similarity index 100%
rename from pkg/connectorrp/frontend/controller/daprstatestores/testdata.go
rename to pkg/connectorrp/frontend/controller/daprstatestores/v20220315privatepreview_test.go
diff --git a/pkg/connectorrp/frontend/controller/extenders/createorupdateextender_test.go b/pkg/connectorrp/frontend/controller/extenders/createorupdateextender_test.go
new file mode 100644
index 000000000..07b6ed867
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/createorupdateextender_test.go
@@ -0,0 +1,159 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	"github.com/project-radius/radius/pkg/connectorrp/api/v20220315privatepreview"
+	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+	"github.com/project-radius/radius/pkg/ucp/store"
+	"github.com/stretchr/testify/require"
+)
+
+func TestCreateOrUpdateExtender_20220315PrivatePreview(t *testing.T) {
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
+
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
+
+	createNewResourceTestCases := []struct {
+		desc               string
+		headerKey          string
+		headerValue        string
+		resourceETag       string
+		expectedStatusCode int
+		shouldFail         bool
+	}{
+		{"create-new-resource-no-if-match", "If-Match", "", "", http.StatusOK, false},
+		{"create-new-resource-*-if-match", "If-Match", "*", "", http.StatusPreconditionFailed, true},
+		{"create-new-resource-etag-if-match", "If-Match", "random-etag", "", http.StatusPreconditionFailed, true},
+		{"create-new-resource-*-if-none-match", "If-None-Match", "*", "", http.StatusOK, false},
+	}
+
+	for _, testcase := range createNewResourceTestCases {
+		t.Run(testcase.desc, func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+			input, dataModel, expectedOutput := getTestModels20220315privatepreview()
+			w := httptest.NewRecorder()
+			req, _ := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodGet, testHeaderfile, input)
+			req.Header.Set(testcase.headerKey, testcase.headerValue)
+			ctx := radiustesting.ARMTestContextFromRequest(req)
+
+			mds.
+				EXPECT().
+				Get(gomock.Any(), gomock.Any()).
+				DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+					return nil, &store.ErrNotFound{}
+				})
+
+			expectedOutput.SystemData.CreatedAt = expectedOutput.SystemData.LastModifiedAt
+			expectedOutput.SystemData.CreatedBy = expectedOutput.SystemData.LastModifiedBy
+			expectedOutput.SystemData.CreatedByType = expectedOutput.SystemData.LastModifiedByType
+
+			if !testcase.shouldFail {
+				mds.
+					EXPECT().
+					Save(gomock.Any(), gomock.Any(), gomock.Any()).
+					DoAndReturn(func(ctx context.Context, obj *store.Object, opts ...store.SaveOptions) error {
+						obj.ETag = "new-resource-etag"
+						obj.Data = dataModel
+						return nil
+					})
+			}
+
+			ctl, err := NewCreateOrUpdateExtender(mds, msm)
+			require.NoError(t, err)
+			resp, err := ctl.Run(ctx, req)
+			require.NoError(t, err)
+			_ = resp.Apply(ctx, w, req)
+			require.Equal(t, testcase.expectedStatusCode, w.Result().StatusCode)
+
+			if !testcase.shouldFail {
+				actualOutput := &v20220315privatepreview.ExtenderResource{}
+				_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
+				require.Equal(t, expectedOutput, actualOutput)
+
+				require.Equal(t, "new-resource-etag", w.Header().Get("ETag"))
+			}
+		})
+	}
+
+	updateExistingResourceTestCases := []struct {
+		desc               string
+		headerKey          string
+		headerValue        string
+		resourceETag       string
+		expectedStatusCode int
+		shouldFail         bool
+	}{
+		{"update-resource-no-if-match", "If-Match", "", "resource-etag", http.StatusOK, false},
+		{"update-resource-*-if-match", "If-Match", "*", "resource-etag", http.StatusOK, false},
+		{"update-resource-matching-if-match", "If-Match", "matching-etag", "matching-etag", http.StatusOK, false},
+		{"update-resource-not-matching-if-match", "If-Match", "not-matching-etag", "another-etag", http.StatusPreconditionFailed, true},
+		{"update-resource-*-if-none-match", "If-None-Match", "*", "another-etag", http.StatusPreconditionFailed, true},
+	}
+
+	for _, testcase := range updateExistingResourceTestCases {
+		t.Run(testcase.desc, func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+			input, dataModel, expectedOutput := getTestModels20220315privatepreview()
+			w := httptest.NewRecorder()
+			req, _ := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodGet, testHeaderfile, input)
+			req.Header.Set(testcase.headerKey, testcase.headerValue)
+			ctx := radiustesting.ARMTestContextFromRequest(req)
+
+			mds.
+				EXPECT().
+				Get(gomock.Any(), gomock.Any()).
+				DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+					return &store.Object{
+						Metadata: store.Metadata{ID: id, ETag: testcase.resourceETag},
+						Data:     dataModel,
+					}, nil
+				})
+
+			if !testcase.shouldFail {
+				mds.
+					EXPECT().
+					Save(gomock.Any(), gomock.Any(), gomock.Any()).
+					DoAndReturn(func(ctx context.Context, obj *store.Object, opts ...store.SaveOptions) error {
+						obj.ETag = "updated-resource-etag"
+						obj.Data = dataModel
+						return nil
+					})
+			}
+
+			ctl, err := NewCreateOrUpdateExtender(mds, msm)
+			require.NoError(t, err)
+			resp, err := ctl.Run(ctx, req)
+			_ = resp.Apply(ctx, w, req)
+			require.NoError(t, err)
+			require.Equal(t, testcase.expectedStatusCode, w.Result().StatusCode)
+
+			if !testcase.shouldFail {
+				actualOutput := &v20220315privatepreview.ExtenderResource{}
+				_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
+				require.Equal(t, expectedOutput, actualOutput)
+
+				require.Equal(t, "updated-resource-etag", w.Header().Get("ETag"))
+			}
+		})
+	}
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/deleteextender_test.go b/pkg/connectorrp/frontend/controller/extenders/deleteextender_test.go
new file mode 100644
index 000000000..f02e159ce
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/deleteextender_test.go
@@ -0,0 +1,142 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+	"github.com/project-radius/radius/pkg/radrp/armerrors"
+	"github.com/project-radius/radius/pkg/ucp/store"
+	"github.com/stretchr/testify/require"
+)
+
+func TestDeleteExtender_20220315PrivatePreview(t *testing.T) {
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
+
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
+
+	t.Parallel()
+
+	t.Run("delete non-existing resource", func(t *testing.T) {
+		teardownTest, mds, msm := setupTest(t)
+		defer teardownTest(t)
+		w := httptest.NewRecorder()
+		req, _ := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodDelete, testHeaderfile, nil)
+		ctx := radiustesting.ARMTestContextFromRequest(req)
+
+		mds.
+			EXPECT().
+			Get(gomock.Any(), gomock.Any()).
+			DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+				return nil, &store.ErrNotFound{}
+			})
+
+		ctl, err := NewDeleteExtender(mds, msm)
+
+		require.NoError(t, err)
+		resp, err := ctl.Run(ctx, req)
+		require.NoError(t, err)
+		err = resp.Apply(ctx, w, req)
+		require.NoError(t, err)
+
+		result := w.Result()
+		require.Equal(t, http.StatusNoContent, result.StatusCode)
+
+		body := result.Body
+		defer body.Close()
+		payload, err := ioutil.ReadAll(body)
+		require.NoError(t, err)
+		require.Empty(t, payload, "response body should be empty")
+	})
+
+	existingResourceDeleteTestCases := []struct {
+		desc               string
+		ifMatchETag        string
+		resourceETag       string
+		expectedStatusCode int
+		shouldFail         bool
+	}{
+		{"delete-existing-resource-no-if-match", "", "random-etag", http.StatusOK, false},
+		{"delete-not-existing-resource-no-if-match", "", "", http.StatusNoContent, true},
+		{"delete-existing-resource-matching-if-match", "matching-etag", "matching-etag", http.StatusOK, false},
+		{"delete-existing-resource-not-matching-if-match", "not-matching-etag", "another-etag", http.StatusPreconditionFailed, true},
+		{"delete-not-existing-resource-*-if-match", "*", "", http.StatusNoContent, true},
+		{"delete-existing-resource-*-if-match", "*", "random-etag", http.StatusOK, false},
+	}
+
+	for _, testcase := range existingResourceDeleteTestCases {
+		t.Run(testcase.desc, func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+			w := httptest.NewRecorder()
+
+			req, _ := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodDelete, testHeaderfile, nil)
+			req.Header.Set("If-Match", testcase.ifMatchETag)
+
+			ctx := radiustesting.ARMTestContextFromRequest(req)
+			_, extenderDataModel, _ := getTestModels20220315privatepreview()
+
+			mds.
+				EXPECT().
+				Get(gomock.Any(), gomock.Any()).
+				DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+					return &store.Object{
+						Metadata: store.Metadata{ID: id, ETag: testcase.resourceETag},
+						Data:     extenderDataModel,
+					}, nil
+				})
+
+			if !testcase.shouldFail {
+				mds.
+					EXPECT().
+					Delete(gomock.Any(), gomock.Any()).
+					DoAndReturn(func(ctx context.Context, id string, _ ...store.DeleteOptions) error {
+						return nil
+					})
+			}
+
+			ctl, err := NewDeleteExtender(mds, msm)
+			require.NoError(t, err)
+			resp, err := ctl.Run(ctx, req)
+			require.NoError(t, err)
+			err = resp.Apply(ctx, w, req)
+			require.NoError(t, err)
+
+			result := w.Result()
+			require.Equal(t, testcase.expectedStatusCode, result.StatusCode)
+
+			body := result.Body
+			defer body.Close()
+			payload, err := ioutil.ReadAll(body)
+			require.NoError(t, err)
+
+			if result.StatusCode == http.StatusOK || result.StatusCode == http.StatusNoContent {
+				// We return either 200 or 204 without a response body for success.
+				require.Empty(t, payload, "response body should be empty")
+			} else {
+				armerr := armerrors.ErrorResponse{}
+				err = json.Unmarshal(payload, &armerr)
+				require.NoError(t, err)
+				require.Equal(t, armerrors.PreconditionFailed, armerr.Error.Code)
+				require.NotEmpty(t, armerr.Error.Target)
+			}
+		})
+	}
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/getextender_test.go b/pkg/connectorrp/frontend/controller/extenders/getextender_test.go
new file mode 100644
index 000000000..815125911
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/getextender_test.go
@@ -0,0 +1,91 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+	"github.com/project-radius/radius/pkg/ucp/store"
+	"github.com/stretchr/testify/require"
+
+	"github.com/project-radius/radius/pkg/connectorrp/api/v20220315privatepreview"
+)
+
+func TestGetExtender_20220315PrivatePreview(t *testing.T) {
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
+
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
+	ctx := context.Background()
+
+	_, extenderDataModel, expectedOutput := getTestModels20220315privatepreview()
+
+	t.Run("get non-existing resource", func(t *testing.T) {
+		teardownTest, mds, msm := setupTest(t)
+		defer teardownTest(t)
+		w := httptest.NewRecorder()
+		req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, nil)
+		ctx := radiustesting.ARMTestContextFromRequest(req)
+
+		mds.
+			EXPECT().
+			Get(gomock.Any(), gomock.Any()).
+			DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+				return nil, &store.ErrNotFound{}
+			})
+
+		ctl, err := NewGetExtender(mds, msm)
+
+		require.NoError(t, err)
+		resp, err := ctl.Run(ctx, req)
+		require.NoError(t, err)
+		_ = resp.Apply(ctx, w, req)
+		require.Equal(t, 404, w.Result().StatusCode)
+	})
+
+	t.Run("get existing resource", func(t *testing.T) {
+		teardownTest, mds, msm := setupTest(t)
+		defer teardownTest(t)
+		w := httptest.NewRecorder()
+		req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, nil)
+		ctx := radiustesting.ARMTestContextFromRequest(req)
+
+		mds.
+			EXPECT().
+			Get(gomock.Any(), gomock.Any()).
+			DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+				return &store.Object{
+					Metadata: store.Metadata{ID: id},
+					Data:     extenderDataModel,
+				}, nil
+			})
+
+		ctl, err := NewGetExtender(mds, msm)
+
+		require.NoError(t, err)
+		resp, err := ctl.Run(ctx, req)
+		require.NoError(t, err)
+		_ = resp.Apply(ctx, w, req)
+		require.Equal(t, 200, w.Result().StatusCode)
+
+		actualOutput := &v20220315privatepreview.ExtenderResource{}
+		_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
+
+		require.Equal(t, expectedOutput, actualOutput)
+	})
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/listextenders_test.go b/pkg/connectorrp/frontend/controller/extenders/listextenders_test.go
new file mode 100644
index 000000000..1bd37d37e
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/listextenders_test.go
@@ -0,0 +1,141 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/google/uuid"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+	"github.com/project-radius/radius/pkg/ucp/store"
+	"github.com/stretchr/testify/require"
+
+	"github.com/project-radius/radius/pkg/connectorrp/api/v20220315privatepreview"
+)
+
+func TestListExtendersRun_20220315PrivatePreview(t *testing.T) {
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
+
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
+	ctx := context.Background()
+
+	_, extenderDataModel, expectedOutput := getTestModels20220315privatepreview()
+
+	t.Run("empty list", func(t *testing.T) {
+		teardownTest, mds, msm := setupTest(t)
+		defer teardownTest(t)
+		w := httptest.NewRecorder()
+		req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, nil)
+		ctx := radiustesting.ARMTestContextFromRequest(req)
+
+		mds.
+			EXPECT().
+			Query(gomock.Any(), gomock.Any(), gomock.Any()).
+			DoAndReturn(func(ctx context.Context, query store.Query, options ...store.QueryOptions) (*store.ObjectQueryResult, error) {
+				return &store.ObjectQueryResult{
+					Items: []store.Object{},
+				}, nil
+			})
+
+		ctl, err := NewListExtenders(mds, msm)
+
+		require.NoError(t, err)
+		resp, err := ctl.Run(ctx, req)
+		require.NoError(t, err)
+		_ = resp.Apply(ctx, w, req)
+		require.Equal(t, http.StatusOK, w.Result().StatusCode)
+
+		actualOutput := &v20220315privatepreview.ExtenderList{}
+		_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
+		require.Equal(t, 0, len(actualOutput.Value))
+		require.Nil(t, actualOutput.NextLink)
+	})
+
+	testCases := []struct {
+		description   string
+		extenderCount int
+		batchCount    int
+		max           string
+		skipToken     bool
+	}{
+		{"list-extender-more-items-than-max", 10, 5, "5", true},
+		{"list-extender-less-items-than-max", 5, 5, "10", false},
+		{"list-extender-no-max", 5, 5, "", false},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(fmt.Sprint(testCase.description), func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+			w := httptest.NewRecorder()
+			req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, nil)
+
+			q := req.URL.Query()
+			q.Add("top", testCase.max)
+			req.URL.RawQuery = q.Encode()
+
+			ctx := radiustesting.ARMTestContextFromRequest(req)
+
+			paginationToken := ""
+			if testCase.skipToken {
+				paginationToken = "nextLink"
+			}
+
+			items := []store.Object{}
+			for i := 0; i < testCase.batchCount; i++ {
+				item := store.Object{
+					Metadata: store.Metadata{
+						ID: uuid.New().String(),
+					},
+					Data: extenderDataModel,
+				}
+				items = append(items, item)
+			}
+
+			mds.
+				EXPECT().
+				Query(gomock.Any(), gomock.Any(), gomock.Any()).
+				DoAndReturn(func(ctx context.Context, query store.Query, options ...store.QueryOptions) (*store.ObjectQueryResult, error) {
+					return &store.ObjectQueryResult{
+						Items:           items,
+						PaginationToken: paginationToken,
+					}, nil
+				})
+
+			ctl, err := NewListExtenders(mds, msm)
+
+			require.NoError(t, err)
+			resp, err := ctl.Run(ctx, req)
+			require.NoError(t, err)
+			_ = resp.Apply(ctx, w, req)
+			require.Equal(t, http.StatusOK, w.Result().StatusCode)
+
+			actualOutput := &v20220315privatepreview.ExtenderList{}
+			_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
+			require.Equal(t, testCase.batchCount, len(actualOutput.Value))
+			require.Equal(t, expectedOutput, actualOutput.Value[0])
+
+			if testCase.skipToken {
+				require.NotNil(t, actualOutput.NextLink)
+			} else {
+				require.Nil(t, actualOutput.NextLink)
+			}
+		})
+	}
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/listsecretsextender_test.go b/pkg/connectorrp/frontend/controller/extenders/listsecretsextender_test.go
new file mode 100644
index 000000000..83dda3d43
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/listsecretsextender_test.go
@@ -0,0 +1,115 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package extenders
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+	"github.com/project-radius/radius/pkg/ucp/store"
+	"github.com/stretchr/testify/require"
+
+	"github.com/project-radius/radius/pkg/connectorrp/api/v20220315privatepreview"
+)
+
+func TestListSecrets_20220315PrivatePreview(t *testing.T) {
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
+
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
+	ctx := context.Background()
+
+	_, extenderDataModel, _ := getTestModels20220315privatepreview()
+
+	t.Run("listSecrets non-existing resource", func(t *testing.T) {
+		teardownTest, mds, msm := setupTest(t)
+		defer teardownTest(t)
+		w := httptest.NewRecorder()
+		req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, nil)
+		ctx := radiustesting.ARMTestContextFromRequest(req)
+
+		mds.
+			EXPECT().
+			Get(gomock.Any(), gomock.Any()).
+			DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+				return nil, &store.ErrNotFound{}
+			})
+
+		ctl, err := NewListSecretsExtender(mds, msm)
+
+		require.NoError(t, err)
+		resp, err := ctl.Run(ctx, req)
+		require.NoError(t, err)
+		_ = resp.Apply(ctx, w, req)
+		require.Equal(t, 404, w.Result().StatusCode)
+	})
+
+	t.Run("listSecrets existing resource", func(t *testing.T) {
+		teardownTest, mds, msm := setupTest(t)
+		defer teardownTest(t)
+		w := httptest.NewRecorder()
+		req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, nil)
+		ctx := radiustesting.ARMTestContextFromRequest(req)
+
+		mds.
+			EXPECT().
+			Get(gomock.Any(), gomock.Any()).
+			DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+				return &store.Object{
+					Metadata: store.Metadata{ID: id},
+					Data:     extenderDataModel,
+				}, nil
+			})
+
+		ctl, err := NewListSecretsExtender(mds, msm)
+
+		require.NoError(t, err)
+		resp, err := ctl.Run(ctx, req)
+		require.NoError(t, err)
+		_ = resp.Apply(ctx, w, req)
+		require.Equal(t, 200, w.Result().StatusCode)
+
+		actualOutput := &v20220315privatepreview.ExtenderResource{}
+		_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
+
+		// TODO update to expect secrets values after controller is integrated with backend.
+		// require.Equal(t, expectedOutput.Properties.Secrets, actualOutput)
+		require.Equal(t, &v20220315privatepreview.ExtenderResource{}, actualOutput)
+	})
+
+	t.Run("listSecrets error retrieving resource", func(t *testing.T) {
+		teardownTest, mds, msm := setupTest(t)
+		defer teardownTest(t)
+		req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, nil)
+		ctx := radiustesting.ARMTestContextFromRequest(req)
+
+		mds.
+			EXPECT().
+			Get(gomock.Any(), gomock.Any()).
+			DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
+				return nil, errors.New("failed to get the resource from data store")
+			})
+
+		ctl, err := NewListSecretsExtender(mds, msm)
+
+		require.NoError(t, err)
+		_, err = ctl.Run(ctx, req)
+		require.Error(t, err)
+	})
+
+}
diff --git a/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_datamodel.json b/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_datamodel.json
new file mode 100644
index 000000000..cd5344ba7
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_datamodel.json
@@ -0,0 +1,38 @@
+{
+    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/applications.connector/extenders/extender0",
+    "name": "extender0",
+    "type": "applications.connector/extenders",
+    "location": "West US",
+    "systemData": {
+        "createdAt": "2022-03-22T18:54:52.6857175Z",
+        "createdBy": "fake@hotmail.com",
+        "createdByType": "User",
+        "lastModifiedAt": "2022-03-22T18:57:52.6857175Z",
+        "lastModifiedBy": "fake@hotmail.com",
+        "lastModifiedByType": "User"
+    },
+    "properties": {
+      "status": {
+        "outputResources": [{
+          "LocalID": "Deployment",
+          "ResourceType": {
+            "Type": "extenderType",
+            "Provider": "extenderProvider"
+          }
+        }]
+      },
+      "provisioningState": "Succeeded",
+      "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/applications/testApplication",
+      "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/environments/env0",
+      "fromNumber": "222-222-2222",
+      "secrets": {
+          "accountSid": "sid",
+          "authToken:": "token"
+      }
+    },
+    "tenantId": "00000000-0000-0000-0000-000000000000",
+    "subscriptionId": "00000000-0000-0000-0000-000000000000",
+    "resourceGroup": "radius-test-rg",
+    "createdApiVersion": "2022-03-15-privatepreview",
+    "updatedApiVersion": "2022-03-15-privatepreview"
+}
\ No newline at end of file
diff --git a/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_input.json b/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_input.json
new file mode 100644
index 000000000..e77c45c91
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_input.json
@@ -0,0 +1,21 @@
+{
+    "location": "West US",
+    "properties": {
+      "status": {
+        "outputResources": [{
+          "LocalID": "Deployment",
+          "ResourceType": {
+            "Type": "extenderType",
+            "Provider": "extenderProvider"
+          }
+        }]
+      },
+      "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/applications/testApplication",
+      "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/environments/env0",
+      "fromNumber": "222-222-2222",
+      "secrets": {
+          "accountSid": "sid",
+          "authToken:": "token"
+      }
+    }
+}
\ No newline at end of file
diff --git a/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_output.json b/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_output.json
new file mode 100644
index 000000000..4db77b759
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_output.json
@@ -0,0 +1,34 @@
+{
+    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/applications.connector/extenders/extender0",
+    "location": "West US",
+    "name": "extender0",
+    "properties": {
+        "status": {
+          "outputResources": [{
+            "LocalID": "Deployment",
+            "ResourceType": {
+              "Type": "extenderType",
+              "Provider": "extenderProvider"
+            }
+          }]
+        },
+        "application": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/applications/testApplication",
+        "environment": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup/providers/Applications.Core/environments/env0",
+        "fromNumber": "222-222-2222",
+        "secrets": {
+          "accountSid": "sid",
+          "authToken:": "token"
+        },
+        "provisioningState": "Succeeded"
+    },
+    "systemData": {
+        "createdAt": "2022-03-22T18:54:52.6857175Z",
+        "createdBy": "fake@hotmail.com",
+        "createdByType": "User",
+        "lastModifiedAt": "2022-03-22T18:57:52.6857175Z",
+        "lastModifiedBy": "fake@hotmail.com",
+        "lastModifiedByType": "User"
+    },
+    "tags": {},
+    "type": "applications.connector/extenders"
+}
\ No newline at end of file
diff --git a/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_requestheaders.json b/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_requestheaders.json
new file mode 100644
index 000000000..275c12b6c
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/extenders/testdata/20220315privatepreview_requestheaders.json
@@ -0,0 +1,63 @@
+{
+    "Accept": "application/json",
+    "Accept-Encoding": "gzip, deflate",
+    "Accept-Language": "en-US",
+    "Content-Length": "305",
+    "Content-Type": "application/json; charset=utf-8",
+    "Referer": "https://radius.dev/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/applications.connector/extenders/extender0?api-version=2022-03-15-privatepreview",
+    "Traceparent": "00-000011048df2134ca37c9a689c3a0000-0000000000000000-01",
+    "User-Agent": "ARMClient/1.6.0.0",
+    "Via": "1.1 Azure",
+    "X-Azure-Requestchain": "hops=1",
+    "X-Fd-Clienthttpversion": "1.1",
+    "X-Fd-Clientip": "0000:0000:0000:1:0000:0000:0000:0000",
+    "X-Fd-Edgeenvironment": "fake",
+    "X-Fd-Eventid": "00005A12DDEC4F8B80B65BB768190000",
+    "X-Fd-Impressionguid": "00005A12DDEC4F8B80B65BB768190000",
+    "X-Fd-Originalurl": "https://radius.dev:443/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Connector/extenders/extender0?api-version=2022-03-15-privatepreview",
+    "X-Fd-Partner": "AzureResourceManager_Test",
+    "X-Fd-Ref": "Ref A: xxxx Ref B: xxxx Ref C: 2022-03-22T18:54:50Z",
+    "X-Fd-Revip": "country=United States,iso=us,state=Washington,city=Redmond,zip=00000,tz=-8,asn=0,lat=0,long=-1,countrycf=8,citycf=8",
+    "X-Fd-Routekey": "000075000",
+    "X-Fd-Socketip": "0000:0000:0000:1:0000:0000:0000:0000",
+    "X-Forwarded-For": "192.168.0.10",
+    "X-Forwarded-Host": "radius.dev",
+    "X-Forwarded-Port": "443",
+    "X-Forwarded-Proto": "https",
+    "X-Forwarded-Scheme": "https",
+    "X-Ms-Activity-Vector": "IN.0P",
+    "X-Ms-Arm-Network-Source": "PublicNetwork",
+    "X-Ms-Arm-Request-Tracking-Id": "00000000-0000-0000-0000-000000000000",
+    "X-Ms-Arm-Resource-System-Data": "{\"lastModifiedBy\":\"fake@hotmail.com\",\"lastModifiedByType\":\"User\",\"lastModifiedAt\":\"2022-03-22T18:57:52.6857175Z\"}",
+    "X-Ms-Arm-Service-Request-Id": "00000000-0000-0000-0000-000000000000",
+    "X-Ms-Client-Acr": "1",
+    "X-Ms-Client-Alt-Sec-Id": "1:live.com:0006000017E40000",
+    "X-Ms-Client-App-Id": "00000000-0000-0000-0000-000000000000",
+    "X-Ms-Client-App-Id-Acr": "0",
+    "X-Ms-Client-Audience": "https://management.core.windows.net/",
+    "X-Ms-Client-Authentication-Methods": "pwd",
+    "X-Ms-Client-Authorization-Source": "RoleBased",
+    "X-Ms-Client-Family-Name-Encoded": "fake",
+    "X-Ms-Client-Given-Name-Encoded": "fake",
+    "X-Ms-Client-Identity-Provider": "live.com",
+    "X-Ms-Client-Ip-Address": "192.168.0.10",
+    "X-Ms-Client-Issuer": "https://sts.windows-ppe.net/00000000-0000-0000-0000-000000000000/",
+    "X-Ms-Client-Location": "centralus",
+    "X-Ms-Client-Object-Id": "00000000-0000-0000-0000-000000000000",
+    "X-Ms-Client-Principal-Group-Membership-Source": "Token",
+    "X-Ms-Client-Principal-Id": "000000000000000",
+    "X-Ms-Client-Principal-Name": "live.com#fake@hotmail.com",
+    "X-Ms-Client-Puid": "000000000000000",
+    "X-Ms-Client-Request-Id": "00000000-0000-0000-0000-000000000000",
+    "X-Ms-Client-Scope": "user_impersonation",
+    "X-Ms-Client-Tenant-Id": "00000000-0000-0000-0000-000000000001",
+    "X-Ms-Client-Wids": "00000000-0000-0000-0000-000000000000, 00000000-0000-0000-0000-000000000001",
+    "X-Ms-Correlation-Request-Id": "00000000-0000-0000-0000-000000000000",
+    "X-Ms-Home-Tenant-Id": "00000000-0000-0000-0000-000000000002",
+    "X-Ms-Request-Id": "00000000-0000-0000-0000-000000000000",
+    "X-Ms-Routing-Request-Id": "CENTRALUS:20220322T185452Z:00000000-0000-0000-0000-000000000000",
+    "X-Original-Forwarded-For": "0000:0000:0000:1:449b:f928:e40a:a351",
+    "X-Real-Ip": "192.168.0.10",
+    "X-Request-Id": "1000f6040000000000004bc7d1666424",
+    "X-Scheme": "https"
+}
\ No newline at end of file
diff --git a/pkg/connectorrp/frontend/controller/rediscaches/testdata.go b/pkg/connectorrp/frontend/controller/extenders/v20220315privatepreview_test.go
similarity index 77%
rename from pkg/connectorrp/frontend/controller/rediscaches/testdata.go
rename to pkg/connectorrp/frontend/controller/extenders/v20220315privatepreview_test.go
index f936e15ab..e6314decd 100644
--- a/pkg/connectorrp/frontend/controller/rediscaches/testdata.go
+++ b/pkg/connectorrp/frontend/controller/extenders/v20220315privatepreview_test.go
@@ -3,7 +3,7 @@
 // Licensed under the MIT License.
 // ------------------------------------------------------------
 
-package rediscaches
+package extenders
 
 import (
 	"encoding/json"
@@ -15,17 +15,17 @@ import (
 
 const testHeaderfile = "20220315privatepreview_requestheaders.json"
 
-func getTestModels20220315privatepreview() (input *v20220315privatepreview.RedisCacheResource, dataModel *datamodel.RedisCache, output *v20220315privatepreview.RedisCacheResource) {
+func getTestModels20220315privatepreview() (input *v20220315privatepreview.ExtenderResource, dataModel *datamodel.Extender, output *v20220315privatepreview.ExtenderResource) {
 	rawInput := radiustesting.ReadFixture("20220315privatepreview_input.json")
-	input = &v20220315privatepreview.RedisCacheResource{}
+	input = &v20220315privatepreview.ExtenderResource{}
 	_ = json.Unmarshal(rawInput, input)
 
 	rawDataModel := radiustesting.ReadFixture("20220315privatepreview_datamodel.json")
-	dataModel = &datamodel.RedisCache{}
+	dataModel = &datamodel.Extender{}
 	_ = json.Unmarshal(rawDataModel, dataModel)
 
 	rawExpectedOutput := radiustesting.ReadFixture("20220315privatepreview_output.json")
-	output = &v20220315privatepreview.RedisCacheResource{}
+	output = &v20220315privatepreview.ExtenderResource{}
 	_ = json.Unmarshal(rawExpectedOutput, output)
 
 	return input, dataModel, output
diff --git a/pkg/connectorrp/frontend/controller/mongodatabases/getmongodatabase_test.go b/pkg/connectorrp/frontend/controller/mongodatabases/getmongodatabase_test.go
index 6db992ffa..81613facf 100644
--- a/pkg/connectorrp/frontend/controller/mongodatabases/getmongodatabase_test.go
+++ b/pkg/connectorrp/frontend/controller/mongodatabases/getmongodatabase_test.go
@@ -27,7 +27,7 @@ func TestGetMongoDatabase_20220315PrivatePreview(t *testing.T) {
 	mStorageClient := store.NewMockStorageClient(mctrl)
 	ctx := context.Background()
 
-	_, mongoDataModel, expectedOutput := getTestModels20220315privatepreview()
+	_, mongoDataModel, expectedOutput := getTestModelsForGetAndListApis20220315privatepreview()
 
 	t.Run("get non-existing resource", func(t *testing.T) {
 		w := httptest.NewRecorder()
@@ -73,7 +73,7 @@ func TestGetMongoDatabase_20220315PrivatePreview(t *testing.T) {
 		_ = resp.Apply(ctx, w, req)
 		require.Equal(t, 200, w.Result().StatusCode)
 
-		actualOutput := &v20220315privatepreview.MongoDatabaseResource{}
+		actualOutput := &v20220315privatepreview.MongoDatabaseResponseResource{}
 		_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
 
 		require.Equal(t, expectedOutput, actualOutput)
diff --git a/pkg/connectorrp/frontend/controller/mongodatabases/listmongodatabases_test.go b/pkg/connectorrp/frontend/controller/mongodatabases/listmongodatabases_test.go
index 7b9b96648..749d168ad 100644
--- a/pkg/connectorrp/frontend/controller/mongodatabases/listmongodatabases_test.go
+++ b/pkg/connectorrp/frontend/controller/mongodatabases/listmongodatabases_test.go
@@ -29,7 +29,7 @@ func TestListMongoDatabasesRun_20220315PrivatePreview(t *testing.T) {
 	mStorageClient := store.NewMockStorageClient(mctrl)
 	ctx := context.Background()
 
-	_, mongoDataModel, expectedOutput := getTestModels20220315privatepreview()
+	_, mongoDataModel, expectedOutput := getTestModelsForGetAndListApis20220315privatepreview()
 
 	t.Run("empty list", func(t *testing.T) {
 		w := httptest.NewRecorder()
diff --git a/pkg/connectorrp/frontend/controller/mongodatabases/testdata.go b/pkg/connectorrp/frontend/controller/mongodatabases/v20220315privatepreview_test.go
similarity index 62%
rename from pkg/connectorrp/frontend/controller/mongodatabases/testdata.go
rename to pkg/connectorrp/frontend/controller/mongodatabases/v20220315privatepreview_test.go
index 2f7361372..1d39a171c 100644
--- a/pkg/connectorrp/frontend/controller/mongodatabases/testdata.go
+++ b/pkg/connectorrp/frontend/controller/mongodatabases/v20220315privatepreview_test.go
@@ -30,3 +30,19 @@ func getTestModels20220315privatepreview() (input *v20220315privatepreview.Mongo
 
 	return input, dataModel, output
 }
+
+func getTestModelsForGetAndListApis20220315privatepreview() (input *v20220315privatepreview.MongoDatabaseResource, dataModel *datamodel.MongoDatabase, output *v20220315privatepreview.MongoDatabaseResponseResource) {
+	rawInput := radiustesting.ReadFixture("20220315privatepreview_input.json")
+	input = &v20220315privatepreview.MongoDatabaseResource{}
+	_ = json.Unmarshal(rawInput, input)
+
+	rawDataModel := radiustesting.ReadFixture("20220315privatepreview_datamodel.json")
+	dataModel = &datamodel.MongoDatabase{}
+	_ = json.Unmarshal(rawDataModel, dataModel)
+
+	rawExpectedOutput := radiustesting.ReadFixture("20220315privatepreview_output.json")
+	output = &v20220315privatepreview.MongoDatabaseResponseResource{}
+	_ = json.Unmarshal(rawExpectedOutput, output)
+
+	return input, dataModel, output
+}
diff --git a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/getrabbitmq_test.go b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/getrabbitmq_test.go
index e67eafa15..5077729fd 100644
--- a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/getrabbitmq_test.go
+++ b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/getrabbitmq_test.go
@@ -27,7 +27,7 @@ func TestGetRabbitMQMessageQueue_20220315PrivatePreview(t *testing.T) {
 	mStorageClient := store.NewMockStorageClient(mctrl)
 	ctx := context.Background()
 
-	_, rabbitMQDataModel, expectedOutput := getTestModels20220315privatepreview()
+	_, rabbitMQDataModel, expectedOutput := getTestModelsForGetAndListApis20220315privatepreview()
 
 	t.Run("get non-existing resource", func(t *testing.T) {
 		w := httptest.NewRecorder()
@@ -73,7 +73,7 @@ func TestGetRabbitMQMessageQueue_20220315PrivatePreview(t *testing.T) {
 		_ = resp.Apply(ctx, w, req)
 		require.Equal(t, 200, w.Result().StatusCode)
 
-		actualOutput := &v20220315privatepreview.RabbitMQMessageQueueResource{}
+		actualOutput := &v20220315privatepreview.RabbitMQMessageQueueResponseResource{}
 		_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
 
 		require.Equal(t, expectedOutput, actualOutput)
diff --git a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/listrabbitmqs_test.go b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/listrabbitmqs_test.go
index 39a151eab..2a7b32622 100644
--- a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/listrabbitmqs_test.go
+++ b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/listrabbitmqs_test.go
@@ -29,7 +29,7 @@ func TestListRabbitMQMessageQueuesRun_20220315PrivatePreview(t *testing.T) {
 	mStorageClient := store.NewMockStorageClient(mctrl)
 	ctx := context.Background()
 
-	_, rabbitMQDataModel, expectedOutput := getTestModels20220315privatepreview()
+	_, rabbitMQDataModel, expectedOutput := getTestModelsForGetAndListApis20220315privatepreview()
 
 	t.Run("empty list", func(t *testing.T) {
 		w := httptest.NewRecorder()
diff --git a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/testdata.go b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/v20220315privatepreview_test.go
similarity index 61%
rename from pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/testdata.go
rename to pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/v20220315privatepreview_test.go
index 992eab0bd..972fc9181 100644
--- a/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/testdata.go
+++ b/pkg/connectorrp/frontend/controller/rabbitmqmessagequeues/v20220315privatepreview_test.go
@@ -30,3 +30,19 @@ func getTestModels20220315privatepreview() (input *v20220315privatepreview.Rabbi
 
 	return input, dataModel, output
 }
+
+func getTestModelsForGetAndListApis20220315privatepreview() (input *v20220315privatepreview.RabbitMQMessageQueueResource, dataModel *datamodel.RabbitMQMessageQueue, output *v20220315privatepreview.RabbitMQMessageQueueResponseResource) {
+	rawInput := radiustesting.ReadFixture("20220315privatepreview_input.json")
+	input = &v20220315privatepreview.RabbitMQMessageQueueResource{}
+	_ = json.Unmarshal(rawInput, input)
+
+	rawDataModel := radiustesting.ReadFixture("20220315privatepreview_datamodel.json")
+	dataModel = &datamodel.RabbitMQMessageQueue{}
+	_ = json.Unmarshal(rawDataModel, dataModel)
+
+	rawExpectedOutput := radiustesting.ReadFixture("20220315privatepreview_output.json")
+	output = &v20220315privatepreview.RabbitMQMessageQueueResponseResource{}
+	_ = json.Unmarshal(rawExpectedOutput, output)
+
+	return input, dataModel, output
+}
diff --git a/pkg/connectorrp/frontend/controller/rediscaches/getrediscache_test.go b/pkg/connectorrp/frontend/controller/rediscaches/getrediscache_test.go
index ce4fcb5a6..63ea10051 100644
--- a/pkg/connectorrp/frontend/controller/rediscaches/getrediscache_test.go
+++ b/pkg/connectorrp/frontend/controller/rediscaches/getrediscache_test.go
@@ -27,7 +27,7 @@ func TestGetRedisCache_20220315PrivatePreview(t *testing.T) {
 	mStorageClient := store.NewMockStorageClient(mctrl)
 	ctx := context.Background()
 
-	_, redisDataModel, expectedOutput := getTestModels20220315privatepreview()
+	_, redisDataModel, expectedOutput := getTestModelsForGetAndListApis20220315privatepreview()
 
 	t.Run("get non-existing resource", func(t *testing.T) {
 		w := httptest.NewRecorder()
@@ -73,7 +73,7 @@ func TestGetRedisCache_20220315PrivatePreview(t *testing.T) {
 		_ = resp.Apply(ctx, w, req)
 		require.Equal(t, 200, w.Result().StatusCode)
 
-		actualOutput := &v20220315privatepreview.RedisCacheResource{}
+		actualOutput := &v20220315privatepreview.RedisCacheResponseResource{}
 		_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
 
 		require.Equal(t, expectedOutput, actualOutput)
diff --git a/pkg/connectorrp/frontend/controller/rediscaches/listrediscaches_test.go b/pkg/connectorrp/frontend/controller/rediscaches/listrediscaches_test.go
index c2237d64b..6d1219edf 100644
--- a/pkg/connectorrp/frontend/controller/rediscaches/listrediscaches_test.go
+++ b/pkg/connectorrp/frontend/controller/rediscaches/listrediscaches_test.go
@@ -29,7 +29,7 @@ func TestListRedisCachesRun_20220315PrivatePreview(t *testing.T) {
 	mStorageClient := store.NewMockStorageClient(mctrl)
 	ctx := context.Background()
 
-	_, redisDataModel, expectedOutput := getTestModels20220315privatepreview()
+	_, redisDataModel, expectedOutput := getTestModelsForGetAndListApis20220315privatepreview()
 
 	t.Run("empty list", func(t *testing.T) {
 		w := httptest.NewRecorder()
diff --git a/pkg/connectorrp/frontend/controller/rediscaches/v20220315privatepreview_test.go b/pkg/connectorrp/frontend/controller/rediscaches/v20220315privatepreview_test.go
new file mode 100644
index 000000000..e98adbd20
--- /dev/null
+++ b/pkg/connectorrp/frontend/controller/rediscaches/v20220315privatepreview_test.go
@@ -0,0 +1,48 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package rediscaches
+
+import (
+	"encoding/json"
+
+	"github.com/project-radius/radius/pkg/connectorrp/api/v20220315privatepreview"
+	"github.com/project-radius/radius/pkg/connectorrp/datamodel"
+	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+)
+
+const testHeaderfile = "20220315privatepreview_requestheaders.json"
+
+func getTestModels20220315privatepreview() (input *v20220315privatepreview.RedisCacheResource, dataModel *datamodel.RedisCache, output *v20220315privatepreview.RedisCacheResource) {
+	rawInput := radiustesting.ReadFixture("20220315privatepreview_input.json")
+	input = &v20220315privatepreview.RedisCacheResource{}
+	_ = json.Unmarshal(rawInput, input)
+
+	rawDataModel := radiustesting.ReadFixture("20220315privatepreview_datamodel.json")
+	dataModel = &datamodel.RedisCache{}
+	_ = json.Unmarshal(rawDataModel, dataModel)
+
+	rawExpectedOutput := radiustesting.ReadFixture("20220315privatepreview_output.json")
+	output = &v20220315privatepreview.RedisCacheResource{}
+	_ = json.Unmarshal(rawExpectedOutput, output)
+
+	return input, dataModel, output
+}
+
+func getTestModelsForGetAndListApis20220315privatepreview() (input *v20220315privatepreview.RedisCacheResource, dataModel *datamodel.RedisCache, output *v20220315privatepreview.RedisCacheResponseResource) {
+	rawInput := radiustesting.ReadFixture("20220315privatepreview_input.json")
+	input = &v20220315privatepreview.RedisCacheResource{}
+	_ = json.Unmarshal(rawInput, input)
+
+	rawDataModel := radiustesting.ReadFixture("20220315privatepreview_datamodel.json")
+	dataModel = &datamodel.RedisCache{}
+	_ = json.Unmarshal(rawDataModel, dataModel)
+
+	rawExpectedOutput := radiustesting.ReadFixture("20220315privatepreview_output.json")
+	output = &v20220315privatepreview.RedisCacheResponseResource{}
+	_ = json.Unmarshal(rawExpectedOutput, output)
+
+	return input, dataModel, output
+}
diff --git a/pkg/connectorrp/frontend/controller/sqldatabases/testdata.go b/pkg/connectorrp/frontend/controller/sqldatabases/v20220315privatepreview_test.go
similarity index 100%
rename from pkg/connectorrp/frontend/controller/sqldatabases/testdata.go
rename to pkg/connectorrp/frontend/controller/sqldatabases/v20220315privatepreview_test.go
diff --git a/pkg/connectorrp/frontend/handler/getoperations_test.go b/pkg/connectorrp/frontend/handler/getoperations_test.go
index dd3808a17..6990aacc2 100644
--- a/pkg/connectorrp/frontend/handler/getoperations_test.go
+++ b/pkg/connectorrp/frontend/handler/getoperations_test.go
@@ -34,7 +34,7 @@ func TestRunWith20220315PrivatePreview(t *testing.T) {
 	case *rest.OKResponse:
 		pagination, ok := v.Body.(*v1.PaginatedList)
 		require.True(t, ok)
-		require.Equal(t, 27, len(pagination.Value))
+		require.Equal(t, 34, len(pagination.Value))
 	default:
 		require.Truef(t, false, "should not return error")
 	}
diff --git a/pkg/connectorrp/frontend/handler/routes_test.go b/pkg/connectorrp/frontend/handler/routes_test.go
index 44077bc5e..e8a7e0a93 100644
--- a/pkg/connectorrp/frontend/handler/routes_test.go
+++ b/pkg/connectorrp/frontend/handler/routes_test.go
@@ -122,6 +122,26 @@ var handlerTests = []struct {
 		url:        "/resourcegroups/testrg/providers/applications.connector/sqldatabases/sql?api-version=2022-03-15-privatepreview",
 		method:     http.MethodDelete,
 		isAzureAPI: false,
+	}, {
+		url:        "/resourcegroups/testrg/providers/applications.connector/extenders?api-version=2022-03-15-privatepreview",
+		method:     http.MethodGet,
+		isAzureAPI: false,
+	}, {
+		url:        "/resourcegroups/testrg/providers/applications.connector/extenders/extender?api-version=2022-03-15-privatepreview",
+		method:     http.MethodPut,
+		isAzureAPI: false,
+	}, {
+		url:        "/resourcegroups/testrg/providers/applications.connector/extenders/extender?api-version=2022-03-15-privatepreview",
+		method:     http.MethodPatch,
+		isAzureAPI: false,
+	}, {
+		url:        "/resourcegroups/testrg/providers/applications.connector/extenders/extender?api-version=2022-03-15-privatepreview",
+		method:     http.MethodDelete,
+		isAzureAPI: false,
+	}, {
+		url:        "/resourcegroups/testrg/providers/applications.connector/extenders/extender/listsecrets?api-version=2022-03-15-privatepreview",
+		method:     http.MethodPost,
+		isAzureAPI: false,
 	},
 	{
 		url:        "/resourcegroups/testrg/providers/applications.connector/daprstatestores?api-version=2022-03-15-privatepreview",
@@ -231,9 +251,16 @@ func assertRouters(t *testing.T, pathBase string, isARM bool, mockSP *dataprovid
 			continue
 		}
 
-		uri := "http://localhost" + pathBase + tt.url
-		if isARM && !tt.isAzureAPI {
-			uri = "http://localhost" + pathBase + "/subscriptions/00000000-0000-0000-0000-000000000000" + tt.url
+		uri := "http://localhost" + pathBase + "/planes/radius/{planeName}" + tt.url
+		if isARM {
+			if tt.isAzureAPI {
+				uri = "http://localhost" + pathBase + tt.url
+			} else {
+				uri = "http://localhost" + pathBase + "/subscriptions/00000000-0000-0000-0000-000000000000" + tt.url
+			}
+		}
+		if !isARM {
+			uri = "http://localhost" + pathBase + "/planes/radius/local" + tt.url
 		}
 
 		t.Run(uri, func(t *testing.T) {
diff --git a/pkg/connectorrp/renderers/mongodatabases/renderer_test.go b/pkg/connectorrp/renderers/mongodatabases/renderer_test.go
index 783197234..15dead82e 100644
--- a/pkg/connectorrp/renderers/mongodatabases/renderer_test.go
+++ b/pkg/connectorrp/renderers/mongodatabases/renderer_test.go
@@ -36,9 +36,11 @@ func Test_Render_Success(t *testing.T) {
 			Type: "Applications.Connector/mongoDatabases",
 		},
 		Properties: datamodel.MongoDatabaseProperties{
-			Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
-			Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
-			Resource:    "/subscriptions/test-sub/resourceGroups/test-group/providers/Microsoft.DocumentDB/databaseAccounts/test-account/mongodbDatabases/test-database",
+			MongoDatabaseResponseProperties: datamodel.MongoDatabaseResponseProperties{
+				Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
+				Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
+				Resource:    "/subscriptions/test-sub/resourceGroups/test-group/providers/Microsoft.DocumentDB/databaseAccounts/test-account/mongodbDatabases/test-database",
+			},
 		},
 	}
 
@@ -91,8 +93,10 @@ func Test_Render_UserSpecifiedSecrets(t *testing.T) {
 			Type: "Applications.Connector/mongoDatabases",
 		},
 		Properties: datamodel.MongoDatabaseProperties{
-			Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
-			Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
+			MongoDatabaseResponseProperties: datamodel.MongoDatabaseResponseProperties{
+				Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
+				Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
+			},
 			Secrets: datamodel.MongoDatabaseSecrets{
 				Username:         userName,
 				Password:         password,
@@ -131,8 +135,10 @@ func Test_Render_NoResourceSpecified(t *testing.T) {
 			Type: "Applications.Connector/mongoDatabases",
 		},
 		Properties: datamodel.MongoDatabaseProperties{
-			Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
-			Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
+			MongoDatabaseResponseProperties: datamodel.MongoDatabaseResponseProperties{
+				Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
+				Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
+			},
 		},
 	}
 
@@ -174,9 +180,11 @@ func Test_Render_InvalidSourceResourceIdentifier(t *testing.T) {
 			Type: "Applications.Connector/mongoDatabases",
 		},
 		Properties: datamodel.MongoDatabaseProperties{
-			Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
-			Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
-			Resource:    "/subscriptions/test-sub/resourceGroups/test-group/Microsoft.DocumentDB/databaseAccounts/test-account/mongodbDatabases/test-database",
+			MongoDatabaseResponseProperties: datamodel.MongoDatabaseResponseProperties{
+				Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
+				Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
+				Resource:    "/subscriptions/test-sub/resourceGroups/test-group/Microsoft.DocumentDB/databaseAccounts/test-account/mongodbDatabases/test-database",
+			},
 		},
 	}
 
@@ -196,9 +204,11 @@ func Test_Render_InvalidResourceType(t *testing.T) {
 			Type: "Applications.Connector/mongoDatabases",
 		},
 		Properties: datamodel.MongoDatabaseProperties{
-			Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
-			Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
-			Resource:    "/subscriptions/test-sub/resourceGroups/test-group/providers/Microsoft.SomethingElse/databaseAccounts/test-account/mongodbDatabases/test-database",
+			MongoDatabaseResponseProperties: datamodel.MongoDatabaseResponseProperties{
+				Application: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/applications/testApplication",
+				Environment: "/subscriptions/test-sub/resourceGroups/test-group/providers/Applications.Core/environments/env0",
+				Resource:    "/subscriptions/test-sub/resourceGroups/test-group/providers/Microsoft.SomethingElse/databaseAccounts/test-account/mongodbDatabases/test-database",
+			},
 		},
 	}
 
diff --git a/pkg/corerp/frontend/controller/gateway/createorupdategateway_test.go b/pkg/corerp/frontend/controller/gateway/createorupdategateway_test.go
new file mode 100644
index 000000000..c3b89cf43
--- /dev/null
+++ b/pkg/corerp/frontend/controller/gateway/createorupdategateway_test.go
@@ -0,0 +1,271 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package gateway
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/google/uuid"
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
+	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+	"github.com/project-radius/radius/pkg/ucp/resources"
+	"github.com/project-radius/radius/pkg/ucp/store"
+	"github.com/stretchr/testify/require"
+)
+
+func TestCreateOrUpdateGatewayRun_20220315PrivatePreview(t *testing.T) {
+
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
+
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
+
+	/*
+		Creating a gateway resource in an async way has multiple operations with branching:
+		1. Get Resource
+		2. [Conditional] If resource exists, check if there is an ongoing operation on it
+		3. Save Resource
+		4. Queue Resource
+		5. [Conditional] If Queue has an error then Rollback changes
+		6. [Conditional] Update the record state to Failed
+	*/
+	createCases := []struct {
+		desc    string
+		getErr  error
+		saveErr error
+		qErr    error
+		rbErr   error
+		rCode   int
+		rErr    error
+	}{
+		{
+			"async-create-new-gateway-success",
+			&store.ErrNotFound{},
+			nil,
+			nil,
+			nil,
+			http.StatusCreated,
+			nil,
+		},
+		{
+			"async-create-new-gateway-concurrency-error",
+			&store.ErrConcurrency{},
+			nil,
+			nil,
+			nil,
+			http.StatusCreated,
+			&store.ErrConcurrency{},
+		},
+		{
+			"async-create-new-gateway-enqueue-error",
+			&store.ErrNotFound{},
+			nil,
+			errors.New("enqueuer client is unset"),
+			nil,
+			http.StatusInternalServerError,
+			errors.New("enqueuer client is unset"),
+		},
+	}
+
+	for _, tt := range createCases {
+		t.Run(tt.desc, func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+
+			gatewayInput, gatewayDataModel, _ := getTestModels20220315privatepreview()
+
+			w := httptest.NewRecorder()
+			req, err := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodPut, testHeaderfile, gatewayInput)
+			require.NoError(t, err)
+
+			ctx := radiustesting.ARMTestContextFromRequest(req)
+			sCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+			mds.EXPECT().Get(gomock.Any(), gomock.Any()).
+				Return(&store.Object{}, tt.getErr).
+				Times(1)
+
+			if tt.getErr == nil || errors.Is(&store.ErrNotFound{}, tt.getErr) {
+				mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+					Return(tt.saveErr).
+					Times(1)
+
+				if tt.saveErr == nil {
+					msm.EXPECT().QueueAsyncOperation(gomock.Any(), gomock.Any(), gomock.Any()).
+						Return(tt.qErr).
+						Times(1)
+
+					if tt.qErr != nil {
+						mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+							Return(tt.rbErr).
+							Times(1)
+					}
+				}
+			}
+
+			ctl, err := NewCreateOrUpdateGateway(mds, msm)
+			require.NoError(t, err)
+
+			resp, err := ctl.Run(ctx, req)
+			if tt.rErr != nil {
+				require.Error(t, tt.rErr)
+			} else {
+				require.NoError(t, err)
+
+				_ = resp.Apply(ctx, w, req)
+				require.Equal(t, tt.rCode, w.Result().StatusCode)
+
+				locationHeader := getAsyncLocationPath(sCtx.ResourceID, gatewayDataModel.TrackedResource.Location, "operationResults", sCtx.OperationID)
+				require.NotNil(t, w.Header().Get("Location"))
+				require.Equal(t, locationHeader, w.Header().Get("Location"))
+
+				azureAsyncOpHeader := getAsyncLocationPath(sCtx.ResourceID, gatewayDataModel.TrackedResource.Location, "operationStatuses", sCtx.OperationID)
+				require.NotNil(t, w.Header().Get("Azure-AsyncOperation"))
+				require.Equal(t, azureAsyncOpHeader, w.Header().Get("Azure-AsyncOperation"))
+			}
+		})
+	}
+
+	updateCases := []struct {
+		desc     string
+		curState v1.ProvisioningState
+		getErr   error
+		saveErr  error
+		qErr     error
+		rbErr    error
+		rCode    int
+		rErr     error
+	}{
+		{
+			"async-update-existing-gateway-success",
+			v1.ProvisioningStateSucceeded,
+			nil,
+			nil,
+			nil,
+			nil,
+			http.StatusAccepted,
+			nil,
+		},
+		{
+			"async-update-existing-gateway-concurrency-error",
+			v1.ProvisioningStateSucceeded,
+			&store.ErrConcurrency{},
+			nil,
+			nil,
+			nil,
+			http.StatusAccepted,
+			&store.ErrConcurrency{},
+		},
+		{
+			"async-update-existing-gateway-save-error",
+			v1.ProvisioningStateSucceeded,
+			nil,
+			errors.New("testing initial save err"),
+			nil,
+			nil,
+			http.StatusInternalServerError,
+			errors.New("testing initial save err"),
+		},
+		{
+			"async-update-existing-gateway-enqueue-error",
+			v1.ProvisioningStateSucceeded,
+			nil,
+			nil,
+			errors.New("enqueuer client is unset"),
+			nil,
+			http.StatusInternalServerError,
+			errors.New("enqueuer client is unset"),
+		},
+	}
+
+	for _, tt := range updateCases {
+		t.Run(tt.desc, func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+
+			gatewayInput, gatewayDataModel, _ := getTestModels20220315privatepreview()
+			gatewayDataModel.Properties.ProvisioningState = tt.curState
+
+			w := httptest.NewRecorder()
+			req, err := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodPatch, testHeaderfile, gatewayInput)
+			require.NoError(t, err)
+
+			ctx := radiustesting.ARMTestContextFromRequest(req)
+			sCtx := servicecontext.ARMRequestContextFromContext(ctx)
+
+			so := &store.Object{
+				Metadata: store.Metadata{ID: sCtx.ResourceID.String()},
+				Data:     gatewayDataModel,
+			}
+
+			mds.EXPECT().Get(gomock.Any(), gomock.Any()).
+				Return(so, tt.getErr).
+				Times(1)
+
+			if tt.getErr == nil {
+				mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+					Return(tt.saveErr).
+					Times(1)
+
+				if tt.saveErr == nil {
+					msm.EXPECT().QueueAsyncOperation(gomock.Any(), gomock.Any(), gomock.Any()).
+						Return(tt.qErr).
+						Times(1)
+
+					if tt.qErr != nil {
+						mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+							Return(tt.rbErr).
+							Times(1)
+					}
+				}
+			}
+
+			ctl, err := NewCreateOrUpdateGateway(mds, msm)
+			require.NoError(t, err)
+
+			resp, err := ctl.Run(ctx, req)
+			if tt.rErr != nil {
+				require.Error(t, tt.rErr)
+			} else {
+				require.NoError(t, err)
+
+				_ = resp.Apply(ctx, w, req)
+				require.Equal(t, tt.rCode, w.Result().StatusCode)
+
+				locationHeader := getAsyncLocationPath(sCtx.ResourceID, gatewayDataModel.TrackedResource.Location, "operationResults", sCtx.OperationID)
+				require.NotNil(t, w.Header().Get("Location"))
+				require.Equal(t, locationHeader, w.Header().Get("Location"))
+
+				azureAsyncOpHeader := getAsyncLocationPath(sCtx.ResourceID, gatewayDataModel.TrackedResource.Location, "operationStatuses", sCtx.OperationID)
+				require.NotNil(t, w.Header().Get("Azure-AsyncOperation"))
+				require.Equal(t, azureAsyncOpHeader, w.Header().Get("Azure-AsyncOperation"))
+			}
+		})
+	}
+}
+
+func getAsyncLocationPath(resourceID resources.ID, location string, resourceType string, operationID uuid.UUID) string {
+	root := fmt.Sprintf("/subscriptions/%s", resourceID.FindScope(resources.SubscriptionsSegment))
+
+	if resourceID.IsUCPQualfied() {
+		root = fmt.Sprintf("/planes/%s", resourceID.PlaneNamespace())
+	}
+
+	return fmt.Sprintf("%s/providers/%s/locations/%s/%s/%s", root, resourceID.ProviderNamespace(), location, resourceType, operationID.String())
+}
diff --git a/pkg/corerp/frontend/controller/gateway/deletegateway_test.go b/pkg/corerp/frontend/controller/gateway/deletegateway_test.go
new file mode 100644
index 000000000..6bc8c869e
--- /dev/null
+++ b/pkg/corerp/frontend/controller/gateway/deletegateway_test.go
@@ -0,0 +1,106 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+// ------------------------------------------------------------
+
+package gateway
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	"github.com/project-radius/radius/pkg/corerp/datamodel"
+	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+	"github.com/project-radius/radius/pkg/ucp/store"
+	"github.com/stretchr/testify/require"
+)
+
+func TestDeleteGatewayRun_20220315PrivatePreview(t *testing.T) {
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
+
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
+
+	t.Parallel()
+
+	deleteCases := []struct {
+		desc     string
+		etag     string
+		curState v1.ProvisioningState
+		getErr   error
+		qErr     error
+		saveErr  error
+		code     int
+	}{
+		{"async-delete-non-existing-resource-no-etag", "", v1.ProvisioningStateNone, &store.ErrNotFound{}, nil, nil, http.StatusNoContent},
+		{"async-delete-existing-resource-not-in-terminal-state", "", v1.ProvisioningStateUpdating, nil, nil, nil, http.StatusConflict},
+		{"async-delete-existing-resource-success", "", v1.ProvisioningStateSucceeded, nil, nil, nil, http.StatusAccepted},
+	}
+
+	for _, tt := range deleteCases {
+		t.Run(tt.desc, func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+
+			w := httptest.NewRecorder()
+
+			req, _ := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodDelete, testHeaderfile, nil)
+			req.Header.Set("If-Match", tt.etag)
+
+			ctx := radiustesting.ARMTestContextFromRequest(req)
+			_, gtwyDataModel, _ := getTestModels20220315privatepreview()
+
+			gtwyDataModel.Properties.ProvisioningState = tt.curState
+
+			mds.EXPECT().
+				Get(gomock.Any(), gomock.Any()).
+				Return(&store.Object{
+					Metadata: store.Metadata{ID: gtwyDataModel.ID},
+					Data:     gtwyDataModel,
+				}, tt.getErr).
+				Times(1)
+
+			if tt.getErr == nil && gtwyDataModel.Properties.ProvisioningState.IsTerminal() {
+				msm.EXPECT().QueueAsyncOperation(gomock.Any(), gomock.Any(), gomock.Any()).
+					Return(tt.qErr).
+					Times(1)
+
+				if tt.qErr != nil {
+					mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+						Return(tt.saveErr).
+						Times(1)
+				}
+			}
+
+			ctl, err := NewDeleteGateway(mds, msm)
+			require.NoError(t, err)
+
+			resp, err := ctl.Run(ctx, req)
+			require.NoError(t, err)
+
+			err = resp.Apply(ctx, w, req)
+			require.NoError(t, err)
+
+			result := w.Result()
+			require.Equal(t, tt.code, result.StatusCode)
+
+			// If happy path, expect that the returned object has Deleting state
+			if tt.code == http.StatusAccepted {
+				actualOutput := &datamodel.Gateway{}
+				_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
+				require.Equal(t, v1.ProvisioningStateDeleting, actualOutput.Properties.ProvisioningState)
+			}
+		})
+	}
+}
diff --git a/pkg/corerp/frontend/controller/httproutes/createorupdatehttproute_test.go b/pkg/corerp/frontend/controller/httproutes/createorupdatehttproute_test.go
index 378e51dab..b9cfa81e8 100644
--- a/pkg/corerp/frontend/controller/httproutes/createorupdatehttproute_test.go
+++ b/pkg/corerp/frontend/controller/httproutes/createorupdatehttproute_test.go
@@ -7,241 +7,265 @@ package httproutes
 
 import (
 	"context"
-	"encoding/json"
+	"errors"
 	"fmt"
 	"net/http"
 	"net/http/httptest"
 	"testing"
 
 	"github.com/golang/mock/gomock"
-	v20220315privatepreview "github.com/project-radius/radius/pkg/corerp/api/v20220315privatepreview"
+	"github.com/google/uuid"
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	"github.com/project-radius/radius/pkg/armrpc/servicecontext"
 	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
+	"github.com/project-radius/radius/pkg/ucp/resources"
 	"github.com/project-radius/radius/pkg/ucp/store"
 	"github.com/stretchr/testify/require"
 )
 
-func TestCreateOrUpdateHttpRouteRun_20220315PrivatePreview(t *testing.T) {
-	mctrl := gomock.NewController(t)
-	defer mctrl.Finish()
+func TestCreateOrUpdateHTTPRouteRun_20220315PrivatePreview(t *testing.T) {
 
-	mStorageClient := store.NewMockStorageClient(mctrl)
-	ctx := context.Background()
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
 
-	createNewResourceCases := []struct {
-		desc               string
-		headerKey          string
-		headerValue        string
-		resourceETag       string
-		expectedStatusCode int
-		shouldFail         bool
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
+
+	/*
+		Creating a httproute resource in an async way has multiple operations with branching:
+		1. Get Resource
+		2. [Conditional] If resource exists, check if there is an ongoing operation on it
+		3. Save Resource
+		4. Queue Resource
+		5. [Conditional] If Queue has an error then Rollback changes
+		6. [Conditional] Update the record state to Failed
+	*/
+	createCases := []struct {
+		desc    string
+		getErr  error
+		saveErr error
+		qErr    error
+		rbErr   error
+		rCode   int
+		rErr    error
 	}{
-		{"create-new-resource-no-if-match", "If-Match", "", "", http.StatusOK, false},
-		{"create-new-resource-*-if-match", "If-Match", "*", "", http.StatusPreconditionFailed, true},
-		{"create-new-resource-etag-if-match", "If-Match", "random-etag", "", http.StatusPreconditionFailed, true},
-		{"create-new-resource-*-if-none-match", "If-None-Match", "*", "", http.StatusOK, false},
+		{
+			"async-create-new-httproute-success",
+			&store.ErrNotFound{},
+			nil,
+			nil,
+			nil,
+			http.StatusCreated,
+			nil,
+		},
+		{
+			"async-create-new-httproute-concurrency-error",
+			&store.ErrConcurrency{},
+			nil,
+			nil,
+			nil,
+			http.StatusCreated,
+			&store.ErrConcurrency{},
+		},
+		{
+			"async-create-new-httproute-enqueue-error",
+			&store.ErrNotFound{},
+			nil,
+			errors.New("enqueuer client is unset"),
+			nil,
+			http.StatusInternalServerError,
+			errors.New("enqueuer client is unset"),
+		},
 	}
 
-	for _, tt := range createNewResourceCases {
+	for _, tt := range createCases {
 		t.Run(tt.desc, func(t *testing.T) {
-			hrtInput, hrtDataModel, expectedOutput := getTestModels20220315privatepreview()
-			w := httptest.NewRecorder()
-			req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, hrtInput)
-			req.Header.Set(tt.headerKey, tt.headerValue)
-			ctx := radiustesting.ARMTestContextFromRequest(req)
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
 
-			mStorageClient.
-				EXPECT().
-				Get(gomock.Any(), gomock.Any()).
-				DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
-					return nil, &store.ErrNotFound{}
-				})
-
-			expectedOutput.SystemData.CreatedAt = expectedOutput.SystemData.LastModifiedAt
-			expectedOutput.SystemData.CreatedBy = expectedOutput.SystemData.LastModifiedBy
-			expectedOutput.SystemData.CreatedByType = expectedOutput.SystemData.LastModifiedByType
-
-			if !tt.shouldFail {
-				mStorageClient.
-					EXPECT().
-					Save(gomock.Any(), gomock.Any(), gomock.Any()).
-					DoAndReturn(func(ctx context.Context, obj *store.Object, opts ...store.SaveOptions) error {
-						obj.ETag = "new-resource-etag"
-						obj.Data = hrtDataModel
-						return nil
-					})
-			}
+			httprouteInput, httprouteDataModel, _ := getTestModels20220315privatepreview()
 
-			ctl, err := NewCreateOrUpdateHTTPRoute(mStorageClient, nil)
-			require.NoError(t, err)
-			resp, err := ctl.Run(ctx, req)
+			w := httptest.NewRecorder()
+			req, err := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodPut, testHeaderfile, httprouteInput)
 			require.NoError(t, err)
-			_ = resp.Apply(ctx, w, req)
-			require.Equal(t, tt.expectedStatusCode, w.Result().StatusCode)
 
-			if !tt.shouldFail {
-				actualOutput := &v20220315privatepreview.HTTPRouteResource{}
-				_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
-				require.Equal(t, expectedOutput, actualOutput)
+			ctx := radiustesting.ARMTestContextFromRequest(req)
+			sCtx := servicecontext.ARMRequestContextFromContext(ctx)
 
-				require.Equal(t, "new-resource-etag", w.Header().Get("ETag"))
-			}
-		})
-	}
+			mds.EXPECT().Get(gomock.Any(), gomock.Any()).
+				Return(&store.Object{}, tt.getErr).
+				Times(1)
 
-	updateExistingResourceCases := []struct {
-		desc               string
-		headerKey          string
-		headerValue        string
-		resourceETag       string
-		expectedStatusCode int
-		shouldFail         bool
-	}{
-		{"update-resource-no-if-match", "If-Match", "", "resource-etag", http.StatusOK, false},
-		{"update-resource-*-if-match", "If-Match", "*", "resource-etag", http.StatusOK, false},
-		{"update-resource-matching-if-match", "If-Match", "matching-etag", "matching-etag", http.StatusOK, false},
-		{"update-resource-not-matching-if-match", "If-Match", "not-matching-etag", "another-etag", http.StatusPreconditionFailed, true},
-		{"update-resource-*-if-none-match", "If-None-Match", "*", "another-etag", http.StatusPreconditionFailed, true},
-	}
+			if tt.getErr == nil || errors.Is(&store.ErrNotFound{}, tt.getErr) {
+				mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+					Return(tt.saveErr).
+					Times(1)
 
-	for _, tt := range updateExistingResourceCases {
-		t.Run(tt.desc, func(t *testing.T) {
-			hrtInput, hrtDataModel, expectedOutput := getTestModels20220315privatepreview()
-			w := httptest.NewRecorder()
-			req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodGet, testHeaderfile, hrtInput)
-			req.Header.Set(tt.headerKey, tt.headerValue)
-			ctx := radiustesting.ARMTestContextFromRequest(req)
+				if tt.saveErr == nil {
+					msm.EXPECT().QueueAsyncOperation(gomock.Any(), gomock.Any(), gomock.Any()).
+						Return(tt.qErr).
+						Times(1)
 
-			mStorageClient.
-				EXPECT().
-				Get(gomock.Any(), gomock.Any()).
-				DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
-					return &store.Object{
-						Metadata: store.Metadata{ID: id, ETag: tt.resourceETag},
-						Data:     hrtDataModel,
-					}, nil
-				})
-
-			if !tt.shouldFail {
-				mStorageClient.
-					EXPECT().
-					Save(gomock.Any(), gomock.Any(), gomock.Any()).
-					DoAndReturn(func(ctx context.Context, obj *store.Object, opts ...store.SaveOptions) error {
-						obj.ETag = "updated-resource-etag"
-						obj.Data = hrtDataModel
-						return nil
-					})
+					if tt.qErr != nil {
+						mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+							Return(tt.rbErr).
+							Times(1)
+					}
+				}
 			}
 
-			ctl, err := NewCreateOrUpdateHTTPRoute(mStorageClient, nil)
+			ctl, err := NewCreateOrUpdateHTTPRoute(mds, msm)
 			require.NoError(t, err)
+
 			resp, err := ctl.Run(ctx, req)
-			_ = resp.Apply(ctx, w, req)
-			require.NoError(t, err)
-			require.Equal(t, tt.expectedStatusCode, w.Result().StatusCode)
+			if tt.rErr != nil {
+				require.Error(t, tt.rErr)
+			} else {
+				require.NoError(t, err)
+
+				_ = resp.Apply(ctx, w, req)
+				require.Equal(t, tt.rCode, w.Result().StatusCode)
 
-			if !tt.shouldFail {
-				actualOutput := &v20220315privatepreview.HTTPRouteResource{}
-				_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
-				require.Equal(t, expectedOutput, actualOutput)
+				locationHeader := getAsyncLocationPath(sCtx.ResourceID, httprouteDataModel.TrackedResource.Location, "operationResults", sCtx.OperationID)
+				require.NotNil(t, w.Header().Get("Location"))
+				require.Equal(t, locationHeader, w.Header().Get("Location"))
 
-				require.Equal(t, "updated-resource-etag", w.Header().Get("ETag"))
+				azureAsyncOpHeader := getAsyncLocationPath(sCtx.ResourceID, httprouteDataModel.TrackedResource.Location, "operationStatuses", sCtx.OperationID)
+				require.NotNil(t, w.Header().Get("Azure-AsyncOperation"))
+				require.Equal(t, azureAsyncOpHeader, w.Header().Get("Azure-AsyncOperation"))
 			}
 		})
 	}
 
-	patchNonExistingResourceCases := []struct {
-		desc               string
-		headerKey          string
-		headerValue        string
-		resourceEtag       string
-		expectedStatusCode int
-		shouldFail         bool
+	updateCases := []struct {
+		desc     string
+		curState v1.ProvisioningState
+		getErr   error
+		saveErr  error
+		qErr     error
+		rbErr    error
+		rCode    int
+		rErr     error
 	}{
-		{"patch-non-existing-resource-no-if-match", "If-Match", "", "", http.StatusNotFound, true},
-		{"patch-non-existing-resource-*-if-match", "If-Match", "*", "", http.StatusNotFound, true},
-		{"patch-non-existing-resource-random-if-match", "If-Match", "randome-etag", "", http.StatusNotFound, true},
+		{
+			"async-update-existing-httproute-success",
+			v1.ProvisioningStateSucceeded,
+			nil,
+			nil,
+			nil,
+			nil,
+			http.StatusAccepted,
+			nil,
+		},
+		{
+			"async-update-existing-httproute-concurrency-error",
+			v1.ProvisioningStateSucceeded,
+			&store.ErrConcurrency{},
+			nil,
+			nil,
+			nil,
+			http.StatusAccepted,
+			&store.ErrConcurrency{},
+		},
+		{
+			"async-update-existing-httproute-save-error",
+			v1.ProvisioningStateSucceeded,
+			nil,
+			errors.New("testing initial save err"),
+			nil,
+			nil,
+			http.StatusInternalServerError,
+			errors.New("testing initial save err"),
+		},
+		{
+			"async-update-existing-httproute-enqueue-error",
+			v1.ProvisioningStateSucceeded,
+			nil,
+			nil,
+			errors.New("enqueuer client is unset"),
+			nil,
+			http.StatusInternalServerError,
+			errors.New("enqueuer client is unset"),
+		},
 	}
 
-	for _, tt := range patchNonExistingResourceCases {
-		t.Run(fmt.Sprint(tt.desc), func(t *testing.T) {
-			hrtInput, _, _ := getTestModels20220315privatepreview()
+	for _, tt := range updateCases {
+		t.Run(tt.desc, func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+
+			httprouteInput, httprouteDataModel, _ := getTestModels20220315privatepreview()
+			httprouteDataModel.Properties.ProvisioningState = tt.curState
+
 			w := httptest.NewRecorder()
-			req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodPatch, testHeaderfile, hrtInput)
-			req.Header.Set(tt.headerKey, tt.headerValue)
+			req, err := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodPatch, testHeaderfile, httprouteInput)
+			require.NoError(t, err)
+
 			ctx := radiustesting.ARMTestContextFromRequest(req)
+			sCtx := servicecontext.ARMRequestContextFromContext(ctx)
 
-			mStorageClient.
-				EXPECT().
-				Get(gomock.Any(), gomock.Any()).
-				DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
-					return nil, &store.ErrNotFound{}
-				})
+			so := &store.Object{
+				Metadata: store.Metadata{ID: sCtx.ResourceID.String()},
+				Data:     httprouteDataModel,
+			}
 
-			ctl, err := NewCreateOrUpdateHTTPRoute(mStorageClient, nil)
-			require.NoError(t, err)
-			resp, err := ctl.Run(ctx, req)
-			require.NoError(t, err)
-			_ = resp.Apply(ctx, w, req)
-			require.Equal(t, tt.expectedStatusCode, w.Result().StatusCode)
-		})
-	}
+			mds.EXPECT().Get(gomock.Any(), gomock.Any()).
+				Return(so, tt.getErr).
+				Times(1)
 
-	patchExistingResourceCases := []struct {
-		desc               string
-		headerKey          string
-		headerValue        string
-		resourceEtag       string
-		expectedStatusCode int
-		shouldFail         bool
-	}{
-		{"patch-existing-resource-no-if-match", "If-Match", "", "resource-etag", http.StatusOK, false},
-		{"patch-existing-resource-*-if-match", "If-Match", "*", "resource-etag", http.StatusOK, false},
-		{"patch-existing-resource-matching-if-match", "If-Match", "matching-etag", "matching-etag", http.StatusOK, false},
-		{"patch-existing-resource-not-matching-if-match", "If-Match", "not-matching-etag", "another-etag", http.StatusPreconditionFailed, true},
-	}
+			if tt.getErr == nil {
+				mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+					Return(tt.saveErr).
+					Times(1)
 
-	for _, tt := range patchExistingResourceCases {
-		t.Run(fmt.Sprint(tt.desc), func(t *testing.T) {
-			hrtInput, hrtDataModel, expectedOutput := getTestModels20220315privatepreview()
-			w := httptest.NewRecorder()
-			req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodPatch, testHeaderfile, hrtInput)
-			req.Header.Set(tt.headerKey, tt.headerValue)
-			ctx := radiustesting.ARMTestContextFromRequest(req)
+				if tt.saveErr == nil {
+					msm.EXPECT().QueueAsyncOperation(gomock.Any(), gomock.Any(), gomock.Any()).
+						Return(tt.qErr).
+						Times(1)
 
-			mStorageClient.
-				EXPECT().
-				Get(gomock.Any(), gomock.Any()).
-				DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
-					return &store.Object{
-						Metadata: store.Metadata{ID: id, ETag: tt.resourceEtag},
-						Data:     hrtDataModel,
-					}, nil
-				})
-
-			if !tt.shouldFail {
-				mStorageClient.
-					EXPECT().
-					Save(gomock.Any(), gomock.Any(), gomock.Any()).
-					DoAndReturn(func(ctx context.Context, obj *store.Object, opts ...store.SaveOptions) error {
-						cfg := store.NewSaveConfig(opts...)
-						obj.ETag = cfg.ETag
-						obj.Data = hrtDataModel
-						return nil
-					})
+					if tt.qErr != nil {
+						mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+							Return(tt.rbErr).
+							Times(1)
+					}
+				}
 			}
 
-			ctl, err := NewCreateOrUpdateHTTPRoute(mStorageClient, nil)
+			ctl, err := NewCreateOrUpdateHTTPRoute(mds, msm)
 			require.NoError(t, err)
+
 			resp, err := ctl.Run(ctx, req)
-			_ = resp.Apply(ctx, w, req)
-			require.NoError(t, err)
-			require.Equal(t, tt.expectedStatusCode, w.Result().StatusCode)
+			if tt.rErr != nil {
+				require.Error(t, tt.rErr)
+			} else {
+				require.NoError(t, err)
+
+				_ = resp.Apply(ctx, w, req)
+				require.Equal(t, tt.rCode, w.Result().StatusCode)
+
+				locationHeader := getAsyncLocationPath(sCtx.ResourceID, httprouteDataModel.TrackedResource.Location, "operationResults", sCtx.OperationID)
+				require.NotNil(t, w.Header().Get("Location"))
+				require.Equal(t, locationHeader, w.Header().Get("Location"))
 
-			if !tt.shouldFail {
-				actualOutput := &v20220315privatepreview.HTTPRouteResource{}
-				_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
-				require.Equal(t, expectedOutput, actualOutput)
+				azureAsyncOpHeader := getAsyncLocationPath(sCtx.ResourceID, httprouteDataModel.TrackedResource.Location, "operationStatuses", sCtx.OperationID)
+				require.NotNil(t, w.Header().Get("Azure-AsyncOperation"))
+				require.Equal(t, azureAsyncOpHeader, w.Header().Get("Azure-AsyncOperation"))
 			}
 		})
 	}
 }
+
+func getAsyncLocationPath(resourceID resources.ID, location string, resourceType string, operationID uuid.UUID) string {
+	root := fmt.Sprintf("/subscriptions/%s", resourceID.FindScope(resources.SubscriptionsSegment))
+
+	if resourceID.IsUCPQualfied() {
+		root = fmt.Sprintf("/planes/%s", resourceID.PlaneNamespace())
+	}
+
+	return fmt.Sprintf("%s/providers/%s/locations/%s/%s/%s", root, resourceID.ProviderNamespace(), location, resourceType, operationID.String())
+}
diff --git a/pkg/corerp/frontend/controller/httproutes/deletehttproute_test.go b/pkg/corerp/frontend/controller/httproutes/deletehttproute_test.go
index 2fffdd215..d5c59b7bc 100644
--- a/pkg/corerp/frontend/controller/httproutes/deletehttproute_test.go
+++ b/pkg/corerp/frontend/controller/httproutes/deletehttproute_test.go
@@ -8,125 +8,98 @@ package httproutes
 import (
 	"context"
 	"encoding/json"
-	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
 	"testing"
 
 	"github.com/golang/mock/gomock"
+	v1 "github.com/project-radius/radius/pkg/armrpc/api/v1"
+	"github.com/project-radius/radius/pkg/armrpc/asyncoperation/statusmanager"
+	"github.com/project-radius/radius/pkg/corerp/datamodel"
 	radiustesting "github.com/project-radius/radius/pkg/corerp/testing"
-	"github.com/project-radius/radius/pkg/radrp/armerrors"
 	"github.com/project-radius/radius/pkg/ucp/store"
 	"github.com/stretchr/testify/require"
 )
 
 func TestDeleteHTTPRouteRun_20220315PrivatePreview(t *testing.T) {
-	mctrl := gomock.NewController(t)
-	defer mctrl.Finish()
-
-	mStorageClient := store.NewMockStorageClient(mctrl)
-	ctx := context.Background()
+	setupTest := func(tb testing.TB) (func(tb testing.TB), *store.MockStorageClient, *statusmanager.MockStatusManager) {
+		mctrl := gomock.NewController(t)
+		mds := store.NewMockStorageClient(mctrl)
+		msm := statusmanager.NewMockStatusManager(mctrl)
+
+		return func(tb testing.TB) {
+			mctrl.Finish()
+		}, mds, msm
+	}
 
 	t.Parallel()
 
-	t.Run("delete non-existing resource", func(t *testing.T) {
-		w := httptest.NewRecorder()
-		req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodDelete, testHeaderfile, nil)
-		ctx := radiustesting.ARMTestContextFromRequest(req)
-
-		mStorageClient.
-			EXPECT().
-			Get(gomock.Any(), gomock.Any()).
-			DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
-				return nil, &store.ErrNotFound{}
-			})
-
-		ctl, err := NewDeleteHTTPRoute(mStorageClient, nil)
-
-		require.NoError(t, err)
-		resp, err := ctl.Run(ctx, req)
-		require.NoError(t, err)
-		err = resp.Apply(ctx, w, req)
-		require.NoError(t, err)
-
-		result := w.Result()
-		require.Equal(t, http.StatusNoContent, result.StatusCode)
-
-		body := result.Body
-		defer body.Close()
-		payload, err := ioutil.ReadAll(body)
-		require.NoError(t, err)
-		require.Empty(t, payload, "response body should be empty")
-	})
-
-	existingResourceDeletionCases := []struct {
-		desc               string
-		ifMatchETag        string
-		resourceETag       string
-		expectedStatusCode int
-		shouldFail         bool
+	deleteCases := []struct {
+		desc     string
+		etag     string
+		curState v1.ProvisioningState
+		getErr   error
+		qErr     error
+		saveErr  error
+		code     int
 	}{
-		{"delete-existing-resource-no-if-match", "", "random-etag", http.StatusOK, false},
-		{"delete-not-existing-resource-no-if-match", "", "", http.StatusNoContent, true},
-		{"delete-existing-resource-matching-if-match", "matching-etag", "matching-etag", http.StatusOK, false},
-		{"delete-existing-resource-not-matching-if-match", "not-matching-etag", "another-etag", http.StatusPreconditionFailed, true},
-		{"delete-not-existing-resource-*-if-match", "*", "", http.StatusNoContent, true},
-		{"delete-existing-resource-*-if-match", "*", "random-etag", http.StatusOK, false},
+		{"async-delete-non-existing-resource-no-etag", "", v1.ProvisioningStateNone, &store.ErrNotFound{}, nil, nil, http.StatusNoContent},
+		{"async-delete-existing-resource-not-in-terminal-state", "", v1.ProvisioningStateUpdating, nil, nil, nil, http.StatusConflict},
+		{"async-delete-existing-resource-success", "", v1.ProvisioningStateSucceeded, nil, nil, nil, http.StatusAccepted},
 	}
 
-	for _, tt := range existingResourceDeletionCases {
+	for _, tt := range deleteCases {
 		t.Run(tt.desc, func(t *testing.T) {
+			teardownTest, mds, msm := setupTest(t)
+			defer teardownTest(t)
+
 			w := httptest.NewRecorder()
 
-			req, _ := radiustesting.GetARMTestHTTPRequest(ctx, http.MethodDelete, testHeaderfile, nil)
-			req.Header.Set("If-Match", tt.ifMatchETag)
+			req, _ := radiustesting.GetARMTestHTTPRequest(context.Background(), http.MethodDelete, testHeaderfile, nil)
+			req.Header.Set("If-Match", tt.etag)
 
 			ctx := radiustesting.ARMTestContextFromRequest(req)
-			_, hrtDataModel, _ := getTestModels20220315privatepreview()
+			_, appDataModel, _ := getTestModels20220315privatepreview()
+
+			appDataModel.Properties.ProvisioningState = tt.curState
 
-			mStorageClient.
-				EXPECT().
+			mds.EXPECT().
 				Get(gomock.Any(), gomock.Any()).
-				DoAndReturn(func(ctx context.Context, id string, _ ...store.GetOptions) (*store.Object, error) {
-					return &store.Object{
-						Metadata: store.Metadata{ID: id, ETag: tt.resourceETag},
-						Data:     hrtDataModel,
-					}, nil
-				})
-
-			if !tt.shouldFail {
-				mStorageClient.
-					EXPECT().
-					Delete(gomock.Any(), gomock.Any()).
-					DoAndReturn(func(ctx context.Context, id string, _ ...store.DeleteOptions) error {
-						return nil
-					})
+				Return(&store.Object{
+					Metadata: store.Metadata{ID: appDataModel.ID},
+					Data:     appDataModel,
+				}, tt.getErr).
+				Times(1)
+
+			if tt.getErr == nil && appDataModel.Properties.ProvisioningState.IsTerminal() {
+				msm.EXPECT().QueueAsyncOperation(gomock.Any(), gomock.Any(), gomock.Any()).
+					Return(tt.qErr).
+					Times(1)
+
+				if tt.qErr != nil {
+					mds.EXPECT().Save(gomock.Any(), gomock.Any(), gomock.Any()).
+						Return(tt.saveErr).
+						Times(1)
+				}
 			}
 
-			ctl, err := NewDeleteHTTPRoute(mStorageClient, nil)
+			ctl, err := NewDeleteHTTPRoute(mds, msm)
 			require.NoError(t, err)
+
 			resp, err := ctl.Run(ctx, req)
 			require.NoError(t, err)
+
 			err = resp.Apply(ctx, w, req)
 			require.NoError(t, err)
 
 			result := w.Result()
-			require.Equal(t, tt.expectedStatusCode, result.StatusCode)
-
-			body := result.Body
-			defer body.Close()
-			payload, err := ioutil.ReadAll(body)
-			require.NoError(t, err)
+			require.Equal(t, tt.code, result.StatusCode)
 
-			if result.StatusCode == http.StatusOK || result.StatusCode == http.StatusNoContent {
-				// We return either http.StatusOK or http.StatusNoContent without a response body for success.
-				require.Empty(t, payload, "response body should be empty")
-			} else {
-				armerr := armerrors.ErrorResponse{}
-				err = json.Unmarshal(payload, &armerr)
-				require.NoError(t, err)
-				require.Equal(t, armerrors.PreconditionFailed, armerr.Error.Code)
-				require.NotEmpty(t, armerr.Error.Target)
+			// If happy path, expect that the returned object has Deleting state
+			if tt.code == http.StatusAccepted {
+				actualOutput := &datamodel.HTTPRoute{}
+				_ = json.Unmarshal(w.Body.Bytes(), actualOutput)
+				require.Equal(t, v1.ProvisioningStateDeleting, actualOutput.Properties.ProvisioningState)
 			}
 		})
 	}
diff --git a/pkg/corerp/frontend/handler/getoperations_test.go b/pkg/corerp/frontend/handler/getoperations_test.go
index 0e157778e..f9bd9d6c3 100644
--- a/pkg/corerp/frontend/handler/getoperations_test.go
+++ b/pkg/corerp/frontend/handler/getoperations_test.go
@@ -34,7 +34,7 @@ func TestRunWith20220315PrivatePreview(t *testing.T) {
 	case *rest.OKResponse:
 		pagination, ok := v.Body.(*v1.PaginatedList)
 		require.True(t, ok)
-		require.Equal(t, 17, len(pagination.Value))
+		require.Equal(t, 19, len(pagination.Value))
 	default:
 		require.Truef(t, false, "should not return error")
 	}
diff --git a/pkg/corerp/frontend/handler/routes_test.go b/pkg/corerp/frontend/handler/routes_test.go
index b55c08b25..c4161bd05 100644
--- a/pkg/corerp/frontend/handler/routes_test.go
+++ b/pkg/corerp/frontend/handler/routes_test.go
@@ -122,9 +122,13 @@ func assertRouters(t *testing.T, pathBase string, isARM bool, mockSP *dataprovid
 			continue
 		}
 
-		uri := "http://localhost" + pathBase + tt.url
-		if isARM && !tt.isAzureAPI {
-			uri = "http://localhost" + pathBase + "/subscriptions/00000000-0000-0000-0000-000000000000" + tt.url
+		uri := "http://localhost" + pathBase + "/planes/radius/{planeName}" + tt.url
+		if isARM {
+			if tt.isAzureAPI {
+				uri = "http://localhost" + pathBase + tt.url
+			} else {
+				uri = "http://localhost" + pathBase + "/subscriptions/00000000-0000-0000-0000-000000000000" + tt.url
+			}
 		}
 
 		t.Run(uri, func(t *testing.T) {
diff --git a/pkg/ucp/db/planes/db_test.go b/pkg/ucp/db/planes/db_test.go
index 6a4fe8bc2..970769bbf 100644
--- a/pkg/ucp/db/planes/db_test.go
+++ b/pkg/ucp/db/planes/db_test.go
@@ -27,7 +27,7 @@ func TestSaveValidPlane(t *testing.T) {
 				"Applications.Core":       "http://localhost:9080/",
 				"Applications.Connection": "http://localhost:9081/",
 			},
-			Kind: "UCPNative",
+			Kind: rest.PlaneKindUCPNative,
 		},
 	}
 
diff --git a/pkg/ucp/frontend/ucphandler/planes/planes_ucphandler_test.go b/pkg/ucp/frontend/ucphandler/planes/planes_ucphandler_test.go
index 9d0f18ab5..82803c625 100644
--- a/pkg/ucp/frontend/ucphandler/planes/planes_ucphandler_test.go
+++ b/pkg/ucp/frontend/ucphandler/planes/planes_ucphandler_test.go
@@ -42,7 +42,7 @@ func Test_CreatePlane(t *testing.T) {
 				"Applications.Core":       "http://localhost:9080/",
 				"Applications.Connection": "http://localhost:9081/",
 			},
-			Kind: "UCPNative",
+			Kind: rest.PlaneKindUCPNative,
 		},
 	}
 
@@ -58,6 +58,60 @@ func Test_CreatePlane(t *testing.T) {
 
 }
 
+func Test_CreateUCPNativePlane_NoResourceProviders(t *testing.T) {
+	ctx, cancel := testcontext.New(t)
+	defer cancel()
+	var testHandler = NewPlanesUCPHandler(Options{})
+
+	body := []byte(`{
+		"properties": {
+			"kind": "UCPNative"
+		}
+	}`)
+	path := "/planes/radius/local"
+	mockCtrl := gomock.NewController(t)
+	defer mockCtrl.Finish()
+	mockStorageClient := store.NewMockStorageClient(mockCtrl)
+
+	response, _ := testHandler.CreateOrUpdate(ctx, mockStorageClient, body, path)
+	badResponse := &rest.BadRequestResponse{
+		Body: rest.ErrorResponse{
+			Error: rest.ErrorDetails{
+				Code:    rest.Invalid,
+				Message: "At least one resource provider must be configured for UCP native plane: local",
+			},
+		},
+	}
+	assert.DeepEqual(t, badResponse, response)
+}
+
+func Test_CreateAzurePlane_NoURL(t *testing.T) {
+	ctx, cancel := testcontext.New(t)
+	defer cancel()
+	var testHandler = NewPlanesUCPHandler(Options{})
+
+	body := []byte(`{
+		"properties": {
+			"kind": "Azure"
+		}
+	}`)
+	path := "/planes/azure/azurecloud"
+	mockCtrl := gomock.NewController(t)
+	defer mockCtrl.Finish()
+	mockStorageClient := store.NewMockStorageClient(mockCtrl)
+
+	response, _ := testHandler.CreateOrUpdate(ctx, mockStorageClient, body, path)
+	badResponse := &rest.BadRequestResponse{
+		Body: rest.ErrorResponse{
+			Error: rest.ErrorDetails{
+				Code:    rest.Invalid,
+				Message: "URL must be specified for plane: azurecloud",
+			},
+		},
+	}
+	assert.DeepEqual(t, badResponse, response)
+}
+
 func Test_ListPlane(t *testing.T) {
 	ctx, cancel := testcontext.New(t)
 	defer cancel()
diff --git a/pkg/ucp/integrationtests/integration_test.go b/pkg/ucp/integrationtests/integration_test.go
index cd9a6d1e7..a702d8b3f 100644
--- a/pkg/ucp/integrationtests/integration_test.go
+++ b/pkg/ucp/integrationtests/integration_test.go
@@ -40,11 +40,14 @@ func NewClient(httpClient *http.Client, baseURL string) Client {
 }
 
 const (
-	rpURL                = "127.0.0.1:7443"
-	testProxyRequestPath = "/resourceGroups/rg1/providers/Applications.Core/applications"
-	apiVersionQueyParam  = "api-version=2022-03-15-privatepreview"
-	testPlaneID          = "/planes/radius/local"
-	basePath             = "/apis/api.ucp.dev/v1alpha3"
+	rpURL                     = "127.0.0.1:7443"
+	azureURL                  = "127.0.0.1:9443"
+	testProxyRequestPath      = "/planes/radius/local/resourceGroups/rg1/providers/Applications.Core/applications"
+	testProxyRequestAzurePath = "/subscriptions/sid/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1"
+	apiVersionQueyParam       = "api-version=2022-03-15-privatepreview"
+	testUCPNativePlaneID      = "/planes/radius/local"
+	testAzurePlaneID          = "/planes/azure/azurecloud"
+	basePath                  = "/apis/api.ucp.dev/v1alpha3"
 )
 
 var applicationList = []map[string]interface{}{
@@ -56,27 +59,38 @@ var applicationList = []map[string]interface{}{
 	},
 }
 
-var testPlane = rest.Plane{
-	ID:   testPlaneID,
+var testUCPNativePlane = rest.Plane{
+	ID:   testUCPNativePlaneID,
 	Name: "local",
 	Type: "System.Planes/radius",
 	Properties: rest.PlaneProperties{
 		ResourceProviders: map[string]string{
 			"Applications.Core": "http://" + rpURL,
 		},
+		Kind: rest.PlaneKindUCPNative,
+	},
+}
+
+var testAzurePlane = rest.Plane{
+	ID:   testAzurePlaneID,
+	Name: "azurecloud",
+	Type: "System.Planes/azure",
+	Properties: rest.PlaneProperties{
+		Kind: rest.PlaneKindAzure,
+		URL:  "http://" + azureURL,
 	},
 }
 
 var testResourceGroup = rest.ResourceGroup{
 	Name: "rg1",
-	ID:   testPlaneID + "/resourceGroups/rg1",
+	ID:   testUCPNativePlaneID + "/resourceGroups/rg1",
 }
 
 func Test_ProxyToRP(t *testing.T) {
 	body, err := json.Marshal(applicationList)
 	require.NoError(t, err)
 	rp := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-
+		require.Equal(t, testProxyRequestPath, r.URL.Path)
 		w.Header().Add("Content-Type", "application/json")
 		w.Header().Add("Location", "http://"+rpURL+testProxyRequestPath)
 		w.WriteHeader(http.StatusOK)
@@ -103,7 +117,7 @@ func Test_ProxyToRP(t *testing.T) {
 	ucpClient := NewClient(http.DefaultClient, ucp.URL+basePath)
 
 	// Register RP with UCP
-	registerRP(t, ucp, ucpClient, db)
+	registerRP(t, ucp, ucpClient, db, true)
 
 	// Create a Resource group
 	createResourceGroup(t, ucp, ucpClient, db)
@@ -112,17 +126,73 @@ func Test_ProxyToRP(t *testing.T) {
 	sendProxyRequest(t, ucp, ucpClient, db)
 }
 
-func registerRP(t *testing.T, ucp *httptest.Server, ucpClient Client, db *store.MockStorageClient) {
-	requestBody := map[string]interface{}{
-		"properties": map[string]interface{}{
-			"resourceProviders": map[string]string{
-				"Applications.Core": "http://" + rpURL,
+func Test_ProxyToRP_NonNativePlane(t *testing.T) {
+	body, err := json.Marshal(applicationList)
+	require.NoError(t, err)
+	rp := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		require.Equal(t, testProxyRequestAzurePath, r.URL.Path)
+		w.Header().Add("Content-Type", "application/json")
+		w.Header().Add("Location", "http://"+azureURL+testProxyRequestAzurePath)
+		w.WriteHeader(http.StatusOK)
+		_, err = w.Write(body)
+	}))
+	listener, err := net.Listen("tcp", azureURL)
+	require.NoError(t, err)
+	rp.Listener = listener
+	defer listener.Close()
+
+	rp.Start()
+	defer rp.Close()
+
+	ctrl := gomock.NewController(t)
+	db := store.NewMockStorageClient(ctrl)
+
+	router := mux.NewRouter()
+	ucp := httptest.NewServer(router)
+	api.Register(router, db, ucphandler.NewUCPHandler(ucphandler.UCPHandlerOptions{
+		Address:  rpURL,
+		BasePath: basePath,
+	}))
+
+	ucpClient := NewClient(http.DefaultClient, ucp.URL+basePath)
+
+	// Register RP with UCP
+	registerRP(t, ucp, ucpClient, db, false)
+
+	// Create a Resource group
+	createResourceGroup(t, ucp, ucpClient, db)
+
+	// Send a request that will be proxied to the RP
+	sendProxyRequest_AzurePlane(t, ucp, ucpClient, db)
+}
+
+func registerRP(t *testing.T, ucp *httptest.Server, ucpClient Client, db *store.MockStorageClient, ucpNative bool) {
+	var requestBody map[string]interface{}
+	if ucpNative {
+		requestBody = map[string]interface{}{
+			"properties": map[string]interface{}{
+				"resourceProviders": map[string]string{
+					"Applications.Core": "http://" + rpURL,
+				},
+				"kind": rest.PlaneKindUCPNative,
 			},
-		},
+		}
+	} else {
+		requestBody = map[string]interface{}{
+			"properties": map[string]interface{}{
+				"kind": rest.PlaneKindAzure,
+				"url":  "http://" + azureURL,
+			},
+		}
 	}
 	body, err := json.Marshal(requestBody)
 	require.NoError(t, err)
-	createPlaneRequest, err := http.NewRequest("PUT", ucp.URL+basePath+"/planes/radius/local", bytes.NewBuffer(body))
+	var createPlaneRequest *http.Request
+	if ucpNative {
+		createPlaneRequest, err = http.NewRequest("PUT", ucp.URL+basePath+"/planes/radius/local", bytes.NewBuffer(body))
+	} else {
+		createPlaneRequest, err = http.NewRequest("PUT", ucp.URL+basePath+"/planes/azure/azurecloud", bytes.NewBuffer(body))
+	}
 	require.NoError(t, err)
 
 	db.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any())
@@ -137,7 +207,11 @@ func registerRP(t *testing.T, ucp *httptest.Server, ucpClient Client, db *store.
 	var responsePlane rest.Plane
 	err = json.Unmarshal(registerPlaneResponseBody, &responsePlane)
 	require.NoError(t, err)
-	assert.Equal(t, testPlane, responsePlane)
+	if ucpNative {
+		assert.Equal(t, testUCPNativePlane, responsePlane)
+	} else {
+		assert.Equal(t, testAzurePlane, responsePlane)
+	}
 }
 
 func createResourceGroup(t *testing.T, ucp *httptest.Server, ucpClient Client, db *store.MockStorageClient) {
@@ -167,18 +241,42 @@ func sendProxyRequest(t *testing.T, ucp *httptest.Server, ucpClient Client, db *
 	db.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, id string, options ...store.GetOptions) (*store.Object, error) {
 		data := store.Object{
 			Metadata: store.Metadata{},
-			Data:     testPlane,
+			Data:     testUCPNativePlane,
+		}
+		return &data, nil
+	})
+
+	proxyRequest, err := http.NewRequest("GET", ucp.URL+basePath+testProxyRequestPath+"?"+apiVersionQueyParam, nil)
+	require.NoError(t, err)
+	proxyRequestResponse, err := ucpClient.httpClient.Do(proxyRequest)
+	require.NoError(t, err)
+	assert.Equal(t, http.StatusOK, proxyRequestResponse.StatusCode)
+	assert.Equal(t, apiVersionQueyParam, proxyRequestResponse.Request.URL.RawQuery)
+	assert.Equal(t, "http://"+proxyRequest.Host+basePath+testProxyRequestPath, proxyRequestResponse.Header["Location"][0])
+
+	proxyRequestResponseBody, err := ioutil.ReadAll(proxyRequestResponse.Body)
+	require.NoError(t, err)
+	responseAppList := []map[string]interface{}{}
+	err = json.Unmarshal(proxyRequestResponseBody, &responseAppList)
+	require.NoError(t, err)
+	assert.Equal(t, applicationList, responseAppList)
+}
+
+func sendProxyRequest_AzurePlane(t *testing.T, ucp *httptest.Server, ucpClient Client, db *store.MockStorageClient) {
+	db.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, id string, options ...store.GetOptions) (*store.Object, error) {
+		data := store.Object{
+			Metadata: store.Metadata{},
+			Data:     testAzurePlane,
 		}
 		return &data, nil
 	})
 
-	proxyRequest, err := http.NewRequest("GET", ucp.URL+basePath+"/planes/radius/local"+testProxyRequestPath+"?"+apiVersionQueyParam, nil)
+	proxyRequest, err := http.NewRequest("GET", ucp.URL+basePath+"/planes/azure/azurecloud"+testProxyRequestAzurePath+"?"+apiVersionQueyParam, nil)
 	require.NoError(t, err)
 	proxyRequestResponse, err := ucpClient.httpClient.Do(proxyRequest)
 	require.NoError(t, err)
 	assert.Equal(t, http.StatusOK, proxyRequestResponse.StatusCode)
 	assert.Equal(t, apiVersionQueyParam, proxyRequestResponse.Request.URL.RawQuery)
-	assert.Equal(t, "http://"+proxyRequest.Host+basePath+testPlaneID+testProxyRequestPath, proxyRequestResponse.Header["Location"][0])
 
 	proxyRequestResponseBody, err := ioutil.ReadAll(proxyRequestResponse.Body)
 	require.NoError(t, err)
diff --git a/pkg/ucp/proxy/arm_test.go b/pkg/ucp/proxy/arm_test.go
index 06e5d4cc0..712187c2f 100644
--- a/pkg/ucp/proxy/arm_test.go
+++ b/pkg/ucp/proxy/arm_test.go
@@ -20,10 +20,11 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-func createTestContext(ctx context.Context, planeURL string, planeID string, httpScheme string, ucpHost string) context.Context {
+func createTestContext(ctx context.Context, planeURL string, planeID string, planeKind string, httpScheme string, ucpHost string) context.Context {
 	ctx = context.WithValue(ctx, UCPRequestInfoField, UCPRequestInfo{
-		PlaneID:    planeID,
 		PlaneURL:   planeURL,
+		PlaneID:    planeID,
+		PlaneKind:  planeKind,
 		HTTPScheme: httpScheme,
 		UCPHost:    ucpHost,
 	})
@@ -54,7 +55,7 @@ func Test_ARM_Baselines(t *testing.T) {
 			pp := NewARMProxy(options, downstream, nil)
 
 			w := httptest.NewRecorder()
-			ctx = createTestContext(ctx, "http://example.com", "/planes/example/local", "http", "localhost:9443")
+			ctx = createTestContext(ctx, "http://example.com", "/planes/example/local", "Azure", "http", "localhost:9443")
 			req := baseline.UpstreamRequest.ToTestRequest(ctx)
 
 			// Send the request
diff --git a/pkg/ucp/proxy/types_test.go b/pkg/ucp/proxy/types_test.go
index a00780f17..114c6dfaa 100644
--- a/pkg/ucp/proxy/types_test.go
+++ b/pkg/ucp/proxy/types_test.go
@@ -12,6 +12,7 @@ import (
 	"net/textproto"
 	"testing"
 
+	"github.com/project-radius/radius/pkg/ucp/rest"
 	"github.com/stretchr/testify/require"
 )
 
@@ -21,6 +22,7 @@ func Test_ConvertHeaderToUCPIDs(t *testing.T) {
 		header         []string
 		planeURL       string
 		planeID        string
+		planeKind      string
 		httpScheme     string
 		ucpHost        string
 		expectedHeader string
@@ -31,6 +33,7 @@ func Test_ConvertHeaderToUCPIDs(t *testing.T) {
 			header:         []string{"http://localhost:7443/subscriptions/sid/resourceGroups/rg/providers/Microsoft.CustomProviders/resourceProviders/radiusv3/Application/testApp/Container/test"},
 			expectedHeader: "http://localhost:9443/planes/test/local/subscriptions/sid/resourceGroups/rg/providers/Microsoft.CustomProviders/resourceProviders/radiusv3/Application/testApp/Container/test",
 			planeURL:       "http://localhost:7443",
+			planeKind:      rest.PlaneKindAzure,
 			planeID:        "/planes/test/local",
 			httpScheme:     "http",
 			ucpHost:        "localhost:9443",
@@ -40,6 +43,7 @@ func Test_ConvertHeaderToUCPIDs(t *testing.T) {
 			header:         []string{"http://localhost:7443/subscriptions/sid/resourceGroups/rg/providers/Microsoft.CustomProviders/resourceProviders/radiusv3/Application/testApp/Container/test"},
 			expectedHeader: "http://localhost:9443/planes/test/local/subscriptions/sid/resourceGroups/rg/providers/Microsoft.CustomProviders/resourceProviders/radiusv3/Application/testApp/Container/test",
 			planeURL:       "http://localhost:7443",
+			planeKind:      rest.PlaneKindAzure,
 			planeID:        "/planes/test/local",
 			httpScheme:     "http",
 			ucpHost:        "localhost:9443",
@@ -49,6 +53,7 @@ func Test_ConvertHeaderToUCPIDs(t *testing.T) {
 			header:         []string{"https://localhost:7443/subscriptions/sid/resourceGroups/rg/providers/Microsoft.CustomProviders/resourceProviders/radiusv3/Application/testApp/Container/test"},
 			expectedHeader: "https://localhost:9443/planes/test/local/subscriptions/sid/resourceGroups/rg/providers/Microsoft.CustomProviders/resourceProviders/radiusv3/Application/testApp/Container/test",
 			planeURL:       "https://localhost:7443",
+			planeKind:      rest.PlaneKindAzure,
 			planeID:        "/planes/test/local",
 			httpScheme:     "https",
 			ucpHost:        "localhost:9443",
@@ -58,6 +63,7 @@ func Test_ConvertHeaderToUCPIDs(t *testing.T) {
 			header:         []string{"https://example.com"},
 			expectedHeader: "https://localhost:9443/planes/test/local/",
 			planeURL:       "https://example.com",
+			planeKind:      rest.PlaneKindAzure,
 			planeID:        "/planes/test/local",
 			httpScheme:     "https",
 			ucpHost:        "localhost:9443",
@@ -67,6 +73,7 @@ func Test_ConvertHeaderToUCPIDs(t *testing.T) {
 			header:         []string{"https://example.com/"},
 			expectedHeader: "https://localhost:9443/planes/test/local/",
 			planeURL:       "https://example.com",
+			planeKind:      rest.PlaneKindAzure,
 			planeID:        "/planes/test/local",
 			httpScheme:     "https",
 			ucpHost:        "localhost:9443",
@@ -76,16 +83,27 @@ func Test_ConvertHeaderToUCPIDs(t *testing.T) {
 			header:         []string{"https://example.com"},
 			expectedHeader: "https://localhost:9443/planes/test/local/",
 			planeURL:       "https://example.com/",
+			planeKind:      rest.PlaneKindAzure,
 			planeID:        "/planes/test/local",
 			httpScheme:     "https",
 			ucpHost:        "localhost:9443",
 		},
+		{
+			name:           LocationHeader,
+			header:         []string{"https://localhost:7443/planes/radius/local/resourceGroups/rg/providers/Applications.Core/Containers/test"},
+			expectedHeader: "https://localhost:9443/planes/radius/local/resourceGroups/rg/providers/Applications.Core/Containers/test",
+			planeURL:       "https://localhost:7443",
+			planeKind:      rest.PlaneKindUCPNative,
+			planeID:        "/planes/radius/local",
+			httpScheme:     "https",
+			ucpHost:        "localhost:9443",
+		},
 	}
 	for _, datum := range positiveTestData {
 		response := http.Response{
 			Header: http.Header{},
 		}
-		ctx := createTestContext(context.Background(), datum.planeURL, datum.planeID, datum.httpScheme, datum.ucpHost)
+		ctx := createTestContext(context.Background(), datum.planeURL, datum.planeID, datum.planeKind, datum.httpScheme, datum.ucpHost)
 		err := convertHeaderToUCPIDs(ctx, datum.name, datum.header, &response)
 		require.NoError(t, err, "%q should have not have failed", datum)
 		// response.SetHeader converts the header into CanonicalMIME format
@@ -104,14 +122,13 @@ func Test_ConvertHeaderToUCPIDs(t *testing.T) {
 			header:         []string{"http://example.com/subscriptions/sid/resourceGroups/rg/providers/Microsoft.CustomProviders/resourceProviders/radiusv3/Application/testApp/Container/test"},
 			expectedHeader: "",
 			planeURL:       "http://localhost:7443",
-			planeID:        "",
 		},
 	}
 	for _, datum := range negativeTestData {
 		response := http.Response{
 			Header: http.Header{},
 		}
-		ctx := createTestContext(context.Background(), datum.planeURL, datum.planeID, datum.httpScheme, datum.ucpHost)
+		ctx := createTestContext(context.Background(), datum.planeURL, datum.planeID, datum.planeKind, datum.httpScheme, datum.ucpHost)
 		err := convertHeaderToUCPIDs(ctx, datum.name, datum.header, &response)
 		require.Error(t, err, "%q should have have failed", datum)
 		require.Equal(t, fmt.Sprintf("PlaneURL: %s received in the request context does not match the url found in %s header", datum.planeURL, datum.name), err.Error())
diff --git a/pkg/ucp/resources/id_test.go b/pkg/ucp/resources/id_test.go
index 420f410db..f1926dfe7 100644
--- a/pkg/ucp/resources/id_test.go
+++ b/pkg/ucp/resources/id_test.go
@@ -247,6 +247,18 @@ func Test_ParseValidIDs(t *testing.T) {
 			types:    []TypeSegment{},
 			provider: "",
 		},
+		{
+			id:       "/planes/radius/local/resourceGroups/r1/providers/Applications.Core/environments/env",
+			expected: "/planes/radius/local/resourceGroups/r1/providers/Applications.Core/environments/env",
+			scopes: []ScopeSegment{
+				{Type: "radius", Name: "local"},
+				{Type: "resourceGroups", Name: "r1"},
+			},
+			types: []TypeSegment{{
+				Type: "Applications.Core/environments", Name: "env"},
+			},
+			provider: "Applications.Core",
+		},
 	}
 
 	for i, v := range values {
diff --git a/pkg/ucp/store/apiserverstore/apiserverclient_test.go b/pkg/ucp/store/apiserverstore/apiserverclient_test.go
index 590fa7472..3b95def5c 100644
--- a/pkg/ucp/store/apiserverstore/apiserverclient_test.go
+++ b/pkg/ucp/store/apiserverstore/apiserverclient_test.go
@@ -690,6 +690,49 @@ func Test_AssignLabels_AllConflict(t *testing.T) {
 	require.Equal(t, expected, set)
 }
 
+func Test_CreateLabelSelector_UCPID(t *testing.T) {
+	query := store.Query{
+		RootScope:    "/planes/radius/local/resourceGroups/cool-group",
+		ResourceType: "Applications.Core/containers",
+	}
+
+	selector, err := createLabelSelector(query)
+	require.NoError(t, err)
+
+	resource := ucpv1alpha1.Resource{
+		Entries: []ucpv1alpha1.ResourceEntry{
+			{
+				// Wrong resource type
+				ID: "/planes/radius/local/resourceGroups/cool-group/providers/Applications.Core/applications/cool-app",
+			},
+		},
+	}
+	set := assignLabels(&resource)
+	require.False(t, selector.Matches(set))
+
+	resource = ucpv1alpha1.Resource{
+		Entries: []ucpv1alpha1.ResourceEntry{
+			{
+				// Different scope
+				ID: "/planes/radius/local/resourceGroups/another-group/providers/Applications.Core/containers/backend",
+			},
+		},
+	}
+	set = assignLabels(&resource)
+	require.False(t, selector.Matches(set))
+
+	resource = ucpv1alpha1.Resource{
+		Entries: []ucpv1alpha1.ResourceEntry{
+			{
+				// Match!
+				ID: "/planes/radius/local/resourceGroups/cool-group/providers/Applications.Core/containers/backend",
+			},
+		},
+	}
+	set = assignLabels(&resource)
+	require.True(t, selector.Matches(set))
+}
+
 func Test_CreateLabelSelector(t *testing.T) {
 	query := store.Query{
 		RootScope:    "/planes/radius/local/resourceGroups/cool-group",
diff --git a/pkg/validator/apivalidator_test.go b/pkg/validator/apivalidator_test.go
index 8c526c4fc..3c99cd8cc 100644
--- a/pkg/validator/apivalidator_test.go
+++ b/pkg/validator/apivalidator_test.go
@@ -25,7 +25,7 @@ const (
 	armIDUrl             = "http://localhost:8080/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/applications.core/environments/env0"
 	ucpIDUrl             = "http://localhost:8080/planes/radius/local/resourceGroups/radius-test-rg/providers/applications.core/environments/env0"
 	operationGetRoute    = "/providers/applications.core/operations"
-	subscriptionPUTRoute = "/subscriptions/{subscriptions}"
+	subscriptionPUTRoute = "/subscriptions/{subscriptions}/resourceGroups/{resourceGroup}"
 )
 
 func TestAPIValidator_ARMID(t *testing.T) {
@@ -38,7 +38,7 @@ func TestAPIValidator_UCPID(t *testing.T) {
 
 func runTest(t *testing.T, resourceIDUrl string) {
 	// Load OpenAPI Spec for applications.core provider.
-	l, err := LoadSpec(context.Background(), "applications.core", swagger.SpecFiles)
+	l, err := LoadSpec(context.Background(), "applications.core", swagger.SpecFiles, "/{rootScope:.*}")
 
 	require.NoError(t, err)
 
diff --git a/pkg/validator/loader_test.go b/pkg/validator/loader_test.go
index 07fdf5aa9..a88137e76 100644
--- a/pkg/validator/loader_test.go
+++ b/pkg/validator/loader_test.go
@@ -62,7 +62,7 @@ func TestParseSpecFilePath(t *testing.T) {
 }
 
 func TestLoader(t *testing.T) {
-	l, err := LoadSpec(context.Background(), "applications.core", swagger.SpecFiles)
+	l, err := LoadSpec(context.Background(), "applications.core", swagger.SpecFiles, "{rootScope:.*}")
 	require.NoError(t, err)
 	v, ok := l.GetValidator("applications.core/environments", "2022-03-15-privatepreview")
 	require.True(t, ok)
diff --git a/pkg/validator/validator_test.go b/pkg/validator/validator_test.go
index cbf8584e9..f5546911e 100644
--- a/pkg/validator/validator_test.go
+++ b/pkg/validator/validator_test.go
@@ -17,7 +17,7 @@ import (
 )
 
 func TestFindParam(t *testing.T) {
-	l, err := LoadSpec(context.Background(), "applications.core", swagger.SpecFiles)
+	l, err := LoadSpec(context.Background(), "applications.core", swagger.SpecFiles, "/{rootScope:.*}")
 	require.NoError(t, err)
 	v, ok := l.GetValidator("applications.core/environments", "2022-03-15-privatepreview")
 	require.True(t, ok)
@@ -47,9 +47,11 @@ func TestToRouteParams(t *testing.T) {
 	ps := v.toRouteParams(req)
 	require.Equal(t, 0, len(ps))
 
-	req, _ = http.NewRequest("", "http://radius/test?api-version=2022-03-15-privatepreview", nil)
+	req, _ = http.NewRequest("", "http://radius/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/applications.core/environments/env0?api-version=2022-03-15-privatepreview", nil)
 	ps = v.toRouteParams(req)
-	require.Equal(t, 1, len(ps))
-	require.Equal(t, "api-version", ps[0].Name)
-	require.Equal(t, "2022-03-15-privatepreview", ps[0].Value)
+	require.Equal(t, 2, len(ps))
+	require.Equal(t, "rootScope", ps[0].Name)
+	require.Equal(t, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg", ps[0].Value)
+	require.Equal(t, "api-version", ps[1].Name)
+	require.Equal(t, "2022-03-15-privatepreview", ps[1].Value)
 }
diff --git a/test/functional/azure/test.go b/test/functional/azure/test.go
index ee592c468..961a9fa48 100644
--- a/test/functional/azure/test.go
+++ b/test/functional/azure/test.go
@@ -37,10 +37,10 @@ func NewTestOptions(t *testing.T) TestOptions {
 	az, err := environments.RequireAzureCloud(env)
 	require.NoError(t, err, "environment was not azure cloud")
 
-	_, radiusConnection, err := kubernetes.CreateAPIServerConnection(az.Context, az.RadiusRPLocalURL)
+	_, radiusConnection, err := kubernetes.CreateLegacyAPIServerConnection(az.Context, az.RadiusRPLocalURL)
 	require.NoError(t, err, "failed to create API Server connection")
 
-	radiusBaseURL, radiusRoundTripper, err := kubernetes.GetBaseUrlAndRoundTripper(az.RadiusRPLocalURL, "api.radius.dev", az.Context)
+	radiusBaseURL, radiusRoundTripper, err := kubernetes.GetLegacyBaseUrlAndRoundTripper(az.RadiusRPLocalURL, "api.radius.dev", az.Context)
 	require.NoError(t, err, "failed to create API Server round-tripper")
 
 	return TestOptions{
diff --git a/test/functional/kubernetes/resources/environment_test.go b/test/functional/kubernetes/resources/environment_test.go
index bd5b573be..feebf6c70 100644
--- a/test/functional/kubernetes/resources/environment_test.go
+++ b/test/functional/kubernetes/resources/environment_test.go
@@ -78,7 +78,7 @@ func Test_EnvironmentWithCoreRP(t *testing.T) {
 						"type":   "Applications.Core/environments@2022-03-15-privatepreview",
 						"properties": map[string]interface{}{
 							"name":     envName,
-							"location": "westus2",
+							"location": "WEST US",
 							"properties": map[string]interface{}{
 								"compute": map[string]interface{}{
 									"kind":       "kubernetes",