You can find code example for this chapter here.
AppSync is a serverless API. On the upside that means you don't need to worry about scaling and a solution is expected to work the same when it gets almost no requests as when it's running in production. On the downside, serverless also means some limits on request/response sizes and times. And that means it does not play well with files.
Of course, nothing prevents an implementation to encode a field as base64 for downloads or an argument encoded similarly for uploads. But that puts an implicit upper limit on the sizes: at some point AppSync will throw an error when data in either direction gets too large. When this happens is a bit blurry, but it definitely won't work for a site that serves videos, for example.
The solution is to use a mechanism called signed URLs. Here, handling files is moved to a dedicated service in a way that retains most of the security properties of the non-serverless approach. In AWS's case, that means storing files in an S3 bucket and using a Lambda function with AppSync to sign URLs for uploading and downloading files. This approach is not specific to AppSync or even to AWS, all serverless APIs that need to handle files of arbitrary sizes use it.
Signed URLs work by adding authentication parameters and a signature to a URL. For example, this is a URL for an S3 object signed by an IAM role:
https://terraform-202....s3.eu-central-1.amazonaws.com /ded45605602f5e8708....jpg? X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Content-Sha256=UNSIGNED-PAYLOAD& X-Amz-Credential=ASIAUB3O2IQ5BLYHGAP2...& X-Amz-Date=20230323T094000Z& X-Amz-Expires=900& X-Amz-Security-Token=IQoJb3Jp....& X-Amz-Signature=a8ad50392eab292de32...& X-Amz-SignedHeaders=host& x-id=GetObject