This skill should be used when the user asks to "validate a sample", "check my sample", "review before submitting", "verify sample structure", or needs to validate a Dev Proxy sample for correctness...
This skill guides validation of Dev Proxy samples to catch common mistakes before submission. Run through these checks to ensure the sample meets repository standards.
ā ļø MANDATORY: You MUST run
jsonckto validate all JSON files against their schemas. Do NOT skip this step or rely on VS Code's JSON validation alone ā it misses errors that Dev Proxy will catch at runtime. Install jsonck first:npm install -g jsonck
jsonck reads the $schema property from JSON files automatically, downloads remote schemas, and validates in one step ā no temp files or manual schema wrangling needed.
# Validate all standalone config files at once
sample="samples/{sample-name}"
jsonck "$sample"/.devproxy/*.json
For structured output (useful in CI or scripts), add --json:
jsonck "$sample"/.devproxy/*.json --json
Note: Install jsonck first with npm install -g jsonck. Requires Node.js >= 20.
Dev Proxy configs have embedded plugin config sections with their own $schema. Extract each section with jq and pipe to jsonck ā it picks up the $schema from the piped JSON automatically:
sample="samples/{sample-name}"
f="$sample/.devproxy/devproxyrc.json"
# Find all config sections that have a $schema and validate each
jq -r '[keys[] as $k | select((.[$k] | type) == "object" and (.[$k]["$schema"] // null) != null) | $k] | .[]' "$f" | while read -r section; do
echo "Validating $section..."
jq ".\"$section\"" "$f" | jsonck - || echo "ā FAILED: $section"
done
Verify required files exist:
samples/{sample-name}/
āāā .devproxy/
ā āāā devproxyrc.json ā
ā āāā [mocks.json, errors.json, etc.] (if needed)
āāā README.md ā
āāā assets/
āāā sample.json ā
Important: All Dev Proxy config files go in .devproxy/ folder.
Check: Every Dev Proxy config file has a $schema defined.
Required schemas:
devproxyrc.json) must have $schema$schema$schemaException: CRUD API data files don't require schemas.
Example of proper schema coverage:
{
"$schema": ".../rc.schema.json", // ā Main config schema
"plugins": [...],
"mockResponsePlugin": {
"$schema": ".../mockresponseplugin.schema.json", // ā Plugin config schema
"mocksFile": "mocks.json"
}
}
Check: All $schema URLs validate against their schemas. Run jsonck on all files and plugin config sections.
Common issues:
$schema on main config file$schema on plugin config sectionsmockresponseplugin.schema.json = plugin config (needs mocksFile)mockresponseplugin.mocksfile.schema.json = mock data (needs mocks array)body: null not allowed (use body: "")| Field | Check |
|---|---|
name |
Matches pnp-devproxy-{folder-name} |
source |
Is "pnp" |
url |
Matches https://github.com/pnp/proxy-samples/tree/main/samples/{folder-name} |
downloadUrl |
Matches https://pnp.github.io/download-partial/?url=... |
shortDescription |
Non-empty, describes the sample |
longDescription[0] |
Identical to shortDescription |
creationDateTime |
Format YYYY-MM-DD |
updateDateTime |
Format YYYY-MM-DD |
products |
Contains ["Dev Proxy"] |
SAMPLE ID |
Matches folder name |
PROXY VERSION |
Matches README badge version |
thumbnails[0].url |
Points to existing screenshot or has placeholder |
authors |
Has at least one author with gitHubAccount, name |
Check: Is PRESET value correct?
"Yes" = Sample is reusable for other APIs (generic config)"No" = Sample is specific to a particular API or scenarioCommon mistake: Setting PRESET to "Yes" just because it has a config file. Most samples should be "No".
| Element | Check |
|---|---|
| Title | Descriptive, not technical |
| Summary | Explains what and why |
| Screenshot | Exists or has placeholder |
| Badge URL | Must use https://aka.ms/devproxy/badge/vX.X.X (not shields.io) |
| Badge version | Matches PROXY VERSION in sample.json |
| Contributors | GitHub profile links |
| Version history | Date matches updateDateTime in sample.json |
| Minimal path | Steps are complete and correct |
| Startup command | Correct (see below) |
| curl commands | Include -ikx http://127.0.0.1:8000 |
| Tracking pixel |  |
Check: Is the startup command correct?
Default config locations (just use devproxy):
devproxyrc.jsondevproxyrc.jsonc.devproxy/devproxyrc.json.devproxy/devproxyrc.jsoncCustom config (use devproxy --config-file custom.json):
Common mistake: Using devproxy --config-file devproxyrc.json ā unnecessary!
Check: Dates match between files.
| Location | Format | Example |
|---|---|---|
sample.json ā updateDateTime |
YYYY-MM-DD |
2026-01-18 |
| README ā Version history | Month DD, YYYY |
January 18, 2026 |
Both should represent the same date.
Check: All curl commands route through Dev Proxy.
Correct:
curl -ikx http://127.0.0.1:8000 https://api.example.com/endpoint
Incorrect:
curl https://api.example.com/endpoint # Bypasses Dev Proxy!
Flags explained:
-i = Include response headers-k = Allow insecure (for SSL issues)-x http://127.0.0.1:8000 = Route through proxyCheck: For scenarios requiring multiple requests, is there a demo app?
Use demo app when:
Acceptable curl when:
Check: Do URLs use proxy-friendly domains?
Avoid these TLDs ā they're often excluded from system proxy settings:
.local ā Reserved for mDNS/Bonjour, typically bypasses proxy.localhost ā Loopback, excluded by most systems.internal ā Often excluded in enterprise environments.test ā Reserved TLD, may have issuesUse instead:
.contoso.com ā Microsoft's example domain (safe, won't resolve).example.com ā IANA reserved for documentation.fabrikam.com ā Another Microsoft example domainWhy this matters: When browsers/apps detect .local domains, they often skip the proxy entirely, making Dev Proxy unable to intercept requests.
Check in files:
urlsToWatch in devproxyrc.jsonbaseUrl in CRUD API files| Mistake | How to Fix |
|---|---|
Missing $schema on main config |
Add $schema to devproxyrc.json |
Missing $schema on plugin config section |
Add $schema to each plugin config section |
PRESET: "Yes" for specific samples |
Change to "No" unless truly reusable |
--config-file devproxyrc.json |
Remove --config-file, just use devproxy |
Config files not in .devproxy/ |
Move all Dev Proxy files to .devproxy/ folder |
shortDescription ā longDescription[0] |
Make them identical |
| Wrong date format | Use YYYY-MM-DD in JSON, Month DD, YYYY in README |
| Dates don't match | Sync dates between sample.json and README |
| curl without proxy | Add -ikx http://127.0.0.1:8000 |
| Wrong schema type | Match schema to file purpose |
| Missing tracking pixel | Add at end of README |
Using .local TLD |
Change to .contoso.com or similar |
| Wrong badge URL (shields.io) | Use https://aka.ms/devproxy/badge/vX.X.X |
Run this to check common issues:
sample="samples/{sample-name}"
# Check required files
echo "=== Required Files ==="
[ -d "$sample/.devproxy" ] && echo "ā .devproxy/" || echo "ā .devproxy/ folder missing"
[ -f "$sample/.devproxy/devproxyrc.json" ] && echo "ā .devproxy/devproxyrc.json" || echo "ā .devproxy/devproxyrc.json missing"
[ -f "$sample/README.md" ] && echo "ā README.md" || echo "ā README.md missing"
[ -f "$sample/assets/sample.json" ] && echo "ā assets/sample.json" || echo "ā assets/sample.json missing"
# Check metadata name matches folder
echo -e "\n=== Metadata Check ==="
folder=$(basename "$sample")
name=$(grep -o '"name": "[^"]*"' "$sample/assets/sample.json" | head -1 | cut -d'"' -f4)
expected="pnp-devproxy-$folder"
[ "$name" = "$expected" ] && echo "ā name matches folder" || echo "ā name '$name' should be '$expected'"
# Check date format
echo -e "\n=== Date Format ==="
grep -E '"(creation|update)DateTime"' "$sample/assets/sample.json" | grep -qE '[0-9]{4}-[0-9]{2}-[0-9]{2}' && echo "ā Date format OK" || echo "ā Check date format"
# Check shortDescription equals longDescription
echo -e "\n=== Description Match ==="
short=$(grep '"shortDescription"' "$sample/assets/sample.json" | cut -d'"' -f4)
long=$(grep -A1 '"longDescription"' "$sample/assets/sample.json" | tail -1 | tr -d '[]"' | xargs)
[ "$short" = "$long" ] && echo "ā Descriptions match" || echo "ā shortDescription ā longDescription[0]"
# Check tracking pixel
echo -e "\n=== Tracking Pixel ==="
grep -q "m365-visitor-stats.azurewebsites.net/SamplesGallery/pnp-devproxy-$folder" "$sample/README.md" && echo "ā Tracking pixel OK" || echo "ā Missing/wrong tracking pixel"
# Check badge URL uses aka.ms
echo -e "\n=== Badge URL ==="
grep -q "https://aka.ms/devproxy/badge/" "$sample/README.md" && echo "ā Badge uses aka.ms" || echo "ā Badge should use https://aka.ms/devproxy/badge/vX.X.X"
Before creating a PR:
.devproxy/ folderpnp-devproxy-{folder-name}https://aka.ms/devproxy/badge/vX.X.X.local or other excluded TLDs