Visit here for our full Cisco 350-901 exam dumps and practice test questions.
Question 101:
A developer needs to implement API authentication using OAuth 2.0. Which OAuth 2.0 grant type is most appropriate for server-to-server API communication without user interaction?
A) Authorization Code Grant
B) Client Credentials Grant for machine-to-machine authentication
C) Implicit Grant
D) Resource Owner Password Credentials Grant
Answer: B
Explanation:
Client Credentials Grant provides secure server-to-server authentication without user involvement, making option B the correct answer. OAuth 2.0 supports multiple grant types designed for different authentication scenarios, and selecting the appropriate grant type is critical for security. Client Credentials Grant authenticates the application itself rather than a user. The client application presents its client ID and client secret directly to the authorization server, receiving an access token for accessing protected resources. This grant type is specifically designed for machine-to-machine communication where no user is present. Authentication flow involves the client sending credentials (client ID and secret) to the token endpoint, the authorization server validating credentials and issuing access token, and the client using the access token in API requests via Authorization header. This simplified flow eliminates user interaction steps. Token scope restricts what the client application can access. Client credentials tokens typically have limited scope appropriate for the service account’s needs, implementing principle of least privilege. Token expiration provides security through short-lived access tokens requiring periodic renewal. Expired tokens must be refreshed by re-authenticating with client credentials, enabling credential rotation and limiting exposure window. Service account pattern treats the client application as a service account with its own identity and permissions. This approach maps naturally to backend services, microservices, or scheduled jobs requiring API access. Credential security requires protecting client secrets like passwords through secure storage in secrets management systems, rotation policies changing secrets periodically, and audit logging tracking secret usage. Comparison with other grant types shows Authorization Code Grant requires user interaction through browser redirects making it unsuitable for server-to-server scenarios. Implicit Grant is deprecated due to security issues and designed for browser-based apps. Resource Owner Password Credentials Grant requires handling user credentials directly, which is discouraged. Use cases for Client Credentials Grant include microservice authentication where Service A calls Service B, batch jobs accessing APIs for data processing, and monitoring systems querying APIs for metrics. Option A is incorrect because Authorization Code Grant requires user browser interaction for authorization, making it inappropriate for automated server-to-server communication. Option C is incorrect because Implicit Grant is deprecated, designed for single-page applications, and inappropriate for server-side scenarios. Option D is incorrect because Password Credentials Grant requires handling user passwords directly, which is security anti-pattern except in legacy migration scenarios.
Question 102:
A developer needs to implement input validation to prevent injection attacks. What validation approach should be used for API endpoints?
A) Trust all input without validation
B) Implement whitelist-based validation, parameterized queries, input sanitization, and context-specific output encoding to prevent injection attacks
C) Only validate data from untrusted sources
D) Remove all special characters from input
Answer: B
Explanation:
Whitelist validation, parameterized queries, sanitization, and output encoding provide comprehensive injection attack prevention, making option B the correct answer. Input validation is the first defense against injection vulnerabilities including SQL injection, command injection, and cross-site scripting. Whitelist-based validation defines allowed input patterns and rejects anything not matching. For example, alphanumeric-only fields reject special characters, email fields validate against email format regex, and numeric fields accept only digits. Whitelisting is more secure than blacklisting since it’s impossible to enumerate all malicious inputs. Parameterized queries prevent SQL injection by separating SQL code from data. Instead of string concatenation like “SELECT * FROM users WHERE id=” + userId, parameterized queries use placeholders: “SELECT * FROM users WHERE id=?” binding userId as parameter. The database driver handles proper escaping. Stored procedures provide another SQL injection defense when implemented correctly with parameterized inputs. However, stored procedures with dynamic SQL construction can still be vulnerable. Input sanitization removes or encodes dangerous characters before processing. HTML encoding converts < to < and > to > preventing script injection. URL encoding handles special characters in URLs. Context-specific output encoding applies appropriate encoding based on where data appears. HTML context requires HTML encoding, JavaScript context needs JavaScript escaping, and SQL context requires SQL escaping. Using wrong encoding for context fails to prevent injection. Data type validation ensures input matches expected type. API schemas define integer, string, boolean, and complex types. Rejecting inputs that don’t match expected types prevents type confusion attacks. Length limits prevent buffer overflow and denial-of-service through excessive input. Maximum lengths for strings and array bounds prevent malicious oversized inputs. Regular expression validation matches input against patterns for emails, phone numbers, credit cards, and other formatted data. However, regex must be carefully written to avoid ReDoS (Regular Expression Denial of Service) vulnerabilities. Content Security Policy headers prevent XSS by restricting resource loading sources. CSP defines allowed script sources, style sources, and other resource origins. Error message sanitization avoids revealing system information in error responses. Generic error messages like “Invalid input” are safer than “SQL syntax error near line 42” which reveals implementation details. Option A is incorrect because trusting all input enables SQL injection, command injection, XSS, and numerous other vulnerabilities that could compromise entire systems. Option C is incorrect because assuming any source is trusted is dangerous; internal systems can be compromised and “trusted” sources can have bugs or be exploited. Option D is incorrect because removing all special characters breaks legitimate use cases like names with apostrophes (O’Brien) or international characters, and doesn’t address all injection vectors.
Question 103:
A developer is building a RESTful API and needs to implement proper HTTP status codes. Which status code should be returned when a resource is successfully created?
A) 200 OK
B) 201 Created with Location header pointing to new resource
C) 204 No Content
D) 202 Accepted
Answer: B
Explanation:
HTTP 201 Created with Location header indicating the new resource URI provides semantically correct response for resource creation, making option B the correct answer. Proper HTTP status code usage improves API clarity and enables client behavior optimization. 201 Created status specifically indicates successful resource creation distinguishing it from general success (200 OK). This semantic specificity helps clients understand operation results without parsing response bodies. Location header provides URI of the newly created resource enabling clients to immediately access the resource without constructing URIs themselves. For example, POST /api/users creating user with ID 123 returns Location: /api/users/123. Response body typically includes created resource representation showing all fields including server-generated values like IDs and timestamps. This eliminates need for additional GET request to retrieve the full resource. Idempotency considerations matter for POST requests. While POST is not idempotent by default, including idempotency keys can make creation idempotent where repeated requests with same key return existing resource with 200 OK or 201 Created. Resource URI design affects Location header value. RESTful URIs should be stable, hierarchical, and human-readable. Created user might be /api/v1/users/123 rather than /api/createUser?id=123. Status code alternatives include 200 OK for successful operations that don’t create resources, 202 Accepted for asynchronous operations where creation is queued but not completed, 204 No Content for successful operations without response body, and 400 Bad Request for validation failures during creation attempts. POST vs PUT semantics matter: POST to collection creates resource with server-assigned ID returning 201 Created. PUT to specific URI creates or replaces resource at that URI returning 201 Created if new or 200 OK if replaced. Client expectations based on status codes enable automated handling: 201 triggers extracting Location header, 400 triggers validation error display, 409 Conflict indicates duplicate resource, and 500 triggers error logging and retry logic. HTTP 201 compliance with REST principles demonstrates proper resource-oriented API design following HTTP specifications and enabling standard HTTP caching and intermediary handling. Option A is incorrect because 200 OK indicates general success but doesn’t specifically communicate resource creation, missing semantic precision that 201 provides. Option C is incorrect because 204 No Content indicates successful request with no response body, typically used for DELETE operations rather than creation. Option D is incorrect because 202 Accepted indicates request accepted for processing but not completed, used for asynchronous operations rather than synchronous resource creation.
Question 104:
A developer needs to implement API versioning to manage breaking changes. What is the recommended approach for versioning REST APIs?
A) Never version APIs and make breaking changes freely
B) Use URI versioning (e.g., /v1/resource), custom headers, or content negotiation with clear deprecation policy
C) Change API behavior without informing clients
D) Version only when clients complain
Answer: B
Explanation:
URI versioning, header-based versioning, or content negotiation with deprecation policies provides clear API evolution management, making option B the correct answer. API versioning enables introducing changes while maintaining backward compatibility for existing clients. URI path versioning embeds version in URL path like /api/v1/users or /api/v2/users. This approach is explicit and visible in documentation, logs, and debugging. Version appears clearly in every request making troubleshooting easier. Advantages include simplicity, clear version visibility, and easy routing to different implementations. Disadvantages include URL proliferation and resources having multiple URIs across versions. Custom header versioning uses HTTP headers like API-Version: 2 or Accept-Version: v2 keeping URLs clean across versions. This approach separates versioning from resource identification but makes versions less visible in logs. Content negotiation uses Accept header with custom media types like Accept: application/vnd.company.v2+json following vendor-specific media type conventions. This standards-compliant approach supports fine-grained versioning per resource type. Semantic versioning principles apply major.minor.patch scheme where major versions introduce breaking changes, minor versions add backward-compatible features, and patches fix bugs without API changes. This convention communicates change impact clearly. Deprecation policy defines timeline for phasing out old versions including deprecation announcement (6-12 months before removal), Sunset header indicating removal date, and documentation updates marking deprecated endpoints. Clear communication enables client migration planning. Version support strategy typically maintains N and N-1 versions providing current and previous version, with 12-18 month support lifecycle before version retirement. Migration tools and documentation help clients upgrade including migration guides explaining changes, code examples showing before/after patterns, and potentially automated migration tools. Backward compatibility techniques minimize version proliferation including optional parameters where new features use optional params with defaults, additive changes adding fields without removing existing ones, and response filtering where newer versions return additional fields older clients ignore. Version routing in API gateways or load balancers directs requests to appropriate backend versions based on version indicators, enabling different implementations for different versions. Option A is incorrect because never versioning makes breaking changes impossible without disrupting all existing clients, effectively forcing all clients to upgrade simultaneously. Option C is incorrect because changing behavior without communication breaks client applications unpredictably causing production failures and destroying client trust. Option D is incorrect because reactive versioning after complaints means clients already experienced breaking changes and failures, making versioning too late to prevent impact.
Question 105:
A developer needs to implement request throttling and rate limiting to prevent API abuse. What approach should be used?
A) Allow unlimited requests from all clients
B) Implement rate limiting using token bucket or sliding window algorithm with per-client limits and appropriate HTTP 429 responses
C) Block all requests after first abuse incident
D) Rate limit only after service degradation occurs
Answer: B
Explanation:
Rate limiting using token bucket or sliding window algorithms with per-client limits provides fair resource allocation and abuse prevention, making option B the correct answer. Rate limiting protects API infrastructure from overload and ensures equitable access across clients. Token bucket algorithm maintains bucket with capacity (burst size) and refill rate (sustained throughput). Each request consumes token, and requests fail when bucket is empty. Bucket refills at constant rate allowing burst traffic up to capacity while enforcing average rate over time. Sliding window algorithm tracks request count over rolling time window. For example, 1000 requests per hour allows up to 1000 requests in any 60-minute period. This approach prevents gaming the system by spreading requests across fixed window boundaries. Fixed window algorithm divides time into fixed periods (e.g., hourly) resetting count at period boundaries. While simple, this allows up to 2x limit when clients request at period boundaries (end of one period and start of next). Per-client identification enables individual rate limits through API keys, OAuth tokens, or IP addresses. Different clients have independent quotas preventing one client from consuming shared limit. Tiered limits provide different quotas for different service tiers. Free tier might allow 1,000 requests/hour, basic tier 10,000 requests/hour, and premium tier 100,000 requests/hour, enabling monetization through rate limit differentiation. HTTP 429 Too Many Requests status code indicates rate limit exceeded. Response includes Retry-After header indicating when client can retry and X-RateLimit headers communicating limit, remaining quota, and reset time. Rate limit headers in every response include X-RateLimit-Limit showing total quota, X-RateLimit-Remaining showing remaining requests, and X-RateLimit-Reset showing reset timestamp. These headers enable clients to implement smart request pacing. Distributed rate limiting in clustered environments uses centralized store like Redis to share rate limit counters across API gateway instances. This prevents clients from bypassing limits by distributing requests across servers. Whitelist exemptions exclude certain clients from rate limiting including monitoring systems, administrative interfaces, and trusted partners. Exemptions support operational requirements without compromising general protection. Dynamic rate adjustment modifies limits based on system load, reducing limits during high load and increasing during low load. This adaptive approach maximizes availability under varying conditions. Option A is incorrect because unlimited requests enable denial-of-service attacks, resource exhaustion, and unfair resource consumption by aggressive clients affecting all users. Option C is incorrect because permanent blocks are excessive punishment for many abuse scenarios and prevent legitimate use after temporary misconfigurations. Option D is incorrect because waiting until degradation occurs means users are already experiencing performance problems, defeating the purpose of proactive rate limiting.
Question 106:
A developer needs to implement Cross-Origin Resource Sharing (CORS) for a web API accessed from browser-based applications. What CORS configuration is required?
A) Disable all CORS headers for security
B) Configure CORS headers including Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers for legitimate cross-origin requests
C) Set Access-Control-Allow-Origin to * for all APIs
D) Ignore preflight OPTIONS requests
Answer: B
Explanation:
Configuring CORS headers with appropriate origin, methods, and headers enables secure cross-origin requests while preventing unauthorized access, making option B the correct answer. CORS enables browsers to make cross-origin requests while maintaining security through server-controlled access. Access-Control-Allow-Origin header specifies which origins can access the API. Values include specific origin like https://app.example.com for production origin, multiple origins through dynamic header generation based on request Origin header, or * wildcard for public APIs without credentials. Access-Control-Allow-Methods lists HTTP methods allowed for cross-origin requests like GET, POST, PUT, DELETE. Browsers check these methods in preflight requests before actual request. Access-Control-Allow-Headers specifies custom headers permitted in requests. Common headers include Content-Type, Authorization, and X-API-Key. Browser blocks requests with headers not in allowed list. Access-Control-Allow-Credentials indicates whether requests with credentials (cookies, authorization headers) are allowed. This header must be true for authenticated cross-origin requests, and when credentials are allowed, Access-Control-Allow-Origin cannot be *. Preflight requests using OPTIONS method check permissions before actual request. Browser sends preflight for requests with custom headers, methods other than GET/POST/HEAD, or Content-Type beyond simple values. Server must respond to OPTIONS with appropriate CORS headers. Access-Control-Max-Age specifies how long (in seconds) preflight response can be cached. Longer cache durations reduce preflight requests improving performance but delay policy updates. Simple requests bypass preflight when using GET/POST/HEAD methods, simple headers, and simple Content-Type values. Simple requests receive CORS headers in actual response rather than preflight. CORS configuration examples show public API allowing all origins: Access-Control-Allow-Origin: . Authenticated API for specific origin: Access-Control-Allow-Origin: https://app.example.com and Access-Control-Allow-Credentials: true. Multiple origins handled dynamically: server checks request Origin against whitelist, returning matching origin in response header. Security considerations include avoiding wildcard origin with credentials which browsers reject, validating origin against whitelist preventing unauthorized domains, and considering subdomain implications where example.com differs from app.example.com. CORS vs JSONP shows CORS as modern standard supporting all HTTP methods and secure credentials, while JSONP is legacy technique with security limitations supporting only GET requests. Option A is incorrect because disabling CORS prevents legitimate browser-based applications from accessing the API, breaking web applications that need cross-origin access. Option C is incorrect because wildcard origin () for all APIs including those with credentials creates security vulnerabilities and is rejected by browsers for credentialed requests. Option D is incorrect because ignoring preflight requests causes cross-origin requests to fail since browsers require successful preflight before sending actual requests.
Question 107:
A developer needs to implement database connection pooling for a high-traffic application. What benefits does connection pooling provide?
A) Create new database connection for every request
B) Implement connection pooling to reuse database connections, reduce connection overhead, improve performance, and manage resource limits
C) Keep one connection open indefinitely for all requests
D) Close connections immediately after each query
Answer: B
Explanation:
Connection pooling reusing database connections reduces overhead, improves performance, and manages resources efficiently, making option B the correct answer. Database connection establishment is expensive involving network handshakes, authentication, and session initialization, making connection reuse critical for performance. Connection pool management maintains pool of ready-to-use database connections. Applications borrow connections from pool for queries, return connections to pool after use, and pool manages connection lifecycle including creation, validation, and cleanup. Performance benefits include eliminating connection establishment overhead which typically takes 50-100ms per connection, reducing latency for database operations since connections are pre-established, and improving throughput by handling more requests with fewer connections through reuse. Resource management controls maximum simultaneous connections preventing database server overload. Pool size limits (e.g., 20 connections) ensure application doesn’t exceed database connection limits or consume excessive memory. Minimum pool size maintains baseline connections for quick request handling. Idle connections are reused immediately without creation delay, though excessive idle connections waste resources. Connection validation tests connections before reuse with validation queries like “SELECT 1” or lightweight pings. Invalid connections are removed and replaced ensuring applications receive working connections. Idle timeout closes connections idle beyond threshold (e.g., 30 minutes) reclaiming resources while maintaining minimum pool size. This handles traffic patterns where peak load requires many connections but off-peak needs fewer. Connection lifetime limits force periodic connection recreation preventing issues from long-lived connections like memory leaks or stale state. Maximum lifetime (e.g., 1 hour) triggers graceful connection replacement. Wait timeout configuration defines maximum time application waits for available connection from pool. Request fails or queues if all connections busy, with timeout preventing indefinite waits. Pool exhaustion monitoring tracks connection usage patterns, pool exhaustion events, and wait times. Alerts trigger when pool frequently exhausted indicating need for pool size increase. Connection leak detection identifies borrowed connections not returned to pool within reasonable time. Leak detection logs warnings and optionally forcibly reclaims leaked connections. Configuration considerations include sizing pool based on concurrent request needs, database connection limits, and application memory. Starting with 10-20 connections per application instance is common baseline. Framework integration shows database libraries like HikariCP (Java), SQLAlchemy (Python), or Sequelize (Node.js) provide built-in connection pooling with sensible defaults. Option A is incorrect because creating new connection per request incurs massive overhead reducing performance by 10-100x compared to pooling, and quickly exhausts database connection limits. Option C is incorrect because single connection bottlenecks all requests forcing serialization, eliminates concurrency benefits, and fails if that connection breaks. Option D is incorrect because immediately closing connections wastes the connection establishment cost on every query, severely degrading performance.
Question 108:
A developer needs to implement asynchronous task processing for long-running operations. What pattern should be used?
A) Process all tasks synchronously blocking API requests
B) Use message queue with worker processes for asynchronous task execution returning task ID immediately and providing status endpoint
C) Make clients wait until task completes
D) Execute long tasks on main API thread
Answer: B
Explanation:
Message queue with worker processes for asynchronous execution provides responsive API while handling long-running tasks, making option B the correct answer. Long-running operations like video processing, report generation, or batch updates should not block API responses. Message queue architecture separates task submission from execution. API receives task request, enqueues task to message queue with unique task ID, immediately returns 202 Accepted with task ID, and worker processes consume tasks from queue executing asynchronously. Task ID enables status tracking where client polls status endpoint like GET /tasks/{taskId} receiving states like pending, processing, completed, or failed. This pattern provides progress visibility without blocking initial request. Background worker processes run independently from API servers. Workers pull tasks from queue, execute business logic, update task status, and store results. Multiple workers enable parallel processing and horizontal scaling. Queue benefits include load leveling buffering traffic spikes, fault tolerance where tasks persist if workers crash, retry logic for failed tasks, and priority queues for urgent tasks. Celery (Python), Sidekiq (Ruby), or Bull (Node.js) provide robust task queue implementations with features like retry policies, scheduled tasks, result backends, and monitoring dashboards. Task status storage tracks task state in database or cache like Redis. Status updates from workers enable API endpoints to report progress to clients. Completed tasks might store results for retrieval. Webhook callbacks notify clients when tasks complete instead of requiring polling. API accepts webhook URL during task submission, and workers POST results to webhook URL upon completion. Result expiration automatically purges old task results after retention period (e.g., 24 hours) preventing unbounded storage growth while maintaining results long enough for client retrieval. Error handling includes task retry with exponential backoff for transient failures, dead letter queues for permanently failed tasks, and error details in task status for debugging. Task priorities enable urgent tasks to jump queue. High-priority tasks like password resets process before low-priority tasks like analytics batch jobs. Monitoring and alerting track queue depth indicating backlog, processing latency showing how long tasks wait, worker health showing active/crashed workers, and failure rates triggering alerts for investigation. Option A is incorrect because synchronous processing blocks API responses during long operations causing timeouts, poor user experience, and server resource exhaustion from many concurrent long tasks. Option C is incorrect because making clients wait violates responsiveness requirements, can exceed HTTP timeouts, and ties up server resources during waiting. Option D is incorrect because executing long tasks on main thread blocks the event loop in single-threaded environments or holds request threads in multi-threaded environments, severely limiting concurrency.
Question 109:
A developer needs to implement request/response compression to reduce bandwidth usage. What HTTP compression should be implemented?
A) Never compress HTTP responses
B) Implement gzip or Brotli compression with Accept-Encoding negotiation and Content-Encoding headers for supported responses
C) Compress only responses under 1KB
D) Compress every response regardless of content type
Answer: B
Explanation:
Implementing gzip or Brotli compression with content negotiation reduces bandwidth while maintaining performance, making option B the correct answer. HTTP compression significantly reduces transmitted data size improving load times and reducing bandwidth costs. Accept-Encoding header in client requests indicates supported compression algorithms like Accept-Encoding: gzip, deflate, br (Brotli). Servers check this header to determine client compression support. Content-Encoding header in server responses indicates applied compression like Content-Encoding: gzip. This informs clients how to decompress response body. Compression algorithms include gzip providing excellent compression with broad support, Brotli offering better compression ratios than gzip particularly for text, and deflate as older algorithm generally replaced by gzip. Brotli typically saves additional 15-20% compared to gzip. Compression candidates include text formats like JSON, XML, HTML, CSS, and JavaScript where compression ratios of 60-80% are common. Binary formats like images (JPEG, PNG) or videos are already compressed and shouldn’t be re-compressed. Compression threshold configures minimum response size for compression (typically 1-2KB). Tiny responses are served uncompressed since compression overhead exceeds benefits for small payloads. Dynamic compression applies compression on-the-fly as responses are generated. This adds CPU overhead but ensures all dynamic content benefits from compression. Static file compression pre-compresses static assets during build. Pre-compressed files are served immediately without runtime CPU overhead. Servers can maintain both compressed and uncompressed versions serving appropriate version based on Accept-Encoding. Compression level balances compression ratio against CPU usage. Level 6 for gzip or level 4 for Brotli provides good balance. Maximum compression improves ratio minimally while dramatically increasing CPU time. Vary header indicates caching behavior for compressed responses: Vary: Accept-Encoding tells caches to maintain separate versions for different encodings. Without Vary, caches might serve compressed responses to clients not supporting compression. Security considerations include BREACH attack where compression reveals information through response size analysis. Mitigation includes disabling compression for sensitive endpoints or adding random padding. Performance impact shows compression reducing bandwidth usage by 50-80% for text, with CPU overhead typically 1-5% of server capacity, and improved load times particularly benefiting mobile users on slow networks. Option A is incorrect because never compressing wastes bandwidth increasing load times and costs, particularly impacting users on mobile networks or limited data plans. Option C is incorrect because compressing only tiny responses misses the primary candidates for compression which are larger text responses where compression provides greatest benefit. Option D is incorrect because compressing already-compressed formats like images or videos wastes CPU without reducing size and may actually increase size due to compression overhead.
Question 110:
A developer needs to implement API authentication using API keys. What security practices should be followed?
A) Send API keys in URL query parameters
B) Use API keys in Authorization header or custom header with HTTPS, implement key rotation, rate limiting per key, and audit logging
C) Store API keys in JavaScript frontend code
D) Share API keys across multiple applications
Answer: B
Explanation:
API keys in headers over HTTPS with rotation, rate limiting, and logging provides secure key-based authentication, making option B the correct answer. API keys offer simple authentication mechanism requiring proper security practices to prevent abuse. Header transmission sends API keys in HTTP headers like Authorization: Bearer {api_key} or X-API-Key: {api_key}. Header-based transmission prevents keys from appearing in URL logs, browser history, or server access logs. HTTPS encryption protects API keys during transmission. TLS encrypts entire request including headers preventing network eavesdropping. Never send API keys over unencrypted HTTP. Key generation creates cryptographically random keys with sufficient entropy (at least 128 bits). Predictable keys enable brute-force attacks. UUID v4 or similar random generation is appropriate. Key rotation policy defines key lifetime and replacement schedule. Regular rotation (quarterly or after security events) limits exposure from compromised keys. Support multiple active keys during rotation transition. Key storage hashes keys in database using strong hashing algorithms like bcrypt. Hashing prevents key disclosure if database is compromised. Store only hashed values, never plaintext keys. Rate limiting per key prevents abuse by limiting requests per key per time period. Compromised keys have limited damage potential when rate-limited. Aggressive rate limiting on key violations throttles brute-force attempts. Scope and permissions associate keys with specific permissions. Different keys for different access levels implements least privilege. Read-only keys for queries, write keys for mutations. Key lifecycle management includes creation generating and returning key once, activation marking key as active, suspension temporarily disabling key, and revocation permanently disabling key. Track all state transitions. Audit logging records key usage including successful authentications, failed authentication attempts, API calls made with each key, and key lifecycle events. Audit trails support security investigations and compliance. Key identification assigns unique ID to each key enabling key-specific analytics, usage tracking, and targeted revocation without knowing actual key value. Monitor usage patterns for anomaly detection including unusual request volumes, requests from new geographic locations, or requests outside normal time patterns. Anomalies may indicate compromised keys. Multiple keys per application allow different keys for different environments (development, staging, production) and enable key rotation without downtime by activating new key before revoking old key. Option A is incorrect because URL query parameters expose keys in logs, browser history, referrer headers, and proxies creating security vulnerabilities. Option C is incorrect because frontend code exposes keys to anyone viewing page source or network traffic, making keys publicly accessible. Option D is incorrect because sharing keys across applications prevents identifying which application made requests, complicates key rotation, and increases compromise blast radius.
Question 111:
A developer needs to implement database transactions with proper isolation levels. What considerations are important for isolation level selection?
A) Always use lowest isolation level
B) Select isolation level based on consistency requirements balancing between Read Uncommitted, Read Committed, Repeatable Read, and Serializable considering concurrency and performance tradeoffs
C) Never use transactions
D) Use random isolation levels
Answer: B
Explanation:
Selecting appropriate isolation level balancing consistency with concurrency based on requirements ensures correct application behavior, making option B the correct answer. Transaction isolation levels prevent different concurrency problems with varying performance impacts. Read Uncommitted allows dirty reads where transactions see uncommitted changes from other transactions. This lowest isolation level provides maximum concurrency but risks reading data that may be rolled back. Rarely appropriate except for scenarios tolerating approximate results. Read Committed prevents dirty reads ensuring transactions only see committed changes. Default isolation level for many databases, it balances consistency with performance. However, non-repeatable reads can occur where successive reads in same transaction return different results. Repeatable Read prevents non-repeatable reads ensuring same query in transaction always returns same results. Once row is read, other transactions cannot modify it until reading transaction completes. However, phantom reads can occur where new rows matching query appear. Serializable provides highest isolation preventing phantom reads through range locks or serializable snapshot isolation. Transactions appear to execute serially without concurrency. Provides strongest consistency but lowest concurrency and performance. Dirty reads occur when transaction reads uncommitted changes rolled back later, potentially causing incorrect calculations or decisions based on data that never truly existed. Non-repeatable reads happen when transaction reads same row twice getting different values because another transaction modified row between reads. This inconsistency can violate business logic assumptions. Phantom reads occur when range query returns different rows on successive executions because another transaction inserted or deleted rows matching query criteria. Aggregation queries particularly susceptible. Isolation level selection depends on use cases: Read Committed for most general purposes balancing consistency and performance, Repeatable Read for financial calculations requiring consistency within transaction, Serializable for critical operations like inventory management where phantom reads cause errors, and Read Uncommitted rarely, possibly for approximate analytics where exact correctness isn’t critical. Performance implications show higher isolation levels reduce concurrency through increased locking, may cause deadlocks requiring retry logic, and typically show 10-50% throughput reduction from Read Committed to Serializable. Database-specific behavior varies: PostgreSQL’s Repeatable Read prevents phantom reads through MVCC, MySQL InnoDB’s Repeatable Read uses gap locks, and SQL Server’s Read Committed Snapshot Isolation provides non-blocking reads. Application design can minimize need for high isolation through optimistic concurrency control with version numbers, shorter transactions reducing conflict probability, and careful query design avoiding unnecessary range scans. Option A is incorrect because lowest isolation level (Read Uncommitted) provides inadequate consistency for most applications potentially causing data corruption or business logic errors. Option C is incorrect because never using transactions eliminates atomicity guarantees allowing partial failures that violate data integrity. Option D is incorrect because random isolation selection creates unpredictable behavior and likely uses inappropriate isolation for requirements.
Question 112:
A developer needs to implement webhooks to notify external systems of events. What webhook implementation best practices should be followed?
A) Send webhook without retry logic
B) Implement webhooks with HTTPS endpoints, signature verification, retry logic with exponential backoff, and timeout handling
C) Send sensitive data without encryption
D) Never verify webhook delivery
Answer: B
Explanation:
Webhooks with HTTPS, signatures, retry logic, and timeouts provide reliable, secure event notification, making option B the correct answer. Webhooks enable real-time integration by pushing event notifications to external systems. HTTPS endpoints require webhook receivers use HTTPS preventing event data interception. Reject plain HTTP webhook URLs during registration protecting sensitive event data. Signature verification uses HMAC signatures to authenticate webhooks. Sender computes signature using shared secret and includes in X-Webhook-Signature header. Receiver recomputes signature and verifies match preventing spoofing. Signature algorithm like HMAC-SHA256 computes signature over entire request body. Include timestamp in signature to prevent replay attacks where old webhooks are resent maliciously. Webhook registration stores receiver URL, signing secret, active/inactive status, and optionally event type filters. Registration API validates URL format and optionally performs verification ping. Retry logic handles delivery failures through exponential backoff (retry after 1, 2, 4, 8 minutes), maximum retry attempts (typically 5-10 tries), and eventual failure notification after exhausting retries. Retries handle transient failures like temporary network issues. Timeout configuration sets reasonable timeout (5-10 seconds) for webhook responses. Long timeouts tie up resources while receiver processes webhook. Receivers should return 2xx immediately then process asynchronously. Idempotency enables safe retries by including unique event ID in webhook payload. Receivers track processed event IDs ignoring duplicate deliveries from retries. Event payload structure includes event type identifier, timestamp of event occurrence, event-specific data, and correlation/trace IDs for debugging. Consistent payload structure simplifies receiver implementation. Webhook delivery guarantees typically provide at-least-once delivery. Events may be delivered multiple times requiring idempotent receiver processing. Exactly-once delivery is significantly more complex. Webhook monitoring tracks delivery success rates, failure reasons, average latency, and retry patterns. Dashboards show webhook health enabling proactive issue detection. Receiver acknowledgment uses HTTP status codes: 2xx indicates successful delivery, 4xx indicates permanent failure don’t retry (bad payload), 5xx indicates temporary failure should retry, and timeouts trigger retries. Security considerations include IP whitelisting limiting webhook sources, rate limiting preventing abuse, payload size limits preventing resource exhaustion, and audit logging of all webhook deliveries. Testing webhooks provides sandbox/test endpoints, webhook replay capabilities for development, and payload examples in documentation. Webhook management UI enables viewing webhook history, manual retry of failed webhooks, enabling/disabling webhooks, and updating webhook configuration. Option A is incorrect because without retry logic, transient failures cause permanent event loss breaking integration reliability. Option C is incorrect because unencrypted webhook data over HTTP exposes potentially sensitive event information to network eavesdropping.
Option D is incorrect because never verifying delivery means senders don’t know if receivers processed events, events may be silently lost, and integration failures go undetected.
Question 113:
A developer needs to implement proper logging for production applications. What logging best practices should be followed?
A) Log everything at DEBUG level in production
B) Implement structured logging with appropriate log levels, include context (request IDs, user IDs), sanitize sensitive data, and use centralized log aggregation
C) Write logs only to local files without aggregation
D) Include passwords and API keys in logs
Answer: B
Explanation:
Structured logging with context, sanitization, and centralized aggregation provides effective production observability, making option B the correct answer. Proper logging enables debugging production issues, security monitoring, and compliance auditing while protecting sensitive information. Structured logging uses consistent format like JSON containing timestamp, log level, logger name, message, and contextual fields. Structured format enables efficient parsing, querying, and analysis compared to unstructured text. Log levels provide severity classification: ERROR for errors requiring attention, WARN for potential problems not yet causing failures, INFO for significant application events, and DEBUG for detailed diagnostic information. Production typically uses INFO level reducing volume while capturing important events. Context enrichment adds contextual fields to log entries including request ID correlating all logs for single request, user ID identifying user associated with operation, session ID tracking user session, and trace ID for distributed tracing across services. Contextual logging enables filtering logs by user, request, or session. Sensitive data sanitization redacts or masks sensitive information before logging including passwords replaced with [REDACTED], credit card numbers showing only last 4 digits, API keys and tokens hidden, and personally identifiable information masked per privacy regulations. Sanitization prevents credential exposure in logs. Request/response logging captures HTTP requests and responses including method, path, status code, duration, and error details. Avoid logging entire payloads in production due to volume and sensitivity concerns. Log complete payloads only in development or with DEBUG level. Error logging includes exception type, error message, stack trace, and context when error occurred. Stack traces enable root cause identification. Structured error logging enables error aggregation and alerting. Performance logging tracks operation durations, database query times, external API call latencies, and resource utilization. Performance logs identify bottlenecks and degradation. Security event logging records authentication attempts (success and failure), authorization decisions, sensitive data access, and configuration changes. Security logs support incident investigation and compliance auditing. Log aggregation using tools like ELK Stack (Elasticsearch, Logstash, Kibana), Splunk, or CloudWatch Logs consolidates logs from distributed services. Centralized logs enable unified search, correlation, and analysis. Log retention policies define how long logs are kept balancing storage costs with compliance requirements. Typical retention: development logs 7 days, production logs 30-90 days, security logs 1+ years per compliance. Log sampling reduces volume in high-traffic systems by logging only percentage of transactions. Sample rate might be 10% for routine operations but 100% for errors. Sampling maintains observability while controlling costs. Correlation IDs propagate through service calls enabling tracing complete request flow. Service A generates correlation ID, passes to Service B via header, and both services include same ID in logs. Alert integration triggers alerts on error patterns, performance degradation, or security events. Log-based alerts enable proactive incident response. Option A is incorrect because DEBUG level in production generates excessive log volume consuming storage and I/O, impacting performance, and increasing costs without commensurate value. Option C is incorrect because local files without aggregation make troubleshooting distributed systems nearly impossible and logs are lost when instances are terminated. Option D is incorrect because logging passwords and keys creates severe security vulnerabilities exposing credentials to anyone with log access violating security fundamentals.
Question 114:
A developer needs to implement service discovery in a microservices architecture. What approach should be used?
A) Hard-code IP addresses of all services
B) Use service discovery mechanism like Consul, Eureka, or Kubernetes service discovery enabling dynamic service location and health checking
C) Manually update configuration files when services move
D) Use DNS with static entries
Answer: B
Explanation:
Service discovery using Consul, Eureka, or Kubernetes enables dynamic service location with health checking for resilient microservices, making option B the correct answer. Microservices architectures with numerous services and dynamic scaling require automated service discovery. Service registry maintains database of available service instances including service name, IP address, port, and health status. Services register themselves on startup and deregister on shutdown. Health checking verifies service health through periodic checks including HTTP health endpoints, TCP connection tests, or script-based checks. Unhealthy instances are removed from registry preventing traffic routing to failed services. Client-side discovery has clients query service registry to obtain available instances then select instance using load balancing algorithm. This approach gives clients direct control but requires registry client in each service. Server-side discovery uses load balancer or API gateway querying registry and routing requests. Clients only know load balancer address simplifying client logic. Common in Kubernetes where service names resolve to pod IPs automatically. DNS-based discovery uses DNS for service discovery where service names resolve to instance IP addresses. DNS entries update as instances change. Provides simple integration but lacks sophisticated health checking. Consul provides distributed service mesh with service registry, health checking, DNS interface, and key-value store. Multi-datacenter support enables global service discovery. Eureka from Netflix offers service registry designed for AWS cloud with built-in registry server and client libraries. Commonly used in Spring Cloud microservices. Kubernetes service discovery uses Services abstracting pod IPs with stable DNS names and load balancing. Pods register automatically via labels and selectors. Service mesh platforms like Istio or Linkerd add service discovery with advanced traffic management, security, and observability. Registration patterns include self-registration where services register themselves on startup, and third-party registration where deployment system registers services. Load balancing algorithms distributed across discovered instances include round-robin distributing evenly, least connections routing to least loaded, and random selection for simplicity. Failover and retry logic handles discovered instance failures by retrying different instance, removing failed instance from local cache, and waiting for registry to detect failure through health checks. Service metadata in registry stores additional information like service version, deployment environment, and custom tags enabling advanced routing decisions. Caching discovered services locally reduces registry queries. Short TTL (10-30 seconds) balances staleness with performance. Stale cache can route to terminated instances. Option A is incorrect because hard-coded addresses are brittle, break when services move, don’t handle scaling, and create deployment coupling making changes difficult. Option C is incorrect because manual configuration updates don’t scale, are error-prone, slow to propagate, and are incompatible with auto-scaling and container orchestration. Option D is incorrect because static DNS entries require manual updates, don’t support health checking, and have long TTL causing stale routing after changes.
Question 115:
A developer needs to implement API gateway pattern for microservices architecture. What capabilities should the API gateway provide?
A) Direct client-to-microservice communication
B) Implement API gateway providing request routing, authentication, rate limiting, request/response transformation, and aggregation of multiple service calls
C) Eliminate all backend services
D) Only provide DNS resolution
Answer: B
Explanation:
API gateway providing routing, authentication, rate limiting, transformation, and aggregation creates unified entry point for microservices, making option B the correct answer. API gateway pattern addresses challenges of client-to-microservices communication including protocol translation, security, and request aggregation. Request routing directs incoming requests to appropriate backend microservices based on URL path, HTTP method, headers, or query parameters. Single gateway endpoint simplifies client configuration. Authentication and authorization centralize security at gateway through OAuth token validation, API key verification, and JWT validation. Gateway authenticates requests before forwarding to backend services allowing services to trust authenticated requests. Rate limiting at gateway level applies rate limits across all backend services preventing abuse. Per-client quotas protect entire backend infrastructure with single enforcement point. Request/response transformation modifies requests before backend routing and responses before client return including header manipulation, payload transformation, and protocol translation (REST to gRPC). Response aggregation combines multiple backend service calls into single client response. Backend-for-frontend pattern where gateway makes parallel calls to multiple services, aggregates responses, and returns unified response reducing client complexity. Load balancing distributes requests across service instances with health checking removing unhealthy instances from rotation. Gateway integrates with service discovery for dynamic routing. Caching responses at gateway reduces backend load by serving cached responses for appropriate requests. Cache headers control caching behavior. Gateway handles cache invalidation and staleness. SSL termination handles TLS encryption/decryption at gateway offloading this processing from backend services. Backend communication may use unencrypted HTTP within secure network perimeter. Circuit breaking prevents cascading failures by detecting failing services and immediately failing requests without calling backend until recovery detected. Protects overall system stability. Request/response logging captures all traffic through gateway providing unified audit trail and debugging capability. Structured logs enable analysis and monitoring. API versioning support routes requests to different backend versions based on URL path or headers enabling gradual API evolution. Metrics and monitoring track request volume, latency percentiles, error rates, and backend service health. Gateway provides comprehensive observability into API usage. WebSocket and streaming support proxies persistent connections and streaming protocols in addition to request/response patterns. CORS handling implements Cross-Origin Resource Sharing policies centralizing browser security policies rather than implementing in each microservice. Popular gateway solutions include Kong providing plugin-based extensibility, Amazon API Gateway as managed service, NGINX as high-performance reverse proxy, and Traefik designed for containers and microservices. Option A is incorrect because direct client-to-service communication increases client complexity, duplicates cross-cutting concerns across services, and tightly couples clients to service locations and protocols. Option C is incorrect because eliminating backend services defeats the purpose of gateway pattern which fronts existing microservices architecture. Option D is incorrect because DNS resolution alone doesn’t provide authentication, rate limiting, aggregation, or other gateway capabilities critical for microservices.
Question 116:
A developer needs to implement idempotent API operations to handle network failures safely. What makes an operation idempotent?
A) Operation can only be executed once
B) Operation produces same result when executed multiple times with same parameters without unintended side effects
C) Operation always fails on retry
D) Operation requires different parameters each time
Answer: B
Explanation:
Idempotent operations producing identical results across multiple executions with same parameters enable safe retries, making option B the correct answer. Idempotency is critical for reliable systems with network unreliability and automatic retries. Naturally idempotent operations include HTTP GET which reads data without modification so multiple requests return same data, PUT which replaces entire resource so multiple identical PUTs produce same final state, and DELETE which removes resource where deleting already-deleted resource has same end result (resource doesn’t exist). POST operations typically aren’t idempotent since posting same data multiple times creates duplicate resources. Idempotency requires different approach for POST through idempotency keys. Idempotency keys provide unique client-generated identifier included in request like Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000. Server tracks processed keys preventing duplicate execution for same key. Implementation stores key with result in database or cache. On request arrival, server checks if key exists, returns cached result if found avoiding reprocessing, processes request if key is new storing result with key, and includes appropriate status code (200 for cached result, 201 for newly created resource). Key expiration balances storage with retry window. Keys expire after 24 hours allowing clients reasonable time to retry while preventing indefinite storage growth. State transitions require careful design for idempotency. Idempotent state transition succeeds if already in target state. For example, “activate user” succeeds if user is already active. Non-idempotent transition fails if already completed. Conditional operations use preconditions for idempotency through If-Match header with ETag ensuring update applies only if resource unchanged since read. Failed precondition returns 412 Precondition Failed enabling client to retry with fresh data. Database transactions ensure idempotency by atomically checking idempotency key and executing operation within transaction. This prevents race conditions where concurrent requests with same key both execute. Payment processing requires strict idempotency since duplicate charges cause financial errors. Payment APIs use idempotency keys ensuring payment is processed exactly once regardless of retries. Retry-able errors (network failures, timeouts) are safe with idempotent operations. Client retries automatically without risking duplicate side effects. Non-retry-able errors (validation failures) shouldn’t trigger retries. Idempotency keys in distributed systems require consistent key checking across all service instances through shared cache (Redis) or database enabling any instance to detect previously processed keys. Client responsibilities include generating unique keys (UUID v4), including keys in retry attempts, and handling different response status codes (201 for new vs 200 for cached). Server responsibilities include validating key format, storing and checking keys, and returning consistent responses for repeated keys. Option A is incorrect because idempotency allows multiple executions safely rather than preventing repeated execution, which is critical for retry reliability. Option C is incorrect because idempotent operations should succeed on retry if original succeeded, not fail systematically. Option D is incorrect because idempotency specifically enables using same parameters repeatedly, which is the entire point for safe retries.
Question 117:
A developer needs to implement content negotiation in REST API to support multiple response formats. How should content negotiation be implemented?
A) Always return JSON regardless of client preference
B) Use Accept header to negotiate response format supporting JSON, XML, or other formats based on client requirements
C) Require format specification in URL parameter
D) Return random format each request
Answer: B
Explanation:
Accept header-based content negotiation supporting multiple formats based on client preference provides flexible REST API responses, making option B the correct answer. Content negotiation enables serving different representations of resources based on client capabilities and preferences. Accept header in requests specifies preferred media types like Accept: application/json for JSON, Accept: application/xml for XML, or Accept: text/html for HTML. Clients list multiple preferences with quality values. Quality values indicate preference strength like Accept: application/json; q=1.0, application/xml; q=0.8 preferring JSON but accepting XML. Server selects best match from supported formats. Server selection chooses format matching client preference from supported types. If no match exists, server returns 406 Not Acceptable status indicating it cannot satisfy request. Content-Type header in response indicates selected format like Content-Type: application/json; charset=utf-8 informing client how to parse response. Media type registration uses standard types from IANA registry like application/json, application/xml, or custom vendor-specific types like application/vnd.company.resource+json. Default format when Accept header is missing or Accept: / typically defaults to JSON as most common format. Document default behavior clearly. Format-specific serialization uses appropriate serializers for each format: JSON serializer for application/json, XML serializer for application/xml, and custom serializers for specialized formats. Serializers handle format-specific requirements. Vary header indicates content negotiation: Vary: Accept tells caches to maintain separate cached versions for different Accept header values. Without Vary, caches might return wrong format. Quality of service negotiation extends beyond format to compression (Accept-Encoding), language (Accept-Language), and charset preferences (Accept-Charset). Comprehensive negotiation provides optimal experience. API versioning interaction with content negotiation combines version and format: Accept: application/vnd.company.v2+json specifies both API version and format in single header. Fallback strategies handle negotiation failure gracefully by defaulting to common format with warning, providing format alternatives in error response, or redirecting to format selection page. Error responses maintain format consistency returning errors in negotiated format. If client accepts JSON, return error as JSON. Consistent error format simplifies client error handling. Documentation clearly specifies supported formats, example Accept headers for each format, and response samples in each format enabling clients to implement negotiation correctly. Performance considerations note different formats have different serialization costs. JSON typically fastest, XML slower, and custom formats vary. Profile format choice impact. Option A is incorrect because forcing JSON ignores client capabilities and preferences, potentially requiring clients to perform their own transformation from JSON to preferred format. Option C is incorrect because URL parameters for format specification isn’t RESTful practice and violates HTTP content negotiation standards, though sometimes used as alternative. Option D is incorrect because random formats make APIs unpredictable and unusable as clients cannot reliably parse responses.
Question 118:
A developer needs to implement API request validation to ensure data quality. What validation approach should be used?
A) Trust all incoming data without validation
B) Implement multi-layered validation including schema validation, business rule validation, data type checking, and range validation with clear error messages
C) Validate only after database insertion
D) Perform validation only in frontend
Answer: B
Explanation:
Multi-layered validation including schema, business rules, types, and ranges with clear errors ensures data quality and security, making option B the correct answer. Comprehensive validation prevents invalid data from entering systems protecting data integrity and preventing security vulnerabilities. Schema validation verifies request structure matches API specification using JSON Schema, OpenAPI specifications, or similar defining required fields, optional fields, data types, and nested object structure. Schema validators automatically reject malformed requests. Data type validation ensures fields contain correct types: strings for names, integers for counts, booleans for flags, and dates in standard formats. Type checking prevents type confusion bugs. Range validation checks numeric values fall within acceptable ranges like age between 0-150, percentage 0-100, and positive quantities > 0. Range checks prevent nonsensical values. Format validation verifies strings match expected patterns using regex for emails, phone numbers, URLs, credit cards, and postal codes. Format validation prevents malformed data entry. Required field validation ensures mandatory fields are present and non-empty. Distinguish between optional fields that may be omitted and required fields that must have values. Business rule validation enforces domain-specific rules like start date before end date, quantity not exceeding inventory, and unique email addresses. Business rules encode domain logic in validation. Custom validators implement complex validation logic not expressible in schema including cross-field validation, external data lookups, and stateful validation based on existing data. Validation error responses return 400 Bad Request with detailed error information including field name causing error, specific validation failure reason, and optionally suggested corrections. Clear errors enable client debugging. Error message structure uses consistent format like {“errors”: [{“field”: “email”, “message”: “Invalid email format”, “code”: “FORMAT_ERROR”}]} enabling programmatic error handling. Validation timing shows early validation at API gateway rejects obviously invalid requests before reaching business logic. Application-level validation performs complete validation including business rules. Database constraints provide final validation safety net. Sanitization accompanies validation by cleaning input while validating: trimming whitespace, normalizing formats, and escaping special characters. Sanitization prevents injection attacks. Whitelist validation defines allowed values explicitly more secure than blacklist forbidding specific values. Enum fields use whitelists of valid options. Validation frameworks like Joi (Node.js), Hibernate Validator (Java), or Marshmallow (Python) provide declarative validation reducing boilerplate code. Performance considerations batch validation checks, fail fast on first error or collect all errors depending on requirements, and cache validation results where applicable. Option A is incorrect because trusting unvalidated data enables injection attacks, data corruption, and application crashes from malformed input. Option C is incorrect because validating after database insertion wastes database resources on invalid data and may partially commit transaction before encountering errors. Option D is incorrect because frontend-only validation is easily bypassed by direct API calls and doesn’t protect against malicious actors or API integrations.
Question 119:
A developer needs to implement ETags for HTTP caching optimization. How should ETags be used?
A) Never use caching headers
B) Implement ETag response header with entity version identifier enabling conditional requests using If-None-Match and If-Match headers for cache validation
C) Cache everything indefinitely without validation
D) Use random ETag values
Answer: B
Explanation:
ETag headers with conditional request support enable efficient cache validation reducing bandwidth and improving performance, making option B the correct answer. ETags provide mechanism for validating cached resources without transferring entire response. ETag response header contains unique identifier for resource version like ETag: “33a64df551425fcc55e4d42a148795d9f25f89d4”. Identifier changes when resource changes enabling clients to detect modifications. ETag generation uses hashing of resource content, version number, or timestamp. Strong ETags indicate exact resource match while weak ETags (W/”123″) indicate semantic equivalence. Conditional GET requests use If-None-Match header containing cached ETag. Client sends If-None-Match: “33a64df551425fcc55e4d42a148795d9f25f89d4” asking if resource changed. Server response returns 304 Not Modified if ETag matches meaning resource unchanged, client uses cached version saving bandwidth. Returns 200 OK with new content if ETag doesn’t match indicating resource changed. Conditional PUT requests use If-Match header for optimistic locking. Client includes If-Match: “33a64df551425fcc55e4d42a148795d9f25f89d4” ensuring update applies only if resource unchanged since read preventing lost updates. Failed match returns 412 Precondition Failed indicating concurrent modification requiring client to retrieve latest version. ETag benefits include bandwidth reduction by not transmitting unchanged resources, server load reduction through 304 responses requiring minimal processing, and optimistic concurrency control preventing race conditions in updates. Strong vs weak ETags differ where strong ETags require byte-for-byte identical content indicated by quotes: ETag: “123”. Weak ETags allow semantically equivalent content indicated by W/ prefix: ETag: W/”123″. Last-Modified header provides alternative cache validation using timestamps: Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT with If-Modified-Since conditional requests. ETags are preferred over Last-Modified for sub-second precision, no timezone complexity, and content-based rather than time-based validation. ETag computation strategies include MD5 or SHA hash of content ensuring any content change generates new ETag, version number incremented on each modification providing simple sequential ETags, or combination of timestamp and content size providing fast computation with reasonable collision resistance. Cache-Control and ETag interaction shows Cache-Control: max-age defines staleness before validation while ETag enables validation. Complement each other for comprehensive caching strategy. Multiple representations with same URL use Vary header with ETags ensuring different compressed/uncompressed versions have different ETags. Vary: Accept-Encoding indicates ETag depends on encoding. Distributed systems require consistent ETag generation across all service instances through centralized version tracking, content-based hashing producing same hash on any instance, or synchronized timestamps. Option A is incorrect because eliminating caching headers forces complete resource transfer every request wasting bandwidth and degrading performance unnecessarily. Option C is incorrect because indefinite caching without validation serves stale data indefinitely violating data freshness requirements when resources change. Option D is incorrect because random ETags defeat validation purpose as changed ETag doesn’t indicate actual resource change causing cache invalidation even when resource is unchanged.
Question 120:
A developer needs to implement graceful shutdown for containerized applications. What should be implemented for graceful shutdown?
A) Kill application immediately on shutdown signal
B) Implement graceful shutdown handling SIGTERM signal, completing in-flight requests, closing database connections, and responding within termination grace period
C) Ignore shutdown signals
D) Restart application instead of shutting down
Answer: B
Explanation:
Graceful shutdown handling SIGTERM, completing requests, and closing connections cleanly prevents data loss and ensures availability during deployments, making option B the correct answer. Container orchestrators like Kubernetes send termination signals expecting applications to shut down gracefully. SIGTERM signal indicates container should terminate. Applications should trap SIGTERM and initiate shutdown sequence. After grace period (typically 30 seconds), forceful SIGKILL terminates application immediately. Shutdown sequence follows specific order: stop accepting new requests by closing listen sockets or removing from load balancer, complete in-flight requests allowing current operations to finish naturally, close database connections gracefully committing transactions, flush logs and metrics ensuring observability data is persisted, and exit process with status code 0 indicating clean shutdown. Request completion waits for active requests with timeout. Graceful period allows requests to complete but doesn’t wait indefinitely. Timeout prevents hung requests from blocking shutdown. Load balancer deregistration removes instance from service discovery or load balancer rotation before beginning shutdown. This prevents new traffic routing to terminating instance. Database connection pool draining closes connections gracefully after completing active queries. Abrupt close risks incomplete transactions or connection corruption. Health check failure marking instance unhealthy during shutdown guides orchestrator to stop routing traffic. Failed health checks combined with readiness probe failure ensures clean traffic drainage. Message queue consumer shutdown stops accepting new messages, processes messages already retrieved, and acknowledges processed messages preventing message loss during shutdown. Preemptive scale-down notification from orchestrator signals upcoming shutdown enabling proactive cleanup. Some platforms provide advance warning before SIGTERM. Shutdown hooks in application frameworks provide convenient mechanism for registering cleanup functions executed during shutdown. Most frameworks support graceful shutdown configuration. Timeout handling respects orchestrator termination grace period (default 30s in Kubernetes). Applications should complete shutdown before forceful termination. Monitoring and logging capture shutdown events including reason for shutdown, pending request count at shutdown, cleanup duration, and any errors during shutdown enabling debugging shutdown issues. Testing graceful shutdown includes sending SIGTERM in development, verifying request completion, checking connection cleanup, and validating no data loss. Regular testing prevents shutdown bugs. Option A is incorrect because immediate kill terminates mid-request causing incomplete operations, connection leaks, uncommitted transactions, and potentially corrupt state. Option C is incorrect because ignoring shutdown signals leads to forceful SIGKILL termination after grace period causing same problems as immediate kill. Option D is incorrect because restarting instead of shutting down violates orchestrator expectations preventing clean container lifecycle management.