<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sam Wallace, Author at DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/author/samw/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Fri, 04 Sep 2026 15:08:10 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://static.dmcinfo.com/wp-content/uploads/2025/04/site-icon-150x150.png</url>
	<title>Sam Wallace, Author at DMC, Inc.</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Copying and Populating Word Documents in SharePoint Online Using Power Automate</title>
		<link>https://static.dmcinfo.com/blog/15946/copying-and-populating-word-documents-in-sharepoint-online-using-power-automate/</link>
		
		<dc:creator><![CDATA[Sam Wallace]]></dc:creator>
		<pubDate>Thu, 10 Oct 2024 11:24:49 +0000</pubDate>
				<category><![CDATA[Digital Workplace Solutions]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Power Automate]]></category>
		<category><![CDATA[SharePoint Online]]></category>
		<category><![CDATA[Word]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/15946/copying-and-populating-word-documents-in-sharepoint-online-using-power-automate/</guid>

					<description><![CDATA[<p>Does your team spend too much time creating Word documents from templates and monotonously changing only a small set of specific details in its content? Tasks like these are common for businesses that author reports or proposals as deliverables to clients, but few take the time to automate this data entry process. With SharePoint Online [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/15946/copying-and-populating-word-documents-in-sharepoint-online-using-power-automate/">Copying and Populating Word Documents in SharePoint Online Using Power Automate</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Does your team spend too much time creating Word documents from templates and monotonously changing only a small set of specific details in its content? Tasks like these are common for businesses that author reports or proposals as deliverables to clients, but few take the time to automate this data entry process. With SharePoint Online and Power Automate, you can inject content from any data source directly into a&nbsp;template Word file and avoid this work altogether!</p>



<h2 id="h-requirements" class="wp-block-heading">Requirements</h2>



<h3 id="h-power-automate" class="wp-block-heading">Power Automate</h3>



<p class="wp-block-paragraph">We will use Power Automate, Microsoft&#8217;s cloud-based business automation platform, to automate this process. In Power Automate, a single executable task is called a flow. Each component of a flow is called an action.</p>



<p class="wp-block-paragraph">To copy and populate Word documents in Power Automate, we must use an action from the Word Online connector which <strong>requires a Power Automate Premium account.</strong></p>



<h3 id="h-sharepoint-online" class="wp-block-heading">SharePoint Online</h3>



<p class="wp-block-paragraph">For the flow we will write, we need a cloud-based location to source the Word document template and a destination to send the populated template copy. If your organization uses SharePoint Online, there are actions we can add that retrieve and save files in SharePoint out of the box!</p>



<h3 id="h-word" class="wp-block-heading">Word</h3>



<p class="wp-block-paragraph">The document templates are created in Word and saved as a <em>.docx</em> file.</p>



<h2 id="h-implementation" class="wp-block-heading">Implementation</h2>



<h3 id="h-part-1-creating-your-word-template" class="wp-block-heading">Part 1: Creating Your Word Template</h3>



<p class="wp-block-paragraph">Let us start off with an example document template that has some placeholder fields.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/blog-word-template.png" alt="A white screen with black textDescription automatically generated"/></figure>



<p class="wp-block-paragraph">To denote the <em>{insert}</em>&nbsp;placeholder values as fields that we want to be able to overwrite with our flow, mark each of them as a &#8220;Plain Text Control&#8221; which you can do on the &#8220;Developer&#8221; tab in the Word editor.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/blog-word-template2.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">We&nbsp;can then configure the control by selecting it on the page (it should show up as a gray box outline around the placeholder text) and select the &#8220;Control Properties&#8221; widget next to the plain text control button.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/blog-word-template3.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">This will open the following dialog. You can name the control anything, but make sure it is descriptive if you are adding multiple&nbsp;controls to your template so there is no confusion when connecting data sources to the controls in Power Automate.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/blog-word-template4.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">At this point, the file is ready for use as a template.&nbsp;Let us save it&nbsp;to a location in SharePoint Online so that our Power Automate flow can make copies of it. If the account creating the flow is different from the account which uploads the document, make sure that it&nbsp;is saved to a location that the former can also access.</p>



<h3 id="h-part-2-creating-the-flow-in-power-automate" class="wp-block-heading">Part 2: Creating the Flow in Power Automate</h3>



<p class="wp-block-paragraph">To create the template population flow, go to the Power Automate console in your browser and click &#8220;Create.&#8221;&nbsp;The type of flow you create depends on what will trigger it. There are three cloud-native flow types available:</p>



<ol class="wp-block-list">
<li>Automated Cloud flow &#8211; a flow that is triggered through a designated event.</li>



<li>Instant Cloud flow &#8211; a flow that is triggered manually through the Power Automate console or through an external command like an HTTP request.</li>



<li>Scheduled flow &#8211; a flow that is triggered automatically on a set schedule.</li>
</ol>



<p class="wp-block-paragraph">Your situation may differ, but as an example, we will create a flow that is manually triggered via an HTTP request that contains all the data populated to the template.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/blog-pa.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">Once we&#8217;ve created the flow,&nbsp;we need to source the content that will populate our template. Since our content passes&nbsp;into the flow with the HTTP request trigger, we will update the output schema of the trigger so we have references to the values we want to pull from the request body. Again, this will differ based on the type of trigger/data source for your flow.&nbsp;Here is an example of what this looks like with our example HTTP trigger, where we define the input schema and specify that the request includes the &#8220;projectName&#8221; value.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/blog-pa2.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">Next, we will add the &#8220;Populate a Microsoft Word Template&#8221; action. When we&nbsp;select the template file, we can see the control fields that can be populated in our flow in the &#8220;Advanced Parameters&#8221; section, identified by the names we specified in the template document. We will specify the values that should be inserted to each field.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/blog-pa3.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">The output of the Word connector is an unsaved copy of our populated template file, which we will then pipe to the &#8220;Create File&#8221; action that saves the file in a specified location in SharePoint.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/blog-pa4.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">Once you specify the location to save the file, the flow is complete.&nbsp;Go ahead and save the flow and test it out.</p>



<h2 id="h-further-considerations" class="wp-block-heading">Further Considerations</h2>



<p class="wp-block-paragraph">As stated before, access to template documents is not guaranteed when you create the flow, based on the SharePoint sites your account has access to. It may be worth setting up flows with an admin account in your organization&nbsp;to ensure they will not break if permissions for certain users are modified. Additionally, updating the template file may cause issues, as references to the control fields in your flow may break when the source template document is updated in the future. If your flow is mission-critical, make sure there is a well-defined system for modifying your template files to avoid any unexpected failures.</p>



<p class="wp-block-paragraph">Power Automate is incredibly useful for automating workflows like these Word templates we have populated. Additionally, you can easily extend a flow like this with conditional logic or other downstream actions for SharePoint/other integrated services, all in one portal. DMC has extensive experience with Power Automate and many other digital workplace technologies. To see how your business processes can be optimized, give us a call!</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Automate Repetitive Word Document Creation</strong>.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Learn more about our <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/" data-type="page" data-id="437">Digital Workplace Solutions</a> for populating Word templates and managing document workflows for your <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/sharepoint/" data-type="page" data-id="1743">SharePoint</a> operations.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/15946/copying-and-populating-word-documents-in-sharepoint-online-using-power-automate/">Copying and Populating Word Documents in SharePoint Online Using Power Automate</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Embedding Private Media Files Securely in a React Frontend with Amazon S3 and AWS Lambda</title>
		<link>https://static.dmcinfo.com/blog/16076/embedding-private-media-files-securely-in-a-react-frontend-with-amazon-s3-and-aws-lambda/</link>
		
		<dc:creator><![CDATA[Sam Wallace]]></dc:creator>
		<pubDate>Wed, 31 Jul 2024 18:30:36 +0000</pubDate>
				<category><![CDATA[Web Application Development]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/16076/embedding-private-media-files-securely-in-a-react-frontend-with-amazon-s3-and-aws-lambda/</guid>

					<description><![CDATA[<p>Amazon Simple Storage Service (S3) is a low-cost service for storing and serving unstructured data, which makes it perfect for hosting any media that will be displayed or referenced in your&#160;React frontend (PDFs, images, etc.). However, if the media fetched by your frontend is read-restricted to only authenticated users of your application, then embedding this [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/16076/embedding-private-media-files-securely-in-a-react-frontend-with-amazon-s3-and-aws-lambda/">Embedding Private Media Files Securely in a React Frontend with Amazon S3 and AWS Lambda</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Amazon Simple Storage Service (S3) is a low-cost service for storing and serving unstructured data, which makes it perfect for hosting any media that will be displayed or referenced in your&nbsp;React frontend (PDFs, images, etc.). However, if the media fetched by your frontend is read-restricted to only authenticated users of your application, then embedding this content gets tricky. In this post, I&#8217;ll expand on my previous post about <a href="https://static.dmcinfo.com/latest-thinking/blog/id/12642/externally-authenticated-access-to-s3-objects-over-the-internet">externally authenticated&nbsp;access to private S3 objects</a>&nbsp;with an outline for a generalized solution to&nbsp;embedding private S3 content into your React components.</p>



<h2 id="h-object-retrieval-pattern" class="wp-block-heading">Object Retrieval Pattern</h2>



<p class="wp-block-paragraph">We&#8217;ll be using presigned S3 object URLs to fetch our private Amazon S3 data. See my previous post linked above to learn more about this design. Below is a diagram visualizing the dataflow of authorizing the React frontend to fetch an image file, using presigned URLs.</p>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6abf21ac13246&quot;}" data-wp-interactive="core/image" data-wp-key="6abf21ac13246" class="wp-block-image size-full is-resized wp-lightbox-container"><img fetchpriority="high" decoding="async" width="747" height="441" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://static.dmcinfo.com/wp-content/uploads/2024/07/object-retreival-pattern-react-frontend.png" alt="" class="wp-image-36100" style="width:480px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2024/07/object-retreival-pattern-react-frontend.png 747w, https://static.dmcinfo.com/wp-content/uploads/2024/07/object-retreival-pattern-react-frontend-300x177.png 300w" sizes="(max-width: 747px) 100vw, 747px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">Click image to expand.</figcaption></figure>



<h2 id="h-initial-implementation" class="wp-block-heading">Initial Implementation</h2>



<p class="wp-block-paragraph">Let&#8217;s set up a simple component with a single <code>&lt;img&gt;</code> element that we&#8217;d like to link to our desired resource, with the resource URL passed as a prop to the component.</p>



<p class="wp-block-paragraph"></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const S3Image = ({ objectUrl }) => {

    return &lt;img src={objectUrl} alt="Image" />;

}

export default S3Image;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">S3Image</span><span style="color: #D4D4D4"> = ({ </span><span style="color: #9CDCFE">objectUrl</span><span style="color: #D4D4D4"> }) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">img</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">objectUrl</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">alt</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Image&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">default</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">S3Image</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">If we want to fetch the presigned URL for the corresponding object pointed to by <code>objectUrl, </code>we need to ensure that the URL embedded into the <code>&lt;img&gt;</code> element is up to date with the object specified in the props.&nbsp;We can set up some local state to store the signed URL and a useEffect to fetch the URL&nbsp;when the <code>objectPath</code> prop&nbsp;changes.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import React, { useState, useEffect } from 'react';
const S3Image = ({ objectPath }) => {

    const &#91;signedUrl, setSignedUrl&#93; = useState('');

    useEffect( async () => {

        try {

            const response = await fetch('/get-signed-url', { objectPath });

            const data = await response.json();

            setSignedUrl(data.url);

        } catch (error) {

            console.error('Error fetching signed URL:', error);

        }

    }, &#91;objectPath&#93;);

 

  return (

      &lt;img src={signedUrl} alt="Image" />

  );

};

export default S3Image;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">React</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">useState</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">useEffect</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;react&apos;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">S3Image</span><span style="color: #D4D4D4"> = ({ </span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4"> }) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> &#91;</span><span style="color: #4FC1FF">signedUrl</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">setSignedUrl</span><span style="color: #D4D4D4">&#93; = </span><span style="color: #DCDCAA">useState</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;&apos;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">useEffect</span><span style="color: #D4D4D4">( </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">response</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">fetch</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;/get-signed-url&apos;</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">data</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">json</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">setSignedUrl</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">url</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">error</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;Error fetching signed URL:&apos;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    }, &#91;</span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4">&#93;);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">img</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">signedUrl</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">alt</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Image&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  );</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">default</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">S3Image</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">For simplicity, we&#8217;ll&nbsp;handle the signed URL&nbsp;creation in&nbsp;lambda function&nbsp;running Node.js. This assumes that an API Gateway is set up to proxy the HTTP request from the react app to this Lambda function, but this pattern could be implemented with other AWS compute resources/VPC connection methods if more applicable.&nbsp;To see more on how to implement this API Gateway + Lambda stack, see my blog on <a href="https://static.dmcinfo.com/latest-thinking/blog/id/12641/cloud-deployments-in-minutes-with-serverless-framework-and-aws-lambda">Cloud APIs in minutes with Serverless Framework and AWS Lambda</a>.</p>



<p class="wp-block-paragraph">We&#8217;ll use the AWS SDK to generate a presigned URL for this image file.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const AWS = require('aws-sdk');

AWS.config.update({

    accessKeyId: // IAM user credentials that have access to the S3 bucket

    secretAccessKey: // IAM user secret key

    signatureVersion: 'v4',

    region: // enter your region here

});

 

const s3 = new AWS.S3();

 

module.exports = async (event) => {

    try {

        // get request parameters

        const body = JSON.parse(event.body);

       

        if(!(body.objectPath?.length)){

            return { statusCode: 400, body: JSON.stringify({error: "Invalid object path"}) };  

        }

 

        const url = s3.getSignedUrl(input.object_method, {

            Bucket: // specify the bucket we're pulling from

            Key: body.object_path,

            Expires: //specify the lifetime of the URL (in milliseconds)

        });

 

        return { statusCode: 200, body: JSON.stringify({url}) };

    } catch (error) {

        return { statusCode: 500, body: JSON.stringify(error) };

    }

}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;aws-sdk&apos;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">update</span><span style="color: #D4D4D4">({</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">accessKeyId:</span><span style="color: #D4D4D4"> </span><span style="color: #6A9955">// IAM user credentials that have access to the S3 bucket</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">secretAccessKey</span><span style="color: #D4D4D4">: </span><span style="color: #6A9955">// IAM user secret key</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">signatureVersion</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&apos;v4&apos;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">region:</span><span style="color: #D4D4D4"> </span><span style="color: #6A9955">// enter your region here</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">s3</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">S3</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #4EC9B0">module</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// get request parameters</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">body</span><span style="color: #D4D4D4"> = </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">parse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">       </span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4">(!(</span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4">?.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4">)){</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">statusCode:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">400</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">stringify</span><span style="color: #D4D4D4">({</span><span style="color: #9CDCFE">error:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Invalid object path&quot;</span><span style="color: #D4D4D4">}) };  </span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">url</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">s3</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getSignedUrl</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">input</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">object_method</span><span style="color: #D4D4D4">, {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Bucket:</span><span style="color: #D4D4D4"> </span><span style="color: #6A9955">// specify the bucket we&apos;re pulling from</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Key</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">object_path</span><span style="color: #D4D4D4">,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Expires:</span><span style="color: #D4D4D4"> </span><span style="color: #6A9955">//specify the lifetime of the URL (in milliseconds)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">statusCode:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">200</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">stringify</span><span style="color: #D4D4D4">({</span><span style="color: #9CDCFE">url</span><span style="color: #D4D4D4">}) };</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">statusCode:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">500</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">stringify</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">) };</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">And there it is! With this implementation alone, you&#8217;ll be able to display that image in your app, even though it&#8217;s not publicly accessible in S3.</p>



<h2 id="h-caveat-signed-url-expiration" class="wp-block-heading">Caveat &#8211; Signed URL Expiration</h2>



<p class="wp-block-paragraph">There&#8217;s one large issue with this implementation—the presigned URLs expire! Each presigned URL generated has a lifespan of a duration (configurable when the URL is generated), and after this time, requests using that&nbsp;URL will fail. This is to prevent persisting public access to the object. Remember, <em>anyone</em> with the presigned URL can use it, as long as it has not expired!</p>



<p class="wp-block-paragraph">This will not be an issue for any media fetched and displayed in the browser on page load (like our image component above), but what if you want to provide a download link to the image file? The user may linger on the page after it&#8217;s initially loaded&nbsp;and only request the file from S3 by clicking the link after the signature has expired. This leads to a nasty error screen and is probably not what your users want to see.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/url-timeout-error.png" alt=""/></figure>



<p class="wp-block-paragraph">So, we don&#8217;t want to let presigned URLs embedded into the page expire, but we also don&#8217;t want to disable the presigned URL&#8217;s timeout. To get around this, we&#8217;ll add logic to periodically re-generate the presigned URL for the given asset. Below is our component, updated with the logic to re-fetch the URL periodically (using the useInterval custom hook from the use-interval package).</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import React, { useState, useCallback } from 'react';

import useInterval from 'use-interval';

 

const S3Image = ({ objectPath }) => {

    const &#91;signedUrl, setSignedUrl&#93; = useState('');

    // define the function used to fetch the signed URL

    const getSignedUrl = useCallback(async () => {

        try {

            const response = await fetch('/get-signed-url', { objectPath });

            const data = await response.json();

            setSignedUrl(data.url);

        } catch (error) {

            console.error('Error fetching signed URL:', error);

        }

    }, &#91;objectPath&#93;);

    // call the function defined above every second

    useInterval( getSignedUrl, 1000, true );

    return &lt;img src={signedUrl} alt="Image" />;

};

export default S3Image;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">React</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">useState</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">useCallback</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;react&apos;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">useInterval</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;use-interval&apos;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">S3Image</span><span style="color: #D4D4D4"> = ({ </span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4"> }) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> &#91;</span><span style="color: #4FC1FF">signedUrl</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">setSignedUrl</span><span style="color: #D4D4D4">&#93; = </span><span style="color: #DCDCAA">useState</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;&apos;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// define the function used to fetch the signed URL</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">getSignedUrl</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">response</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">fetch</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;/get-signed-url&apos;</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">data</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">json</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">setSignedUrl</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">url</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">error</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;Error fetching signed URL:&apos;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    }, &#91;</span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4">&#93;);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// call the function defined above every second</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">useInterval</span><span style="color: #D4D4D4">( </span><span style="color: #9CDCFE">getSignedUrl</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1000</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4"> );</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">img</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">signedUrl</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">alt</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Image&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">default</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">S3Image</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">This implementation can be further ruggedized by modifying our Lambda function to return the&nbsp;lifetime along with the URL itself,&nbsp;such that the client knows exactly when it will need to regenerate it.&nbsp;However, regenerating the URL is not a time or compute intensive operation, so simply regenerating more often than you would ever expect the presigned URL timeout to be set to&nbsp;is most likely a reliable solution.</p>



<h2 id="h-abstracting-as-a-custom-hook" class="wp-block-heading">Abstracting as a Custom Hook</h2>



<p class="wp-block-paragraph">As a one-off use of this procedure, this implementation is perfectly suitable now. However, this logic would muddy your state management design if added in multiple locations or more complex components. To avoid this, let&#8217;s abstract this logic into a custom hook that&nbsp;provides the&nbsp;presigned URL for the S3 object path&nbsp;passed to it.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import React, { useState, useCallback } from 'react';

import useInterval from 'use-interval';

 

export const useSignedUrl = (objectPath) => {

    const &#91;signedUrl, setSignedUrl&#93; = useState('');

    const getSignedUrl = useCallback(async () => {

        try {

            const response = await fetch('/get-signed-url', { objectPath });

            const data = await response.json();

            setSignedUrl(data.url);

        } catch (error) {

            console.error('Error fetching signed URL:', error);

        }

    }, &#91;objectPath&#93;);

    useInterval( getSignedUrl, 1000, true );

    return signedUrl;

};</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">React</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">useState</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">useCallback</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;react&apos;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">useInterval</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;use-interval&apos;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">useSignedUrl</span><span style="color: #D4D4D4"> = (</span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> &#91;</span><span style="color: #4FC1FF">signedUrl</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">setSignedUrl</span><span style="color: #D4D4D4">&#93; = </span><span style="color: #DCDCAA">useState</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;&apos;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">getSignedUrl</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">response</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">fetch</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;/get-signed-url&apos;</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">data</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">json</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">setSignedUrl</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">url</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">error</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;Error fetching signed URL:&apos;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    }, &#91;</span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4">&#93;);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">useInterval</span><span style="color: #D4D4D4">( </span><span style="color: #9CDCFE">getSignedUrl</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1000</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4"> );</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">signedUrl</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">};</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">This simplifies our component definition significantly.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import useSignedUrl from './useSignedUrl';

const S3Image = ({ objectPath }) => {

    const signedUrl = useSignedUrl(objectPath);

    return &lt;img src={signedUrl} alt="Image" />;

};

export default S3Image;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">useSignedUrl</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;./useSignedUrl&apos;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">S3Image</span><span style="color: #D4D4D4"> = ({ </span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4"> }) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">signedUrl</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useSignedUrl</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">objectPath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">img</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">signedUrl</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">alt</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Image&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">default</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">S3Image</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">With this, we have a clean, generalized solution for embedding restricted S3 content in our components.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Securely Deliver Private Media in React</strong>.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Explore our <a href="https://static.dmcinfo.com/services/application-development/" data-type="page" data-id="434">Application Development</a> expertise in React, Amazon S3, and AWS Lambda for embedding protected media and our capabilities in <a href="https://static.dmcinfo.com/services/application-development/cloud-application-development/" data-type="page" data-id="710">Cloud App Dev Services</a>.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/16076/embedding-private-media-files-securely-in-a-react-frontend-with-amazon-s3-and-aws-lambda/">Embedding Private Media Files Securely in a React Frontend with Amazon S3 and AWS Lambda</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Externally Authenticated Access to S3 Objects Over the Internet</title>
		<link>https://static.dmcinfo.com/blog/16081/externally-authenticated-access-to-s3-objects-over-the-internet/</link>
		
		<dc:creator><![CDATA[Sam Wallace]]></dc:creator>
		<pubDate>Wed, 31 Jul 2024 17:11:11 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/16081/externally-authenticated-access-to-s3-objects-over-the-internet/</guid>

					<description><![CDATA[<p>Amazon S3 is great for storing any type of binary data or file you may need in a centralized location in the cloud. There is a dedicated URL for each object, which can be easily shared with anyone who needs to access it. However, say that your bucket is storing private/proprietary information. You wouldn&#8217;t want [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/16081/externally-authenticated-access-to-s3-objects-over-the-internet/">Externally Authenticated Access to S3 Objects Over the Internet</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Amazon S3 is great for storing any type of binary data or file you may need in a centralized location in the cloud. There is a dedicated URL for each object, which can be easily shared with anyone who needs to access it.</p>



<p class="wp-block-paragraph">However, say that your bucket is storing private/proprietary information. You wouldn&#8217;t want just anybody to be able to retrieve that data with an HTTP request, would you? In this blog, we&#8217;ll explore how we can securely and efficiently access Amazon S3 objects with either direct AWS or third-party authentication/authorization.</p>



<h2 id="h-bucket-policies" class="wp-block-heading">Bucket Policies</h2>



<p class="wp-block-paragraph">Bucket policies are the first step&nbsp;to restricting public access to objects. They apply to entire buckets in S3, and can be set up to only allow certain AWS IAM users, user roles, or methods of access to retrieve objects within the bucket to which it&#8217;s applied.</p>



<p class="wp-block-paragraph">Here&#8217;s a straightforward bucket policy to restrict any access to an S3 bucket except for those that provide IAM credentials that match to a specific user:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JSON</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::ACCOUNT_ID:user/USER_NAME"
            },
            "Action": &#91;
                "s3:GetObject"
            &#93;,
            "Resource": &#91;
                "arn:aws:s3:::BUCKET_NAME/*"
            &#93;
        }
    ]
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;Version&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;2012-10-17&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;Statement&quot;</span><span style="color: #D4D4D4">: [</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">&quot;Effect&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;Allow&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">&quot;Principal&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">&quot;AWS&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;arn:aws:iam::ACCOUNT_ID:user/USER_NAME&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">            },</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">&quot;Action&quot;</span><span style="color: #D4D4D4">: &#91;</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #CE9178">&quot;s3:GetObject&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">            &#93;,</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">&quot;Resource&quot;</span><span style="color: #D4D4D4">: &#91;</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #CE9178">&quot;arn:aws:s3:::BUCKET_NAME/*&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">            &#93;</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    ]</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Now this solution works for any situation where the client fetching the S3 object is able to provide permanent IAM credentials in their request. However, this is very rarely a valid solution. What if we have an existing&nbsp;authentication solution that we want to use to determine access to an S3 object? Or what if we don&#8217;t want/need to edit this policy whenever a new user needs access?</p>



<h2 id="h-accommodating-third-party-authentication" class="wp-block-heading">Accommodating Third-party Authentication</h2>



<p class="wp-block-paragraph">To abstract the IAM authentication layer entirely,&nbsp;we could proxy the S3 files through some intermediate compute resource&nbsp;within our VPC that:</p>



<ol class="wp-block-list">
<li>can authenticate a&nbsp;request with a 3rd party auth solution.</li>



<li>can access the buckets directly, with its own static set of IAM credentials.</li>
</ol>



<p class="wp-block-paragraph">Below is a diagram of this dataflow. Only the solid lines are data transfers that contain the data of the S3 object being requested.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Externally-authenticated-access-to-S3-objects1.png" alt=""/></figure>



<p class="wp-block-paragraph">This is, strictly speaking, an effective solution. However, S3 objects can be&nbsp;very large, so passing the whole object through some intermediary compute resource may incur unacceptable memory/data transfer&nbsp;costs. What we&#8217;d want is a way to securely access the S3 object while still being able to pull it directly from the bucket to the end client making the request, in order to take advantage of S3&#8217;s ultra-cost-efficient retrieval pricing.</p>



<p class="wp-block-paragraph">Enter &#8211; the presigned URL!</p>



<p class="wp-block-paragraph">Presigned URLs are used to temporarily authorize operations across AWS to anybody who has the URL. To generate a presigned URL for a specific action, your IAM policy must be authorized to perform that action. To mitigate the chance that the power of a presigned URL falls into the wrong hands, they are configured to only serve their purpose for a defined timeout.</p>



<p class="wp-block-paragraph">Using presigned URLs generated to provide access to individual S3 objects at request time, we can extend the secure access approach above, such that:</p>



<ol class="wp-block-list">
<li>The client sends an authenticated request using the 3rd-party auth to a compute resource (lambda works perfectly) with full read-access to our S3 bucket.</li>



<li>The compute resource authenticates this request against 3rd party auth.</li>



<li>The compute resource generates a pre-signed URL for the S3 object requested and returns it to the client.</li>



<li>The client fetches the S3 object using the presigned URL before it times out.</li>
</ol>



<p class="wp-block-paragraph">&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Externally-authenticated-access-to-S3-objects2.png" alt=""/></figure>



<p class="wp-block-paragraph">Notice how the file is requested directly from S3 in this setup! With that, we have a secure and performant solution.</p>



<p class="wp-block-paragraph">To see an example implementation of this design, see my follow-up post,&nbsp;<a href="https://static.dmcinfo.com/latest-thinking/blog/id/12643/embedding-private-media-files-securely-in-a-react-frontend-with-amazon-s3-and-aws-lambda">Embedding private media files securely in a React frontend with Amazon S3 and AWS Lambda</a>.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Control Access to Private S3 Content</strong></h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Explore our <a href="https://static.dmcinfo.com/services/application-development/" data-type="page" data-id="434">Application Development</a> expertise in Amazon S3, secure object delivery, and external authentication for protecting cloud-hosted files.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/16081/externally-authenticated-access-to-s3-objects-over-the-internet/">Externally Authenticated Access to S3 Objects Over the Internet</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Cloud Deployments in Minutes with Serverless Framework and AWS Lambda</title>
		<link>https://static.dmcinfo.com/blog/16084/cloud-deployments-in-minutes-with-serverless-framework-and-aws-lambda/</link>
		
		<dc:creator><![CDATA[Sam Wallace]]></dc:creator>
		<pubDate>Wed, 31 Jul 2024 16:07:35 +0000</pubDate>
				<category><![CDATA[Web Application Development]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/16084/cloud-deployments-in-minutes-with-serverless-framework-and-aws-lambda/</guid>

					<description><![CDATA[<p>Let&#8217;s say that you have a&#160;RESTful API deployed to some reserved compute resources in AWS. The API&#8217;s surface is well-designed and is perfectly capable of meeting all of the needs of any clients that consume it. But&#160;then, you&#8217;re told that there is some small internal feature or action that must be implemented in your&#160;cloud infrastructure. [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/16084/cloud-deployments-in-minutes-with-serverless-framework-and-aws-lambda/">Cloud Deployments in Minutes with Serverless Framework and AWS Lambda</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Let&#8217;s say that you have a&nbsp;RESTful API deployed to some reserved compute resources in AWS. The API&#8217;s surface is well-designed and is perfectly capable of meeting all of the needs of any clients that consume it. But&nbsp;then, you&#8217;re told that there is some small internal feature or action that must be implemented in your&nbsp;cloud infrastructure.</p>



<p class="wp-block-paragraph">For example,&nbsp;say you need to set up a service that sends an email containing data from the same data sources accessed by your API&nbsp;when triggered by an HTTP request. The API&#8217;s codebase could very easily be extended to provide this functionality, but doing so can lead to several&nbsp;types of tech debt.</p>



<ul class="wp-block-list">
<li><strong>Design &#8211;</strong>&nbsp;The API surface should abstract the complexities of data retrieval/syncing, so adding endpoints to manage this process goes against the design pattern.</li>



<li><strong>Security &#8211;</strong> If this is an external-facing API, you might run into serious security issues with allowing processes that consume your API to trigger such an action!</li>



<li><strong>Cost optimization &#8211; </strong>This is probably not a concern if your code just needs to send an email, but if&nbsp;you need to perform a more compute or memory intensive action, like a sync between two data sources. If this data sync is a very bursty workload, then running it on the same resources provisioned for nominal API usage may lead to surge pricing.</li>
</ul>



<p class="wp-block-paragraph">So, looks like you need a scheduled process within your cloud infrastructure that runs this operation separately from your API. This now seems like a lot more of an undertaking. The source code for this tiny task should be very quick to implement,&nbsp;but the overhead of provisioning, testing, deploying, and maintaining new resources dedicated for that&nbsp;task seems too high.</p>



<h2 id="h-serverless-functions-to-the-rescue" class="wp-block-heading">Serverless Functions to the Rescue!</h2>



<p class="wp-block-paragraph">Serverless functions like AWS Lambda (which is what we&#8217;ll focus on) are perfect for these kinds of actions. They&#8217;re quick and easy to develop and can cost almost nothing compared to reserved compute like EC2 for small tasks like sending an email or two.</p>



<p class="wp-block-paragraph">The code below is an example of an entire Lambda function implementation, minus any&nbsp;package dependencies. See how quickly these can be developed?</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
 
var AWS = require('aws-sdk');
AWS.config.update({region: 'us-west-2'});
var ses = new AWS.SES({apiVersion: '2010-12-01'});

exports.handler = async (event) => {
    var params = // email params
    try {
        var data = await ses.sendEmail(params).promise();
        return {
            statusCode: 200,
            body: JSON.stringify("Email sent! Message ID: " + data.MessageId),
        };
    } catch (error) {
        console.error(error);
        return {
            statusCode: 500,
            body: JSON.stringify("Error sending email: " + error.message),
        };
    }
};
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;aws-sdk&apos;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">update</span><span style="color: #D4D4D4">({</span><span style="color: #9CDCFE">region:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;us-west-2&apos;</span><span style="color: #D4D4D4">});</span></span>
<span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ses</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">SES</span><span style="color: #D4D4D4">({</span><span style="color: #9CDCFE">apiVersion:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;2010-12-01&apos;</span><span style="color: #D4D4D4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">handler</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">params</span><span style="color: #D4D4D4"> = </span><span style="color: #6A9955">// email params</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ses</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">sendEmail</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">params</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">promise</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">statusCode:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">200</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">body:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">stringify</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Email sent! Message ID: &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">MessageId</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">        };</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">error</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">statusCode:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">500</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">body:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">stringify</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Error sending email: &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">message</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">        };</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">But wait! What if a second data sync action needs to be added? A third? Serverless functions are great for implementing one-off features like this in a vacuum, but managing a whole flock of serverless functions with their own source code, their own VPC configurations, their own deployment processes, etc., can become an unmanageable mess very quickly.</p>



<h2 id="h-serverless-framework" class="wp-block-heading">Serverless Framework</h2>



<p class="wp-block-paragraph">The <a href="https://www.serverless.com/" target="_blank">Serverless Framework</a> package provides a suite of Infrastructure-as-Code&nbsp;capabilities built to allow you to&nbsp;deploy and configure&nbsp;one or more serverless functions defined within a single directory. This means that you can easily keep your functions&#8217; implementations and configurations all tracked within one repository!</p>



<p class="wp-block-paragraph">Let&#8217;s walk through the setup of a project using the serverless framework to show how simple it is.</p>



<h3 id="h-create-a-node-project-and-install-the-serverless-framework-package" class="wp-block-heading">Create a Node Project and Install the Serverless Framework Package</h3>



<p class="wp-block-paragraph">In your project directory, with your Unix shell of choice, run the following.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ShellScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
 
npm init
npm install serverless
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">init</span></span>
<span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">install</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">serverless</span></span>
<span class="line"></span></code></pre></div>



<h3 id="h-use-the-serverless-framework-cli-to-pick-the-project-template" class="wp-block-heading">Use the Serverless Framework CLI to Pick the Project Template</h3>



<p class="wp-block-paragraph">The CLI&nbsp;will provide a list of templates to choose from. For this post, we&#8217;re going to create a Lambda application targeting Node.js with an Amazon&nbsp;API Gateway integration for triggering our functions.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Bash</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
 
? What do you want to make?
  AWS - Node.js - Starter
> AWS - Node.js - HTTP API
  AWS - Node.js - Scheduled Task
  AWS - Node.js - SQS Worker
  AWS - Node.js - Express API
  AWS - Node.js - Express API with DynamoDB
  AWS - Python - Starter
  AWS - Python - HTTP API
  AWS - Python - Scheduled Task
  AWS - Python - SQS Worker
  AWS - Python - Flask API
  AWS - Python - Flask API with DynamoDB
  Other
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">? What </span><span style="color: #C586C0">do</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">you</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">want</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">to</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">make?</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Node.js</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Starter</span></span>
<span class="line"><span style="color: #D4D4D4">&gt; AWS - Node.js - HTTP API</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Node.js</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Scheduled</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Task</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Node.js</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">SQS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Worker</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Node.js</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Express</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">API</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Node.js</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Express</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">API</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">with</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">DynamoDB</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Python</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Starter</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Python</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">HTTP</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">API</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Python</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Scheduled</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Task</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Python</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">SQS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Worker</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Python</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Flask</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">API</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Python</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Flask</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">API</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">with</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">DynamoDB</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">Other</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Name the project once you&#8217;ve selected the template.&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Bash</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
 
? What do you want to make? AWS - Node.js - HTTP API
? What do you want to call this project? example-project
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">? What </span><span style="color: #C586C0">do</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">you</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">want</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">to</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">make?</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">AWS</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Node.js</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">-</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">HTTP</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">API</span></span>
<span class="line"><span style="color: #D4D4D4">? What </span><span style="color: #C586C0">do</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">you</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">want</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">to</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">call</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">this</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">project?</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">example-project</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">This should&nbsp;generate the following files in your Node project.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="196" height="211" src="https://static.dmcinfo.com/wp-content/uploads/2024/07/node-project-files.png" alt="" class="wp-image-36141"/></figure>



<p class="wp-block-paragraph">The configuration of each Lambda function and this gateway are all specified in the generated serverless.yaml file.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">YAML</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
 
service: example-project
frameworkVersion: '3'
provider:
  name: aws
  runtime: nodejs18.x
functions:
  api:
    handler: index.handler
    events:
      - httpApi:
          path: /
          method: get
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">service</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">example-project</span></span>
<span class="line"><span style="color: #569CD6">frameworkVersion</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&apos;3&apos;</span></span>
<span class="line"><span style="color: #569CD6">provider</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">name</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">aws</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">runtime</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">nodejs18.x</span></span>
<span class="line"><span style="color: #569CD6">functions</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">api</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">handler</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">index.handler</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">events</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #569CD6">httpApi</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">path</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">/</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">method</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">get</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">This config tells the API&nbsp;gateway to invoke our Lambda (referenced here as the auto-generated function name of <code>index.handler</code>, which matches the function code&#8217;s file name and export field) in a Node 18 runtime, whenever a GET request is sent to the API gateway. The auto-generated function (in ./index.js) looks like this.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
 
module.exports.handler = async (event) => {
  return {
    statusCode: 200,
    body: JSON.stringify(
      {
        message: "Go Serverless v3.0! Your function executed successfully!",
        input: event,
      },
      null,
      2
    ),
  };
};
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #4EC9B0">module</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">handler</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">statusCode:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">200</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">body:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">stringify</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">message:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Go Serverless v3.0! Your function executed successfully!&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">input:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      },</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #B5CEA8">2</span></span>
<span class="line"><span style="color: #D4D4D4">    ),</span></span>
<span class="line"><span style="color: #D4D4D4">  };</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span></code></pre></div>



<h3 id="h-creating-the-functions" class="wp-block-heading">Creating the Functions</h3>



<p class="wp-block-paragraph">Let&#8217;s update index.js to include both of our emailing functions.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
 
var AWS = require('aws-sdk');
AWS.config.update({region: 'us-west-2'});
var ses = new AWS.SES({apiVersion: '2010-12-01'});
const sendEmailAndReturnResponse = async (params) => {
  try {
      var data = await ses.sendEmail(params).promise();
      return {
          statusCode: 200,
          body:
    JSON.stringify("Email sent! Message ID: " + data.MessageId),
      };
  } catch (error) {
      console.error(error);
      return {
          statusCode: 500,
          body: JSON.stringify("Error sending email: " + error.message),
      };
  }
};
           
exports.mail1 = async (event) => {
    var params = getEmailParams1(event); // getEmailParams1 is a function that you'll define for your own system
    return sendEmailAndReturnResponse(params);
};
exports.mail2 = async (event) => {
    var params = getEmailParams2(event); // getEmailParams2 is a function that you'll define for your own system
    return sendEmailAndReturnResponse(params);
};
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;aws-sdk&apos;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">update</span><span style="color: #D4D4D4">({</span><span style="color: #9CDCFE">region:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;us-west-2&apos;</span><span style="color: #D4D4D4">});</span></span>
<span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ses</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">AWS</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">SES</span><span style="color: #D4D4D4">({</span><span style="color: #9CDCFE">apiVersion:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;2010-12-01&apos;</span><span style="color: #D4D4D4">});</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sendEmailAndReturnResponse</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">params</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ses</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">sendEmail</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">params</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">promise</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #9CDCFE">statusCode:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">200</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #9CDCFE">body:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">stringify</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Email sent! Message ID: &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">MessageId</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">      };</span></span>
<span class="line"><span style="color: #D4D4D4">  } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">error</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #9CDCFE">statusCode:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">500</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #9CDCFE">body:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">JSON</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">stringify</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Error sending email: &quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">message</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">      };</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"><span style="color: #D4D4D4">           </span></span>
<span class="line"><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">mail1</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">params</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">getEmailParams1</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">); </span><span style="color: #6A9955">// getEmailParams1 is a function that you&apos;ll define for your own system</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sendEmailAndReturnResponse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">params</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">mail2</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">params</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">getEmailParams2</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">); </span><span style="color: #6A9955">// getEmailParams2 is a function that you&apos;ll define for your own system</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sendEmailAndReturnResponse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">params</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span></code></pre></div>



<h3 id="h-configuring-the-functions" class="wp-block-heading">Configuring the Functions</h3>



<p class="wp-block-paragraph">Updates the serverless.yaml file to map both functions to&nbsp;POST requests sent to their endpoints, and to route the API gateway endpoints to each&nbsp;function&nbsp;correctly.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">YAML</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
 
service: example-project
frameworkVersion: '3'
provider:
  name: aws
  runtime: nodejs18.x
functions:
  api:
    handler: index.mail1
    events:
      - httpApi:
          path: /
          method: post
  api:
    handler: index.mail2
    events:
      - httpApi:
          path: /
          method: post
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">service</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">example-project</span></span>
<span class="line"><span style="color: #569CD6">frameworkVersion</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&apos;3&apos;</span></span>
<span class="line"><span style="color: #569CD6">provider</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">name</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">aws</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">runtime</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">nodejs18.x</span></span>
<span class="line"><span style="color: #569CD6">functions</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">api</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">handler</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">index.mail1</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">events</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #569CD6">httpApi</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">path</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">/</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">method</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">post</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">api</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">handler</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">index.mail2</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">events</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #569CD6">httpApi</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">path</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">/</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">method</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">post</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Enter your AWS account credentials, and both of your functions will be deployed to a new Lambda application for you!</p>



<h3 id="h-update-your-functions" class="wp-block-heading">Update Your Functions</h3>



<p class="wp-block-paragraph">Updates to the serverless.yaml or the function source code can be easily applied to the deployments by simply re-running the command above. Serverless Framework tracks the configuration of your functions with AWS CloudFormation, so it knows exactly what to update when changes have been pushed.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Deploy Serverless Cloud Functions in Minutes</strong></h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Check out our <a href="https://static.dmcinfo.com/services/application-development/" data-type="page" data-id="434">Application Development</a> capabilities for building scalable, cost-efficient <a href="https://static.dmcinfo.com/services/application-development/cloud-application-development/" data-type="page" data-id="710">cloud services</a> with AWS Lambda and Infrastructure as Code.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/16084/cloud-deployments-in-minutes-with-serverless-framework-and-aws-lambda/">Cloud Deployments in Minutes with Serverless Framework and AWS Lambda</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>3 Common Pitfalls of Theme Customization with Material UI </title>
		<link>https://static.dmcinfo.com/blog/17372/3-common-pitfalls-of-theme-customization-with-material-ui/</link>
		
		<dc:creator><![CDATA[Sam Wallace]]></dc:creator>
		<pubDate>Wed, 19 Jul 2023 13:14:15 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17372/3-common-pitfalls-of-theme-customization-with-material-ui/</guid>

					<description><![CDATA[<p>Material UI is a great tool for speeding up the development process of your React app. The library offers out-of-the-box React UI components with built-in properties that greatly simplify implementing the styling and interaction requirements of your product. Out-of-the-box UI rarely matches an application&#8217;s predetermined design alone, however. In these situations, we are required to [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17372/3-common-pitfalls-of-theme-customization-with-material-ui/">3 Common Pitfalls of Theme Customization with Material UI </a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Material UI is a great tool for speeding up the development process of your React app. The library offers out-of-the-box React UI components with built-in properties that greatly simplify implementing the styling and interaction requirements of your product. </p>



<p class="wp-block-paragraph">Out-of-the-box UI rarely matches an application&#8217;s predetermined design alone, however. In these situations, we are required to open these components and tinker with their CSS styles directly.</p>



<p class="wp-block-paragraph">Material UI offers extensive documentation for component styling and customization, but the actual process of reworking these styles can be confusing and frustrating. In this blog post, I hope to simplify this process by covering 3 common pitfalls when overriding Material UI styles.&nbsp;</p>



<p class="wp-block-paragraph">This post will exemplify these pitfalls by overriding styles on an MUI TextField component. The implementation of these examples can be found in this <a href="https://codesandbox.io/p/sandbox/brave-gauss-qb2mbs" data-type="link" data-id="https://codesandbox.io/p/sandbox/brave-gauss-qb2mbs" target="_blank" rel="noreferrer noopener">Code Sandbox</a>. The source code we will start off with is a single TextField component rendered to the page, with style overrides controlled with MUI’s built-in createTheme() function: </p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const theme = createTheme({
 components: {
   MuiInputBase: {
     styleOverrides: {
       root: {}
     }
   }
 }
});
export default function App() {
 return (
   
     
       
         }}
       />
     
   
 );
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">theme</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">createTheme</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">components:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #9CDCFE">MuiInputBase:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">styleOverrides:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">       </span><span style="color: #9CDCFE">root:</span><span style="color: #D4D4D4"> {}</span></span>
<span class="line"><span style="color: #D4D4D4">     }</span></span>
<span class="line"><span style="color: #D4D4D4">   }</span></span>
<span class="line"><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">default</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">App</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">   </span></span>
<span class="line"><span style="color: #D4D4D4">     </span></span>
<span class="line"><span style="color: #D4D4D4">       </span></span>
<span class="line"><span style="color: #D4D4D4">         }}</span></span>
<span class="line"><span style="color: #D4D4D4">       /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">     </span></span>
<span class="line"><span style="color: #D4D4D4">   </span></span>
<span class="line"><span style="color: #D4D4D4"> );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">With no overrides in place to begin, the rendered page looks like this:&nbsp;</p>



<p class="wp-block-paragraph">There are multiple approaches to&nbsp;specifying style overrides within your project, and you may require something different than what is provided in this&nbsp;demo. For more information on the different approaches for locating style overrides, check out the&nbsp;<a href="https://mui.com/material-ui/customization/how-to-customize/" rel="noreferrer noopener" target="_blank">MUI documentation.</a>&nbsp;&nbsp;</p>



<h2 id="h-part-1-materialui-slot-selectors-nbsp" class="wp-block-heading">Part 1: MaterialUI Slot Selectors&nbsp;</h2>



<p class="wp-block-paragraph">Style overrides are most commonly located in a “theme” object. This object designates custom styles to components&nbsp;and the “slots” that compose a given component. Each slot maps to a single HTML element rendered within the larger component.&nbsp;</p>



<p class="wp-block-paragraph">To add or override a style, we specify both the component and slot that we are targeting. The styles we specify are applied in a CSS class specific to that element. In the example below, we target the input element within an MUI TextField, which is accessed by the MUI component MuiInputBase and slot root:&nbsp;&nbsp;</p>


<pre class="”brush:pascal”">
const theme = createTheme({
  components: {
    MuiInputBase: {
      styleOverrides: {
        root: {
          color: &quot;green&quot;
        }
      }
    }
  }
});
</pre>


<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Material-UI-Screenshot-1.png" alt="Screenshot of code on a computer"/></figure>



<p class="wp-block-paragraph"><strong>Pitfall: Choosing the Wrong Slot&nbsp;</strong></p>



<p class="wp-block-paragraph">When we specify styles for a component, they may appear in the rendered CSS but not induce a visible change on the page. In this case, the slot you specified may not be the correct one to target. A good practice to prevent this issue is to determine where the styles you want to override are initially applied and ensure you specify those slots in your theme.&nbsp;</p>



<p class="wp-block-paragraph">For example,&nbsp;say that I am trying to both increase the width of the TextField border and remove the preset borderRadius. If I apply both updates to the MuiInputBase-root slot, I&nbsp;get the following result:&nbsp;</p>


<pre class="”brush:pascal”">
const theme = createTheme({
  components: {
    MuiOutlinedInput: {
      styleOverrides: {
        root: {
          borderWidth: 3,
          borderRadius: 0
        }
      }
    }
  }
});

</pre>


<figure class="wp-block-image size-full"><img decoding="async" width="267" height="81" src="https://static.dmcinfo.com/wp-content/uploads/2023/07/screenshot-of-rendered-page-2.png" alt="" class="wp-image-36156"/></figure>



<p class="wp-block-paragraph">As you can see, the border has been removed, but the box width remains the same. If I investigate the styling specified for each slot, I see that there is a default value of borderRadius specified for MuiOutlinedInput-root, but the default borderWidth set on MuiOutlinedInput-notchedOutline is still being applied:</p>



<p class="wp-block-paragraph">If I move this override to the correct slot, we can see the desired output:&nbsp;</p>


<pre class="”brush:pascal”">
const theme = createTheme({
  components: {
    MuiOutlinedInput: {
      styleOverrides: {
        root: {
          borderRadius: 0
        },
        notchedOutline:{
          borderWidth: 3
        }
      }
    }
  }
});
</pre>


<figure class="wp-block-image size-full"><img decoding="async" width="271" height="82" src="https://static.dmcinfo.com/wp-content/uploads/2023/07/screenshot-of-rendered-page-3.png" alt="" class="wp-image-36157"/></figure>



<h2 id="h-part-2-correct-mui-class-reference-syntax-nbsp" class="wp-block-heading">Part 2: Correct MUI Class Reference Syntax&nbsp;</h2>



<p class="wp-block-paragraph">Beyond the theme specification exemplified above, MUI theme overrides allow string keys that specify selectors, providing greater control over the styles applied.&nbsp;&nbsp;</p>



<p class="wp-block-paragraph">There are many features of this string notation, but two features are used most frequently:&nbsp;</p>



<ul class="wp-block-list">
<li>Specifying the component-slot names of a descendant MUI component (akin to CSS descendant combinators)&nbsp;</li>



<li>Specifying a state selector that applies styles to the component only if it is in a certain state (akin to CSS pseudo-classes)&nbsp;</li>
</ul>



<p class="wp-block-paragraph">An example of both can be seen below:&nbsp;</p>


<pre class="”brush:pascal”">const theme = createTheme({
 components: {
   MuiOutlinedInput: {
     styleOverrides: {
       root: {
         borderRadius: 0,
         "&amp;. MuiSvgIcon-root": {
           color: "rgb(100,100,100)"
         },
         "&amp;.Mui-focused": {
           backgroundColor: "rgb(220,240,250)",
         }
       },
       notchedOutline: {
         borderWidth: 3,
         borderColor: "black"
       }
     }
   }
 }
})
</pre>


<figure class="wp-block-image size-full"><img decoding="async" width="260" height="74" src="https://static.dmcinfo.com/wp-content/uploads/2023/07/screenshot-of-rendered-page-4.png" alt="" class="wp-image-36158"/></figure>



<p class="wp-block-paragraph">Here, we have added an adornment icon to the TextField, which has a default color of black (“rgb(0,0,0)”), but we can specify a selector for this MUI component and update its color to a dark gray (“rgb(220,240,250)”). Additionally, we can set the background color of the field whenever the field is in focus by specifying a background color in the state selector “.Mui-focused”.</p>



<h3 id="h-pitfall-string-selector-syntax" class="wp-block-heading">Pitfall: String Selector Syntax</h3>



<p class="wp-block-paragraph">These string-notation selectors are fantastic for adding a higher level of specificity to your overrides, but they also fall outside of the typing for MUI themes – every key with this notation is just a string. This means that applying styles to incorrectly formatted selectors will fail silently. Given the extensive feature set of these string selectors, consulting the MUI documentation on formatting is best for more complex cases. For simpler and more common cases like the one above, here is a quick tip that may save you some time:</p>



<ul class="wp-block-list">
<li>Descendant selectors follow the notation &#8220;&amp; .[Component]-[Slot]&#8221;. Note the space after the ampersand.&nbsp;&nbsp;</li>



<li>State selectors follow the notation &#8220;&amp;.[state]&#8221; with no space after the ampersand.&nbsp;</li>
</ul>



<p class="wp-block-paragraph">This small difference is due to how these strings are parsed into plain CSS selectors. Descendant components are implemented with descendant CSS combinators as mentioned above, which require&nbsp;a space. State selectors are simply appended to the existing component class name, so the space is not included. Failing to follow this format for either type of selector results in styles not being applied. Below, we can see that neither the background highlight nor the color modification of the adornment icon is applied when the format is incorrect.&nbsp;</p>


<pre class="”brush:pascal”">const theme = createTheme({
 components: {
   MuiOutlinedInput: {
     styleOverrides: {
       root: {
         borderRadius: 0,
         "&amp;. MuiSvgIcon-root": {
           color: "rgb(100,100,100)"
         },
         "&amp;.Mui-focused": {
           backgroundColor: "rgb(220,240,250)",
         }
       },
       notchedOutline: {
         borderWidth: 3,
         borderColor: "black"
       }
     }
   }
 }
});
</pre>


<figure class="wp-block-image size-full"><img decoding="async" width="286" height="81" src="https://static.dmcinfo.com/wp-content/uploads/2023/07/screenshot-of-rendered-page-5.png" alt="" class="wp-image-36159"/></figure>



<h2 id="h-part-3-selector-specificity-is-correct-nbsp" class="wp-block-heading">Part 3: Selector Specificity is Correct&nbsp;</h2>



<p class="wp-block-paragraph">The nested selector structure shown in the last two examples follows the same rule as applying classes to HTML elements: if two classes are applied to an element and one class has a more specific selector than the other, then the more specific class’s styles will be displayed with higher priority than the other.</p>



<p class="wp-block-paragraph">In MUI theme overrides, specificity is determined by matching slot selectors and state selectors, as well as any base CSS selector.&nbsp;</p>



<h3 id="h-pitfall-override-s-selector-is-still-not-a-higher-specificity-than-the-out-of-the-box-styling" class="wp-block-heading">Pitfall: Override&#8217;s selector is still not a higher specificity than the out-of-the-box styling</h3>



<p class="wp-block-paragraph">There are already many selectors in the default styles of an MUI component that are very specific to certain elements within it. If your style override does not appear and the default style is still applied, check the style&#8217;s specificity and try to match it to your overriding selector.&nbsp;</p>



<p class="wp-block-paragraph">I’ll demonstrate this by&nbsp;extending&nbsp;the example from the last two sections. If you look at the image from the last section, you&#8217;ll notice that our custom black border is not present when the text box is selected. The border becomes thinner, and the color changes to a darker blue.</p>



<p class="wp-block-paragraph">If we dig around the DOM a bit when the TextField component is in focus, we can see a default TextField style that is making this change with the help of the higher specificity of the “.Mui-focused” state selector:&nbsp;</p>



<p class="wp-block-paragraph">If we want to override the border color of the text field when it is in focus, we need to match the level of specificity from the selector of the default style:&nbsp;</p>


<pre class="”brush:pascal”">const theme = createTheme({
 components: {
   MuiOutlinedInput: {
     styleOverrides: {
       root: {
         borderRadius: 0,
         "&amp;. MuiSvgIcon-root": {
           color: "rgb(100,100,100)"
         },
         "&amp;.Mui-focused": {
           backgroundColor: "rgb(220,240,250)",
           "&amp; .MuiOutlinedInput-notchedOutline":{
             borderColor: "black"
           }
         }
       },
       notchedOutline: {
         borderWidth: 3,
         borderColor: "black"
       }
     }
   }
 }
});
</pre>


<p class="wp-block-paragraph">Now, if we look at the DOM and the resultant page, we see that the more specific default style has been successfully overridden:&nbsp;</p>



<p class="wp-block-paragraph">Another important consideration here is that the selectors must be nested in the right order to be successfully applied;&nbsp;if the .MUI-focused state selector is nested in MuiOutlinedInput-notchedOutline class selector, then the style would not apply.&nbsp;</p>



<h2 id="h-conclusion" class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">MUI’s default styles and style overrides provide a very high level of configurability to web developers, but opening their out-of-the-box solutions can be tricky. The pitfalls exemplified are not the only possible issues, but from my experience, keeping these common problems in mind will considerably reduce the time needed to debug your styles.&nbsp;</p>



<p class="wp-block-paragraph"><strong>Learn more about DMC’s&nbsp;<a href="https://static.dmcinfo.com/services/application-development/web-application-development">Web Application Development</a>&nbsp;services and&nbsp;<a href="https://static.dmcinfo.com/contact">contact us</a>&nbsp;for your next project.&nbsp;</strong></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17372/3-common-pitfalls-of-theme-customization-with-material-ui/">3 Common Pitfalls of Theme Customization with Material UI </a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
