Development with AWS Services · Topic 2 of 7

SDK Calls, Serialization, and Resilience

Call AWS services with SDKs, convert data to and from the wire formats services expect, and build in retries with backoff and graceful degradation.

  • 5 min
In a nutshell
  • Use the credential provider chain and IAM roles, never hard coded keys.
  • Create SDK clients outside the Lambda handler so that they are reused.
  • Retry with exponential backoff and jitter; the SDK default standard mode does this.

What it is

Every AWS service is an HTTPS API. An AWS SDK (Boto3 for Python, the AWS SDK for JavaScript, Java and others) signs each request, sends it, parses the reply and retries some failures for you.

Serialization turns an in memory object into text or bytes that a service accepts, such as a JSON string for an SQS message body. Deserialization turns the reply back into an object.

A resilient application expects calls to fail now and then. It retries the right errors with backoff, and it keeps working in a reduced way when a dependency stays down.

Your codeobjectserializeSDK clientsign and sendHTTPSAWS servicereturns bytesdeserializeYour codeobject

How it works

Using an SDK correctly

  • Credentials come from the default provider chain: code settings, environment variables, shared profile files, then container or instance roles. In Lambda the chain finds the execution role, so you never put access keys in code.
  • Region must be set in config, in an environment variable or on the client.
  • Create clients outside the handler in Lambda, so warm invocations reuse the connection.
  • Paginators loop over truncated results. S3 ListObjectsV2 returns a limited page of keys, and a paginator follows the continuation token for you.
  • Waiters poll until a resource reaches a state, such as a table becoming active.
import json, boto3

sqs = boto3.client("sqs")          # created once, reused

def handler(event, context):
    sqs.send_message(
        QueueUrl=QUEUE_URL,
        MessageBody=json.dumps({"orderId": "42"}),   # serialize
    )

Serialization by service

Service callWire formatWhat your code must do
SQS and SNS message bodyStringjson.dumps to send, json.loads to read
SNS to SQS deliveryJSON envelope around your messageParse the envelope, or enable raw message delivery
Kinesis recordBinary blobEncode to bytes; Lambda hands it over base64 encoded, so decode it
DynamoDB low level APITyped values such as {"S": "abc"} and {"N": "42"}Use the resource or document interface, which converts types
Lambda Invoke responseStreaming payloadRead the stream, then parse the JSON
API Gateway proxy with binary bodyBase64 textSet isBase64Encoded and decode

Two classic traps are worth knowing. DynamoDB sends numbers as strings, and the Python resource interface rejects float values, so use Decimal. And the Payload from a Lambda Invoke call is a stream, so calling json.loads on it directly fails until you .read() it.

Retries with exponential backoff

SDKs retry automatically. The recommended standard retry mode (the default in most current SDKs) uses exponential backoff with jitter, which means each wait is longer than the last and randomized so that many clients do not retry together. You can change the retry mode (standard, adaptive or legacy) and the maximum attempts in code, environment variables or the shared config file.

  • Throttling and server errors are retried, for example ThrottlingException, ProvisionedThroughputExceededException and HTTP 5xx.
  • Client errors such as ValidationException and AccessDeniedException are not retried, because repeating them cannot succeed.
  • Adaptive mode adds client side rate limiting, which suits a single throttled resource but can slow other calls from the same client.

Retries are safe only for idempotent work. Pass a client token where an API offers one (many create calls accept ClientToken or ClientRequestToken), use SQS FIFO deduplication, or write with condition expressions.

Batch calls need extra care. PutRecords, SendMessageBatch and BatchWriteItem can succeed overall while some items fail, and the response lists them (for example UnprocessedItems). Your code must retry just those items, with backoff.

Graceful degradation

When a dependency fails, serve something useful instead of an error.

  • Return cached or default data, such as a generic recommendation list.
  • Skip a nonessential call, such as analytics, and continue.
  • Set connect and read timeouts so that a hung call fails fast.
  • Park failed work in a dead letter queue so that it can be replayed later.
Call failsthrottle or 5xxSDK retriesBackoff and jitterlonger waitsstill failingFallbackcache or default

How the exam asks about this

  • "A function calling DynamoDB gets ProvisionedThroughputExceededException during bursts." -> Rely on SDK retries with exponential backoff and jitter, and reduce request bursts.
  • "The recommendation service is down, but checkout must still work." -> Degrade gracefully: skip it or return default items.
  • "A Lambda function reads a Kinesis record and gets unreadable text." -> The data is base64 encoded, so decode it before parsing.

What to remember for the exam

  • Use the credential provider chain and IAM roles, never hard coded keys.
  • Create SDK clients outside the Lambda handler so that they are reused.
  • Retry with exponential backoff and jitter; the SDK default standard mode does this.
  • Do not retry validation or access denied errors, because they will keep failing.
  • Retry only idempotent operations, or add a client token or conditional write.
  • Check batch responses for failed or unprocessed items and retry only those.
  • Lambda delivers Kinesis data base64 encoded; DynamoDB low level numbers are strings.
Watch out

Retrying a non idempotent call, such as charging a card, can run it twice. Add an idempotency key before you rely on retries.

Common mistakes

Treating a batch call as all or nothing. A 200 response from BatchWriteItem can still contain unprocessed items. Always inspect the response.

Retrying everything in a loop. A tight retry loop without backoff adds load to a service that is already struggling. Use the SDK settings instead of writing your own.

Parsing before decoding. Binary or base64 payloads, such as Kinesis data in Lambda, must be decoded before json.loads can read them.

Check yourself

  • Which errors does the SDK retry by default?

    Transient and throttling errors, such as HTTP 5xx and ThrottlingException, but not client errors like ValidationException.

  • Why must Python code use Decimal instead of float for DynamoDB numbers?

    DynamoDB stores numbers as typed strings, and the Boto3 resource interface rejects float values.

  • What should you do after a BatchWriteItem call returns UnprocessedItems?

    Retry only the unprocessed items, using exponential backoff.

Topic 2 of 7 in Development with AWS Services

Test yourself on Development with AWS Services

The full AWS DVA-C03 question bank has 850 questions, with timed practice exams and an explanation for every answer.

This study guide is independent and is not affiliated with, endorsed by, or sponsored by AWS. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.