diff --git a/samples/shadow-api-detection/.devproxy/api.contoso.com.json b/samples/shadow-api-detection/.devproxy/api.contoso.com.json new file mode 100644 index 0000000..972296f --- /dev/null +++ b/samples/shadow-api-detection/.devproxy/api.contoso.com.json @@ -0,0 +1,146 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Contoso Products API", + "description": "API for managing products in the Contoso catalog", + "version": "v1.0" + }, + "servers": [ + { + "url": "https://api.contoso.com" + } + ], + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "price": { + "type": "number" + }, + "category": { + "type": "string" + } + } + } + } + }, + "paths": { + "/products": { + "get": { + "summary": "Get all products", + "operationId": "getProducts", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + }, + "post": { + "summary": "Create a product", + "operationId": "createProduct", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + }, + "/products/{product-id}": { + "get": { + "summary": "Get product by ID", + "operationId": "getProductById", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + }, + "patch": { + "summary": "Update product by ID", + "operationId": "updateProductById", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + }, + "delete": { + "summary": "Delete product by ID", + "operationId": "deleteProductById", + "responses": { + "204": { + "description": "No Content" + } + } + }, + "parameters": [ + { + "name": "product-id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + } +} diff --git a/samples/shadow-api-detection/.devproxy/devproxyrc.json b/samples/shadow-api-detection/.devproxy/devproxyrc.json new file mode 100644 index 0000000..4f28186 --- /dev/null +++ b/samples/shadow-api-detection/.devproxy/devproxyrc.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/rc.schema.json", + "record": true, + "plugins": [ + { + "name": "CrudApiPlugin", + "enabled": true, + "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll", + "configSection": "productsApi" + }, + { + "name": "OpenApiSpecGeneratorPlugin", + "enabled": true, + "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll" + }, + { + "name": "ApiCenterOnboardingPlugin", + "enabled": true, + "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll", + "configSection": "apiCenterOnboardingPlugin" + }, + { + "name": "PlainTextReporter", + "enabled": true, + "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll" + } + ], + "urlsToWatch": [ + "https://api.contoso.com/*", + "https://jsonplaceholder.typicode.com/*" + ], + "productsApi": { + "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/crudapiplugin.schema.json", + "apiFile": "products-api.json" + }, + "apiCenterOnboardingPlugin": { + "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/apicenteronboardingplugin.schema.json", + "subscriptionId": "your-subscription-id", + "resourceGroupName": "your-resource-group", + "serviceName": "your-api-center" + } +} diff --git a/samples/shadow-api-detection/.devproxy/products-api.json b/samples/shadow-api-detection/.devproxy/products-api.json new file mode 100644 index 0000000..f859ec0 --- /dev/null +++ b/samples/shadow-api-detection/.devproxy/products-api.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.0.0/crudapiplugin.apifile.schema.json", + "baseUrl": "https://api.contoso.com/products", + "dataFile": "products-data.json", + "actions": [ + { + "action": "getAll" + }, + { + "action": "getOne", + "url": "/{product-id}", + "query": "$.[?(@.id == '{product-id}')]" + }, + { + "action": "create" + }, + { + "action": "merge", + "url": "/{product-id}", + "query": "$.[?(@.id == '{product-id}')]" + }, + { + "action": "delete", + "url": "/{product-id}", + "query": "$.[?(@.id == '{product-id}')]" + } + ] +} diff --git a/samples/shadow-api-detection/.devproxy/products-data.json b/samples/shadow-api-detection/.devproxy/products-data.json new file mode 100644 index 0000000..9af91d8 --- /dev/null +++ b/samples/shadow-api-detection/.devproxy/products-data.json @@ -0,0 +1,20 @@ +[ + { + "id": "1", + "name": "Widget A", + "price": 29.99, + "category": "Electronics" + }, + { + "id": "2", + "name": "Gadget B", + "price": 49.99, + "category": "Electronics" + }, + { + "id": "3", + "name": "Tool C", + "price": 19.99, + "category": "Hardware" + } +] diff --git a/samples/shadow-api-detection/.gitignore b/samples/shadow-api-detection/.gitignore new file mode 100644 index 0000000..9636a11 --- /dev/null +++ b/samples/shadow-api-detection/.gitignore @@ -0,0 +1 @@ +*Reporter* diff --git a/samples/shadow-api-detection/README.md b/samples/shadow-api-detection/README.md new file mode 100644 index 0000000..e7f15e9 --- /dev/null +++ b/samples/shadow-api-detection/README.md @@ -0,0 +1,57 @@ +# Find shadow APIs with Azure API Center + +## Summary + +This sample demonstrates how to use Dev Proxy to detect APIs not registered in Azure API Center (shadow APIs). Shadow APIs are APIs that your application uses but aren't registered in your organization's API catalog. By detecting shadow APIs, you can improve API governance, compliance, and security by ensuring all APIs are properly cataloged. + + + +## Compatibility + +![Dev Proxy v2.0.0](https://aka.ms/devproxy/badge/v2.0.0) + +## Contributors + +- [Waldek Mastykarz](https://github.com/waldekmastykarz) + +## Version history + +Version|Date|Comments +-------|----|-------- +1.0|January 6, 2026|Initial release + +## Prerequisites + +- [Azure API Center](https://learn.microsoft.com/azure/api-center/) +- [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension for Visual Studio Code + +## Minimal path to awesome + +- Create Azure API Center instance + - Get the API Center instance name, resource group name and subscription ID +- In API Center, create a new API and import the OpenAPI spec from the `.devproxy/api.contoso.com.json` file +- In the `.devproxy/devproxyrc.json` file, in the `apiCenterOnboardingPlugin` update the API Center information +- Start Dev Proxy by running `devproxy --config-file .devproxy/devproxyrc.json` +- In VSCode, open the `shadow-api-detection.http` file and run the requests to the API +- In the terminal where Dev Proxy is running, press `s` to stop recording +- Dev Proxy will generate a report showing which APIs are registered and which are shadow APIs + +## Help + +We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues. + +You can try looking at [issues related to this sample](https://github.com/pnp/proxy-samples/issues?q=label%3A%22sample%3A%20shadow-api-detection%22) to see if anybody else is having the same issues. + +If you encounter any issues using this sample, [create a new issue](https://github.com/pnp/proxy-samples/issues/new). + +Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/proxy-samples/issues/new). + +## Disclaimer + +**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** + +![](https://m365-visitor-stats.azurewebsites.net/SamplesGallery/pnp-devproxy-shadow-api-detection) diff --git a/samples/shadow-api-detection/assets/sample.json b/samples/shadow-api-detection/assets/sample.json new file mode 100644 index 0000000..45f09b1 --- /dev/null +++ b/samples/shadow-api-detection/assets/sample.json @@ -0,0 +1,82 @@ +[ + { + "name": "pnp-devproxy-shadow-api-detection", + "source": "pnp", + "title": "Find shadow APIs with Azure API Center", + "shortDescription": "Detect APIs not registered in Azure API Center (shadow APIs) to improve API governance, compliance, and security before reaching production.", + "url": "https://github.com/pnp/proxy-samples/tree/main/samples/shadow-api-detection", + "downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/proxy-samples/tree/main/samples/shadow-api-detection", + "longDescription": [ + "Detect APIs not registered in Azure API Center (shadow APIs) to improve API governance, compliance, and security before reaching production." + ], + "creationDateTime": "2026-01-10", + "updateDateTime": "2026-01-10", + "products": [ + "Dev Proxy" + ], + "metadata": [ + { + "key": "SAMPLE ID", + "value": "shadow-api-detection" + }, + { + "key": "PRESET", + "value": "Yes" + }, + { + "key": "MOCKS", + "value": "Yes" + }, + { + "key": "PLUGIN", + "value": "No" + }, + { + "key": "PROXY VERSION", + "value": "v2.0.0" + } + ], + "thumbnails": [ + { + "type": "image", + "order": 100, + "url": "https://github.com/pnp/proxy-samples/raw/main/samples/shadow-api-detection/assets/screenshot.png", + "alt": "Dev Proxy detecting shadow APIs not registered in Azure API Center" + } + ], + "authors": [ + { + "gitHubAccount": "waldekmastykarz", + "pictureUrl": "https://github.com/waldekmastykarz.png", + "name": "Waldek Mastykarz" + } + ], + "references": [ + { + "name": "ApiCenterOnboardingPlugin reference", + "description": "Learn more about the ApiCenterOnboardingPlugin", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/technical-reference/apicenteronboardingplugin" + }, + { + "name": "How to find shadow APIs", + "description": "Step-by-step guide on detecting shadow APIs with Dev Proxy", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/how-to/check-shadow-apis" + }, + { + "name": "Get started with the Dev Proxy", + "description": "The tutorial will introduce you to the Dev Proxy and show you how to use its features.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/get-started" + }, + { + "name": "Use Dev Proxy in CI/CD scenarios", + "description": "Learn how to integrate Dev Proxy into your CI/CD pipelines", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/how-to/use-dev-proxy-in-ci-cd-overview" + }, + { + "name": "Azure API Center documentation", + "description": "Learn about Azure API Center for API governance", + "url": "https://learn.microsoft.com/azure/api-center/" + } + ] + } +] diff --git a/samples/shadow-api-detection/shadow-api-detection.http b/samples/shadow-api-detection/shadow-api-detection.http new file mode 100644 index 0000000..010005d --- /dev/null +++ b/samples/shadow-api-detection/shadow-api-detection.http @@ -0,0 +1,19 @@ +# Registered API - registered in API Center +# This call should be marked as "registered" in the report + +### Get all products (registered API) +GET https://api.contoso.com/products + +### Get specific product (registered API) +GET https://api.contoso.com/products/1 + +### + +# Shadow API - NOT registered in API Center +# This call should be marked as "new/unregistered" in the report + +### Get posts from shadow API (unregistered) +GET https://jsonplaceholder.typicode.com/posts + +### Get specific post from shadow API (unregistered) +GET https://jsonplaceholder.typicode.com/posts/1