<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roman Sytnyk</title>
    <description>The latest articles on DEV Community by Roman Sytnyk (@romansytnyk).</description>
    <link>https://dev.to/romansytnyk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F983117%2F41aea111-1587-46cf-99fb-73b4c860193b.jpeg</url>
      <title>DEV Community: Roman Sytnyk</title>
      <link>https://dev.to/romansytnyk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/romansytnyk"/>
    <language>en</language>
    <item>
      <title>Caching images from Amazon S3 in React Native</title>
      <dc:creator>Roman Sytnyk</dc:creator>
      <pubDate>Tue, 13 Dec 2022 09:37:34 +0000</pubDate>
      <link>https://dev.to/romansytnyk/caching-images-from-amazon-s3-in-react-native-11ki</link>
      <guid>https://dev.to/romansytnyk/caching-images-from-amazon-s3-in-react-native-11ki</guid>
      <description>&lt;p&gt;&lt;em&gt;This post explains how to fix caching of images from Amazon S3 bucket and similar storage services in React Native using a custom cache key.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Aloha, everyone!&lt;/p&gt;

&lt;p&gt;Recently, I was working on a React Native app, whose back-end was relying on Amazon S3 bucket as image hoster.&lt;/p&gt;

&lt;p&gt;In order to optimize the performance of the app &amp;amp; reduce the network traffic of the app, it was required to cache images, preferably with some animations.&lt;/p&gt;

&lt;p&gt;To accomplish this task, we’ve chosen &lt;a href="https://github.com/georstat/react-native-image-cache" rel="noopener noreferrer"&gt;georstat/react-native-image-cache&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;Setup of this library is pretty simple. After installation, it’s required to create a global config in App.tsx or index.js for image caching, as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CacheManager } from '@georstat/react-native-image-cache';
import { Dirs } from 'react-native-file-access';

CacheManager.config = {
  baseDir: `${Dirs.CacheDir}/images_cache/`,
  blurRadius: 15,
  cacheLimit: 0,
  sourceAnimationDuration: 500,
  thumbnailAnimationDuration: 500,
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more options, please, look at the official documentation on GitHub page.&lt;/p&gt;

&lt;p&gt;Following usage of image component in the code looks similar to the usage of standard Image component of React Native:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CachedImage } from '@georstat/react-native-image-cache';

&amp;lt;CachedImage
  source="https://via.placeholder.com/3500x3500"
  style={{ height: 350, width: 150 }}
  thumbnailSource="https://via.placeholder.com/350x150"
/&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But here we faced our problem with images from Amazon S3 bucket!&lt;/p&gt;

&lt;p&gt;With each app startup, the app was re-downloading images from scratch! Cache doesn’t work.&lt;/p&gt;

&lt;p&gt;I started looking for the source of the problem.&lt;/p&gt;

&lt;p&gt;Firstly, I looked at the image URL, which I was receiving from the REST API via our back-end.&lt;/p&gt;

&lt;p&gt;It had a similar view:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://test-imagedata.s3.eu-west-2.amazonaws.com/uploads/images/filename/614/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=creds&amp;amp;X-Amz-Date=20221202T110948Z&amp;amp;X-Amz-Expires=900&amp;amp;X-Amz-SignedHeaders=host&amp;amp;X-Amz-Signature=token" rel="noopener noreferrer"&gt;https://test-imagedata.s3.eu-west-2.amazonaws.com/uploads/images/filename/614/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=creds&amp;amp;X-Amz-Date=20221202T110948Z&amp;amp;X-Amz-Expires=900&amp;amp;X-Amz-SignedHeaders=host&amp;amp;X-Amz-Signature=token&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you can see, we receive an image with credentials and tokens in the URL as params for the access to it — URL params such as &lt;em&gt;X-Amz-Algorigthm, Z-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amx-Signature&lt;/em&gt; and other.&lt;/p&gt;

&lt;p&gt;After that, I searched for the details, what key library is using for images in order to cache them, and I’ve found this code in CacheEntry class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
const { exists, path, tmpPath } = await getCacheEntry(source, maxAge);

...
const getCacheEntry = async ( cacheKey: string, maxAge?: number | undefined ): Promise&amp;lt;{ exists: boolean; path: string; tmpPath: string }&amp;gt; =&amp;gt; {
…
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see that the library is using the whole image URL as a cache key!&lt;/p&gt;

&lt;p&gt;And that’s the reason of caching bug with Amazons S3.&lt;/p&gt;

&lt;p&gt;The library is re-downloading &amp;amp; caching the same image multiple times, but with different URL (different access token).&lt;/p&gt;

&lt;p&gt;It consumes additional disk space &amp;amp; network traffic of the users.&lt;/p&gt;

&lt;p&gt;What can we do with that bug?&lt;/p&gt;

&lt;p&gt;The back-end couldn’t do anything about that from their side.&lt;/p&gt;

&lt;p&gt;Also this problem is actual inother popular image libraries for React Native, such as DylanVann/react-native-fast-image&lt;br&gt;
Solution&lt;/p&gt;

&lt;p&gt;So, I’ve decided to make a contribution to the image library to allow setting custom cache keys in the global CacheConfig with getCustomCacheKey function.&lt;/p&gt;

&lt;p&gt;So, in the case of Amazon S3 bucket, it’s enough to use as a custom cache key based on the image URL just without any params. Something like that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://test-imagedata.s3.eu-west-2.amazonaws.com/uploads/images/filename/614/image.png" rel="noopener noreferrer"&gt;https://test-imagedata.s3.eu-west-2.amazonaws.com/uploads/images/filename/614/image.png&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to achieve this, I’ve added removing URL params logic in getCustomCacheKey function in CacheConfig:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CacheManager.config = {
  // ...
  getCustomCacheKey: (source: string) =&amp;gt; {
    // Remove params from the URL for caching images (useful for caching images from Amazons S3 bucket and etc)
    let newCacheKey = source;
    if (source.includes('?')) {
      newCacheKey = source.substring(0, source.lastIndexOf('?'));
    }
    return newCacheKey;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, it works, the app is caching images from Amazon S3 storage.&lt;/p&gt;

&lt;p&gt;This solution could be useful also with other storage services, which put tokens and credentials into the URL of the image.&lt;br&gt;
Also you can add additional checks or regexp in the case, if it shouldn’t influence all images URLs in the app.&lt;/p&gt;

&lt;p&gt;Also you can set a custom cache key as you want with getCustomCacheKey function of CacheManager according to your requirements.&lt;/p&gt;

&lt;p&gt;Thank you for your attention&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tooling</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
