PowerShell / Intermediate: binding, errors, modules, data, and tests / Lesson 11
Build typed data and API boundaries
Separate parsing, request construction, transport, authentication, status, schema validation, and retry semantics using offline fixtures.
On this page
Lesson goals
- Validate JSON structure and types before consuming fields.
- Distinguish data serialization from an actual HTTP operation.
- Define pagination, failure, and retry contracts without contacting services.
Parsing data does not prove a service contract
ConvertFrom-Json can transform JSON text into PowerShell data according to supported options, while web cmdlets add transport and response behavior. Invoke-RestMethod and Invoke-WebRequest have different output contracts; neither should be treated as a generic parser with no effects. An actual request can disclose data, use credentials, change server state, or follow redirects. This lesson makes no requests and uses only synthetic in-memory JSON. Keep parser validity, schema validity, HTTP status, authentication, and application completion as separate milestones in any future authorized integration. A successful parse alone establishes none of the later properties.
A response schema includes nulls, types, and cardinality
Validate required fields and distinguish absent keys from explicit nulls. Check whether an endpoint promises one record, an array, or a paged envelope. Numeric-looking identifiers may need to remain strings, and a date string needs its specified timezone and interpretation. Case sensitivity and duplicate-name behavior can differ across JSON consumers, so avoid relying on accidental key conversion. Preserve unknown fields only according to a deliberate compatibility policy. A local object that looks correct in a table may still violate the wire schema when serialized with insufficient depth or unsupported values.
Parse only a declared synthetic response
The PowerShell illustration parses an in-memory response and projects the names from its declared items array. It intentionally contains no URI, token, credential, web cmdlet, or configured file. The engine is absent, so the example remains non-runnable and its expected record contract is explained rather than claimed as tested. A real integration should validate status and content type before applying a schema, then handle malformed or unexpected data as a truthful failure. Do not use a catch-all empty list to make an unavailable service indistinguishable from a valid empty result.
$text = '{"items":[{"id":"001","name":"review"}],"next":null}'
$response = $text | ConvertFrom-Json
$response.items | Select-Object -ExpandProperty name
The intended value is review and the identifier remains textual. No PowerShell parser or HTTP engine was executed, and no endpoint is contacted.
Pagination and retries need bounded ownership
A paged API can repeat, omit, or reorder data according to its consistency contract. Bound page count, response size, and continuation handling, and do not follow an unvalidated next link to an unrelated authority. Retry policy must distinguish transient failure, permanent rejection, and uncertain completion of a state-changing request. A lost response does not prove the server did nothing. Use operation identity and idempotency support where the application defines them, not an unlimited retry loop. Keep tokens and request payloads out of routine logs and test these paths with non-secret fixtures before any authorized service operation.
Validate the fixture without pretending to test HTTP
An offline parser/schema check can establish that this fixture has an items array, string identifiers, and a known terminal continuation value. It does not test TLS, authentication, web-cmdlet behavior, response streaming, or service availability. Preserve the distinction in reports. A later authorized runtime suite should test error status, malformed JSON, missing keys, nulls, empty pages, repeated continuations, and cancellation. Separate request construction from transport so most validation can remain local and deterministic. The course executes only the following Python model and does not install or configure any service client.
import json
response = json.loads('{"items":[{"id":"001","name":"review"}],"next":null}')
assert isinstance(response['items'], list)
assert all(isinstance(item['id'], str) for item in response['items'])
print(','.join(item['name'] for item in response['items']))
print('terminal=' + str(response['next'] is None))
review
terminal=True
This validates Python JSON data only. It opens no socket and proves no PowerShell web behavior or real endpoint contract.
Common errors and fixes
HTTP failure becomes an empty successful collection
- Why it happens
- Transport and valid empty results were conflated.
- How to fix it
- Preserve status and report the documented failure.
- Prevent it next time
- Test unavailable and valid-empty cases separately.
A numeric-looking identifier loses leading zeros
- Why it happens
- Identity data was coerced into a quantity.
- How to fix it
- Preserve the wire schema’s intended type.
- Prevent it next time
- Include identifier round-trip cases.
A next link is followed without a boundary check
- Why it happens
- Response data was allowed to choose arbitrary destinations.
- How to fix it
- Validate continuation scope and bound the traversal.
- Prevent it next time
- Keep request construction separate from transport.
Check your understanding
1. Why should null continuation and missing continuation be distinguished?
Show worked solution
The API schema may define null as a valid terminal page while a missing field indicates malformed or incompatible data. Apply that documented contract instead of treating every false-like value as successful completion.
2. A state-changing request times out. Is immediate blind retry justified?
Show worked solution
No. The operation may have completed before the response was lost. Reconcile with the application’s operation identity and retry contract, preserving uncertainty and bounded attempts rather than assuming timeout means rollback.
Key takeaways
- Separate parser, schema, transport, identity, and completion.
- Bound pagination and retries and preserve wire types.