What you'll learn
This lesson brings the first five lessons together. You'll reason about an IT automation pipeline, handle untrusted input, produce reviewable reports and prepare for the final Network Inventory Analyzer.
- Describe a read-only Python automation pipeline from input through verification.
- Interpret mock HTTP response status codes, JSON payloads and common API failure modes.
- Distinguish authentication from authorization and keep secrets out of source code.
- Validate structured records without silently counting unknown data as healthy.
- Correlate fictional log events with validated inventory hosts.
- Explain dry-run behavior, bounded retries and scope of privileged changes.
- Test edge cases and return a deterministic machine-readable report.
Think in workflows, not isolated snippets
A useful IT automation script has a repeatable pipeline: receive an input, validate its format, normalize values, apply a decision rule, and produce a reviewable result. A script that prints 'done' without checking its actual output is not reliable. Keep parsing, business rules and reporting in separate functions so you can test each stage. In this course, all inventories and responses are fictional, and Python runs only inside an isolated browser workbench.
Input → parse → validate → decide → report
Each step has a contract. A file may open successfully but contain incorrect columns; a JSON payload may parse but omit expected keys.
Make output inspectable
Return structured values and include invalid-record counts, source notes and deterministic ordering. Never silently relabel missing evidence as healthy.
def summarize(records):
offline = sorted(r['host'] for r in records
if r.get('status') == 'offline')
return {'offline_hosts': offline, 'count': len(offline)}
print(summarize([{'host':'AP-02','status':'offline'}]))What does the function return, and why is that more reusable than a print-only helper? Reveal explanation after you predict.
It returns a dictionary with count 1 and offline_hosts containing AP-02. The caller can save, format, or test the dictionary; printing only would not give subsequent code the report value.
Understand requests and response codes
An API exposes a structured interface to another service. A GET request is commonly used to retrieve records, while POST creates or initiates operations; PUT and PATCH modify resources and DELETE removes them. The server returns an HTTP status code and often a JSON payload. Success is not the same as usable data: a 200 response can contain incomplete records. For a beginner browser lesson, use offline response fixtures—not outbound network requests, credentials, or live endpoints.
Status code families
2xx indicates success, 3xx redirects, 4xx client-side request problems, and 5xx server problems. 401 means unauthenticated; 403 means access is denied, even if identity is known.
Check before parsing
Use the status code to decide whether a response should be processed. Handle missing data separately after JSON parsing. A 204 response has no content.
response = {'status_code': 503, 'json': None}
if response['status_code'] >= 500:
print('service error')
elif response['status_code'] == 200:
print('check payload')
else:
print('review response')Why shouldn't a script call json.loads on every HTTP response unconditionally? Reveal explanation after you predict.
A failed request may contain HTML, an error body, or no content. Check status first, then confirm the expected body and required JSON fields before using it.
Inspect a response before trusting its contents.
Pick a fictional HTTP response. The decision depends on both status and payload shape. No outbound request is sent.
Successful response status
Parsing and validating are separate steps.
{"devices":[{"host":"SW-01","status":"online"},{"host":"AP-02","status":"offline"}]}Decision: Accepted: validated devices array
Never paste API tokens or live customer responses into educational tools.
Handle authentication as an operational boundary
Some APIs require credentials such as tokens or API keys, often supplied through an Authorization header. Authentication establishes identity; authorization determines allowed actions. Do not hardcode real tokens in source files, paste secrets into a learning workbench or include them in log output. Production scripts usually read credentials from a protected secret manager or runtime environment and use least-privilege, short-lived credentials when available.
Read-only first
Start with inventory retrieval and report generation. A script that changes devices, accounts, or firewall policy needs separately approved scope, a change plan and rollback.
Redact sensitive details
Errors and logs should provide status and context, not raw Authorization headers, tokens, passwords, or customer records.
response = {'status_code': 401}
if response['status_code'] == 401:
print('authentication required')
elif response['status_code'] == 403:
print('permission denied')
else:
print('check request result')How are HTTP 401 and HTTP 403 different, and what should an automation report? Reveal explanation after you predict.
401 generally indicates that valid authentication credentials are missing or inadequate; 403 indicates that the request is forbidden. Report the distinction and do not expose the token.
Validate types, fields and missing evidence
Data from exports and simulated API responses can be inconsistent. A host may be blank, latency text may not convert to an integer, and a status may arrive as ' OFFLINE '. Normalize valid values while rejecting malformed ones. Keep an invalid-row count separate from offline counts. If a field is missing, mark it unknown or invalid according to the contract—do not default to online. Sorting results makes repeated reports stable and easier to compare.
Know your accepted values
Define rules for hosts, status, and numeric measurements. Test empty or whitespace-only values and negative numbers.
Count rejected rows
A successful report should include what was skipped. Reports that silently drop errors are hard to audit.
def valid_latency(value):
try:
number = int(value)
except (TypeError, ValueError):
return False
return number >= 0
print(valid_latency('80'))
print(valid_latency('N/A'))Which value passes the validator, and why must invalid values be tracked separately? Reveal explanation after you predict.
'80' passes; 'N/A' fails integer conversion. A failed record is an input-quality issue, not evidence of a healthy or unhealthy device.
Join log evidence to inventory records
An inventory identifies devices and their attributes; a log records observations over time. A useful report can cross-reference a hostname from an alert with validated inventory records. Do not treat alerts from unknown hostnames as verified inventory devices. In a simplified fictional log, each line contains a severity, hostname and event; production logs require timestamp and format handling, deduplication and retention policies.
Choose stable identifiers
Normalize hostnames before comparison so 'ap-02' and 'AP-02' refer to the same fictional device under an explicitly case-insensitive rule.
Keep unknown alerts visible
An alert for a host not found in inventory should be identified as unmatched evidence, not attributed to another device.
known = {'SW-01', 'AP-02'}
log_lines = ['ALERT AP-02 link_down', 'ALERT GHOST-9 link_down']
matched = []
for line in log_lines:
severity, host, event = line.split()
if severity == 'ALERT' and host in known:
matched.append(host)
print(sorted(matched))Why doesn't GHOST-9 appear in the matched results? Reveal explanation after you predict.
It is not in the verified known-host set. A separate unmatched-alert count could preserve that evidence instead of treating it as a known inventory device.
Dry runs, repeatability and scope
Automating a change is different from automating an observation. A dry-run mode shows proposed actions without applying them. For destructive or privileged operations, define approved targets, expected effects, rollback and validation before execution. In this beginner course, every task is read-only against fictional data, with no remote connections. A reliable report should be deterministic: the same input should produce the same output and rerunning it should not accumulate duplicate records.
Idempotence matters
A repeatable inventory report should not append duplicate summaries on every run. If writing a report file, deliberately replace the generated report rather than append uncontrolled entries.
Retries need a policy
A transient 503 may merit a bounded retry with backoff in real systems; a 401 or 403 should generally trigger a credential/permission investigation, not endless retries.
def plan_action(host, dry_run=True):
if dry_run:
return f'WOULD check {host}'
return f'Check requested for {host}'
print(plan_action('SW-01'))Does this sample contact SW-01 or make a change when dry_run=False? Reveal explanation after you predict.
No. Both branches only return text in this illustrative example. Real side-effecting actions would require separate implementations, permissions and approvals.
Test edge cases rather than memorizing one output
A script that passes one demonstration can still be wrong. Use assert statements and simple helper tests to prove requirements for different data shapes: empty inputs, duplicate hostnames, missing fields, malformed numbers, case changes and unexpected log hosts. A test should compare the full returned result, not just search for a string in console output. When tests fail, inspect the failing case and fix the underlying function instead of hardcoding the expected answer.
Test the boundary
If 200 ms is considered critical, verify results at 199, 200 and 201. If unknown status is allowed, ensure it is not counted as online.
Test twice, at least
Different fixtures reveal logic that accidentally depends on the order, number or name of sample records.
def is_critical(value):
return value >= 200
assert is_critical(199) is False
assert is_critical(200) is True
print('boundary checks passed')What happens if the implementation uses > 200 rather than >= 200? Reveal explanation after you predict.
The second assertion fails at the boundary value 200, revealing the off-by-one comparison that a single high-latency example could miss.
Create a report someone else can use
A technician's automation should produce a useful artifact: offline hosts, valid record counts, malformed-row counts, matched alerts, and perhaps unmatched log evidence. Keep output stable, document how missing data was handled and avoid presenting estimates as confirmed health. A JSON report is easy to inspect and exchange; a CSV summary can be convenient for reviewers. The final capstone combines all six lessons in an offline Network Inventory Analyzer.
Separate findings from confidence
A malformed row is not an offline device and not proof of online operation. Show rejected counts alongside confirmed findings.
Make the report reproducible
Keep processing rules in functions; sort hostnames and write JSON with sort_keys=True. Verify the result before communicating success.
import json
report = {'offline_hosts': ['AP-02'], 'invalid_rows': 1,
'matched_alert_hosts': ['AP-02']}
print(json.dumps(report, sort_keys=True))What should a reviewer learn from invalid_rows=1 in this report? Reveal explanation after you predict.
At least one source record was rejected during validation, so the report may not cover the entire supplied inventory. The operator should investigate that quality gap rather than assume it is healthy.
Write the automation, then prove it works
Complete six code challenges covering HTTP decisions, JSON shape, validation, log correlation, dry-run behavior and boundary tests. After the clinic, the final capstone tests a complete analyzer using several different datasets.
Write it. Run it. Understand it.
Use offline API fixtures, data validation, log evidence and assertions to build reliable read-only IT workflows.
Classify simulated API responses
Write classify_response(status_code) for a fictional API: 200 returns 'ok'; 401 returns 'authenticate'; 403 returns 'forbidden'; codes 500 or higher return 'server_error'; all other statuses return 'review'. Call it for 200, 401, 403, 503 and 404. Print exactly 'ok,authenticate,forbidden,server_error,review'. Do not send requests.
ok,authenticate,forbidden,server_error,reviewTry solving it before asking for help. Hints never show a completed program.
Your printed output and errors will appear here.
Run the code, then step through the executed lines to watch variable values change.
From practice scripts to an independent investigation.
Finish the six automation exercises, then build the Network Inventory Analyzer. The capstone deliberately uses different fixtures to check whether your functions generalize.
Continue to six automation challenges →View the final capstone →Reference material
Use original documentation when interpreting status codes, parsing data and testing your scripts. API examples in this course are simulations, not live integrations.
