<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Web Development | Andrii Shupta's Blog]]></title><description><![CDATA[Web Development | Andrii Shupta's Blog]]></description><link>https://blog.andriishupta.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 00:28:44 GMT</lastBuildDate><atom:link href="https://blog.andriishupta.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Connect Polkadot to a Next.js website with @polkadot/extension-dapp]]></title><description><![CDATA[🔗 Links

andriishupta/polkadot-extension-dapp-example | GitHub

polkadot-extension-dapp-example | Deployed on Vercel

Extension Docs

SubWallet

PolkaVerse | GitHub

Subtips | Github

🌴 My Links


📰 Published on

Hashnode 💻

Medium ✍️

DEV Commun...]]></description><link>https://blog.andriishupta.dev/connect-polkadot-to-a-nextjs-website-with-polkadotextension-dapp</link><guid isPermaLink="true">https://blog.andriishupta.dev/connect-polkadot-to-a-nextjs-website-with-polkadotextension-dapp</guid><category><![CDATA[polkadot]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Andrii Shupta]]></dc:creator><pubDate>Sat, 17 Dec 2022 09:32:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671216802800/kPlwyZuIA.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-links">🔗 Links</h2>
<ul>
<li><p><a target="_blank" href="https://github.com/andriishupta">andriishupta/polkadot-extension-dapp-example | GitHub</a></p>
</li>
<li><p><a target="_blank" href="https://polkadot-extension-dapp-example.vercel.app">polkadot-extension-dapp-example | Deployed on Vercel</a></p>
</li>
<li><p><a target="_blank" href="https://polkadot.js.org/docs/extension/">Extension Docs</a></p>
</li>
<li><p><a target="_blank" href="https://subwallet.app/">SubWallet</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/dappforce/polkaverse">PolkaVerse | GitHub</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/andriishupta/subtips-app">Subtips | Github</a></p>
</li>
<li><p>🌴 <a target="_blank" href="https://linktr.ee/andriishupta">My Links</a></p>
</li>
</ul>
<h2 id="heading-published-on">📰 Published on</h2>
<ul>
<li><p><a target="_blank" href="https://blog.andriishupta.dev">Hashnode 💻</a></p>
</li>
<li><p><a target="_blank" href="https://andriishupta.medium.com">Medium ✍️</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/andriishupta">DEV Community 👩‍💻👨‍💻</a></p>
</li>
</ul>
<h2 id="heading-intro">🤓 Intro</h2>
<p>As a developer, it's essential to understand the differences between various blockchain platforms to choose the right one for your needs. One key difference(as for me) is the availability of technical resources and tutorials for developers. Ethereum has many articles and tutorials demonstrating how to connect a wallet to a website, whereas there is less information available on Polkadot. This may make it easier for developers who are new to Ethereum to get started and learn how to build applications on the platform.</p>
<p>It's important for developers also to be familiar with Polkadot and how to build on its platform, as it has unique features and potential applications.</p>
<p>Developer Experience outside just documentation is quite important nowadays for the web3 community.</p>
<p>In this article, I will show an example of how to connect a <a target="_blank" href="https://subwallet.app">SubWallet</a>(that's what I have used) to a Next.js website.</p>
<h3 id="heading-technology">Technology</h3>
<p>On Ethereum, we have web3.js and ethers.js for connecting to a website and many different libraries built on top of it. For example, many projects I have seen use <a target="_blank" href="https://wagmi.sh/">wagmi</a> with React.js. It is just a blessing, such as it includes a full list of functionality that you need to have to interact with blockchain: "Connect Wallet" display ENS and balances information, sign messages, interact with contracts, and much more — all with caching, request deduplication, and persistence.</p>
<p>Polkadot has production-ready libraries and tools to work with blockchain, and one of them is <code>@polkadot/extension-dapp</code>. That's what we would use to "Connect Wallet".</p>
<h2 id="heading-coding">🧑‍💻 Coding</h2>
<p>We will use the default Next.js app, so nothing is new here. Check out <a target="_blank" href="https://nextjs.org/docs/getting-started">Getting Started</a> to remind yourself of Next.js.</p>
<p>The most crucial point with <code>@polkadot/extension-dapp</code> is that it needs a browser to run, so with Next.js, we need to render the "Connect" button only during Client-Side rendering. For that, we would use <a target="_blank" href="https://nextjs.org/docs/advanced-features/dynamic-import">dynamic import</a>.</p>
<p><a target="_blank" href="https://github.com/andriishupta/polkadot-extension-dapp-example/blob/main/pages/index.tsx">🔗 source code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671219047736/roqYOj1nM.png" alt="dynamic-import" /></p>
<p>On the Home page, we load our <code>Connect</code> component dynamically. Connect components are where all magic happens.</p>
<p><a target="_blank" href="https://github.com/andriishupta/polkadot-extension-dapp-example/blob/main/components/Connect.tsx">🔗 source code</a></p>
<p>Let's start with imports:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671219434237/F7sYcDbv7.png" alt="polkadot-imports" /></p>
<p><code>InjectedAccountWithMeta</code> is a type of account that we would get. I imported it for TypeScript.</p>
<p>Our main focus here is <code>web3Enable</code> and <code>web3Accounts</code> .</p>
<hr />
<p><em>I have used promise chaining down below, but if you prefer</em> <code>try-catch</code> <em>+</em> <code>async / await</code> <em>- go for it!</em></p>
<h3 id="heading-web3enable"><code>web3Enable</code></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671220325736/EwaKnQgKB.png" alt="web3Enable" /></p>
<p>The initial function is to call even to check if our browser has any wallets to work with. In case we don't have anything to work with, the extension shows it in the console, and we also should throw an error to show the user that he should use the browser with a valid Wallet.</p>
<h3 id="heading-web3accounts"><code>web3Accounts</code></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671220369395/4b-P1tlxU.png" alt="web3Accounts" /></p>
<p>Same with <code>web3Accounts</code> - it would load accounts connected or prompt you to connect to the website if you opened it for the first time - a very familiar experience for web3 users.</p>
<p>You could try out the flow on <a target="_blank" href="https://polkadot-extension-dapp-example.vercel.app">polkadot-extension-dapp-example | Deployed on Vercel</a>, and it looks like this:</p>
<p><em>Disclaimer: I have tried only when I have 1 wallet, but for a simple example, it should be enough.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671221534061/3pDnjuHRy.png" alt="connect" /></p>
<hr />
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671221517280/1GHs07_eH.png" alt="connecting" /></p>
<hr />
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671221545484/CTSIIHHEi.png" alt="hello" /></p>
<hr />
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671221550600/uNmesdOSX.png" alt="error" /></p>
<hr />
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671221556790/I5BoS4U2I.png" alt="logs" /></p>
<h2 id="heading-next-steps-and-more-examples">🧑‍🏫 Next steps and more examples</h2>
<p>With a connected wallet and available account, you can do everything you want: check out how to create and sign a transaction, show <code>&lt;Identicon/&gt;</code> and more:</p>
<p><a target="_blank" href="https://polkadot.js.org/docs">https://polkadot.js.org/docs</a></p>
<p>A more mature example using <code>@polkadot/api</code> , <code>@polkadot/ui-keyring</code> and more is <a target="_blank" href="https://github.com/dappforce/polkaverse">PolkaVerse</a>. It is a decentralized social network built on <a target="_blank" href="https://subsocial.network/">Subsocial</a> - "The Blockchain for Social Finance".</p>
<p>Also, I have another project where I tried to use Subsocial API - it is raw-raw-raw cause it was fine for me to connect to Subsocial API and Polkadot to experience how things work. Feel free to check it out: <a target="_blank" href="https://github.com/andriishupta/subtips-app">https://github.com/andriishupta/subtips-app</a></p>
<hr />
<hr />
<hr />
<p>Thanks for reading! 🙇</p>
]]></content:encoded></item><item><title><![CDATA[Simplify usage of Lens API with @use-lens and graphql-codegen]]></title><description><![CDATA[🔗 Links

andriishupta | Github
Use Lens | Github
Lens API
GraphQL Code Generator

📰 Published on

Hashnode 💻
Medium ✍️
DEV Community 👩‍💻👨‍💻

🤓 Intro
Recently, I have used Lens API to build some playground apps and noticed a repetitive task: I...]]></description><link>https://blog.andriishupta.dev/simplify-usage-of-lens-api-with-use-lens-and-graphql-codegen</link><guid isPermaLink="true">https://blog.andriishupta.dev/simplify-usage-of-lens-api-with-use-lens-and-graphql-codegen</guid><category><![CDATA[Web3]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[lensprotocol]]></category><category><![CDATA[GraphQL]]></category><dc:creator><![CDATA[Andrii Shupta]]></dc:creator><pubDate>Tue, 04 Oct 2022 11:05:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664822999895/TeLrwv8kv.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-links">🔗 Links</h2>
<ul>
<li><a target="_blank" href="https://github.com/andriishupta">andriishupta | Github</a></li>
<li><a target="_blank" href="https://github.com/use-lens/use-lens">Use Lens | Github</a></li>
<li><a target="_blank" href="https://docs.lens.xyz">Lens API</a></li>
<li><a target="_blank" href="https://the-guild.dev/graphql/codegen">GraphQL Code Generator</a></li>
</ul>
<h2 id="heading-published-on">📰 Published on</h2>
<ul>
<li><a target="_blank" href="https://blog.andriishupta.dev">Hashnode 💻</a></li>
<li><a target="_blank" href="https://andriishupta.medium.com">Medium ✍️</a></li>
<li><a target="_blank" href="https://dev.to/andriishupta">DEV Community 👩‍💻👨‍💻</a></li>
</ul>
<h2 id="heading-intro">🤓 Intro</h2>
<p>Recently, I have used Lens API to build some playground apps and noticed a repetitive task: I created Lens API Queries and Mutations for every project and used <a target="_blank" href="https://the-guild.dev/graphql/codegen">GraphQL Code Generator</a> to use React hooks with Apollo Client. </p>
<p>After 2nd time doing the same job, I decided to create a library for easier use of Lens API that would save me some time to do actual work.</p>
<p>I have never created open-source packages and thought it would be a great experience to do it, even if only I would use it 😅.</p>
<p>npm <a target="_blank" href="https://www.npmjs.com/org/use-lens">@use-lens</a> so far contains 2 packages - <em>CLI</em> and <em>react-apollo</em>. Later in this article, I will explain how to use them and when, and the same information could be found in the <a target="_blank" href="https://github.com/use-lens/use-lens/#-usage">repo's README.md</a>.
I will explain how I see the best use of <code>@use-lens/*</code> later in the article.</p>
<p>Also, I liked Lens Protocol so much that I have created Github Organization <a target="_blank" href="https://github.com/use-lens">Use Lens</a>, where I plan to develop and publish some tools, examples and apps working on top of Lens.</p>
<h3 id="heading-technology">Technology</h3>
<blockquote>
<p>Lens Protocol is a composable and decentralized social graph, ready for you to build on so you can focus on creating a great experience, not scaling your users.</p>
<p>Own your content. Own your social graph. Own your data.</p>
</blockquote>
<p>If you have read so far - you know what Lens API is and how to use it. If you are here to check out <code>@use-lens</code> or just to check how to generate GraphQL code - educate yourself of Lens Protocol and API here:</p>
<p>🌿 https://docs.lens.xyz.</p>
<p><a target="_blank" href="https://the-guild.dev/graphql/codegen">GraphQL Code Generator</a> - is a tool to build read-to-use code from your GraphQL schema and operations with a simple CLI with a lot of plugins for different frameworks: React, Next.js, Svelte, Vue with Apollo, URLQ and others - you name it.</p>
<h2 id="heading-how-to">🧑‍💻 How to</h2>
<h3 id="heading-generate-with-use-lensclihttpsgithubcomuse-lensuse-lenstreemainpackagescli">Generate with <a target="_blank" href="https://github.com/use-lens/use-lens/tree/main/packages/cli">@use-lens/cli</a></h3>
<pre><code class="lang-bash">npm install --save-dev @use-lens/cli
use-lens generate %PACKAGE%
</code></pre>
<p>with <code>npx</code></p>
<pre><code class="lang-bash">npx @use-lens/cli generate %PACKAGE%
</code></pre>
<p>This would copy essential files of Lens API to your repo and would run <code>graphql-codegen</code> to generate the code. By default, it would go to <code>src/lens-api/index.ts</code>.
From here, you could adjust <code>tsconfig.json</code> to use it with <code>@use-lens</code> shortening, so it would feel like a package usage. More on how to do it <a target="_blank" href="https://github.com/use-lens/use-lens/tree/main/packages/cli#optional-tsconfigs-paths">here</a>.</p>
<h3 id="heading-with-use-lens">With <code>@use-lens/*</code></h3>
<p>The simple <code>npm install --save @use-lens/%PACKAGE%</code> and use it as a regular package.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> {
  GlobalProtocolStatsDocument,
  GlobalProtocolStats <span class="hljs-keyword">as</span> GlobalProtocolStatsType,
  useGlobalProtocolStatsQuery,
  useGlobalProtocolStatsLazyQuery,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@use-lens/react-apollo'</span>
</code></pre>
<h3 id="heading-manual-graphql-code-generator">Manual GraphQL Code Generator</h3>
<p>The default approach is simple and could be followed by official docs <a target="_blank" href="https://the-guild.dev/graphql/codegen/docs/getting-started">here</a></p>
<p>On high-level:</p>
<ul>
<li>install <code>@graphql-codegen/cli</code></li>
<li>pick a plugin for your stack: for example, <a target="_blank" href="https://www.the-guild.dev/graphql/codegen/plugins/typescript/typescript-react-apollo">react-apollo</a> and install it</li>
<li>get your GraphQL Schema and Documents</li>
<li>create basic <code>codegen.yml</code> for <code>graphql-codegen</code></li>
<li>run <code>graphql-codegen</code></li>
</ul>
<p>In your <code>codegen.yml</code>, you should specify schema, documents, where to save, and with what:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">schema:</span> <span class="hljs-string">schema.graphql</span> <span class="hljs-comment"># full schema; could be HTTP link</span>
<span class="hljs-attr">documents:</span> <span class="hljs-string">documents.graphql</span> <span class="hljs-comment"># queries and mutations that you want to have</span>
<span class="hljs-attr">generates:</span>
  <span class="hljs-string">./src/my-api/index.ts:</span> <span class="hljs-comment"># where to save</span>
    <span class="hljs-attr">plugins:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">typescript</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">typescript-operations</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">typescript-react-apollo</span> <span class="hljs-comment"># stack that you are going to use</span>
</code></pre>
<h2 id="heading-caution">⚠️ CAUTION</h2>
<p>🌿 https://docs.lens.xyz/docs/introduction:</p>
<blockquote>
<p>This API is beta and not production complete yet, which means that we could change schemas and endpoints at any time without warning or notice to you. When this API is production ready, we will remove this beta warning and will endeavor to ensure that there are no changes going forward unless a major change to the protocol itself is required.</p>
</blockquote>
<p>Lens API is not production complete, and so is <code>@use-lens/*</code>. Please, keep this in mind when going to production.</p>
<h3 id="heading-recommended-use">Recommended use</h3>
<p>If you want to <strong>play with Lens API</strong> - don't hesitate and install some of the <code>@use-lens/*</code> packages - it will give you all you need to start.</p>
<p>If you want to <strong>have more control</strong> - use <code>@use-lens/cli</code> to generate code locally. This would copy essential files that a package contains and would run <code>graphql-codegen</code>.</p>
<p>You would be able to do more with <code>codegen.yml</code>.</p>
<h2 id="heading-react-with-apollo-client">👨‍🏫 React with Apollo Client</h2>
<p>For <code>@use-lens/react-apollo</code>, I have prepared an example of how to use it.</p>
<p>Check out the source code <a target="_blank" href="https://github.com/use-lens/use-lens/tree/main/examples/react-apollo">here</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664823332275/pzXJ82KMc.png" alt="use-lens-react-apollo-example.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664823349167/ch0TjFDaH.png" alt="use-lens-react-apollo-example-2.png" /></p>
<h2 id="heading-lens-api-documents">🤝 Lens API Documents</h2>
<p>The complete set of Lens API Documents has been taken from <a target="_blank" href="https://github.com/lens-protocol/api-examples">api-examples</a>, a repo of Lens Protocol that shows how to use Lens API.
The same (or similar) queries are given as examples in Lens API docs.</p>
<h2 id="heading-summary">📚 Summary</h2>
<p>If you would like to use Lens API to see what it is - simplify your developer experience by using <a target="_blank" href="https://github.com/use-lens/use-lens">@use-lens</a> or <a target="_blank" href="https://the-guild.dev/graphql/codegen">GraphQL Code Generator</a>.</p>
<p>Thanks for reading! 🙇</p>
]]></content:encoded></item><item><title><![CDATA[Create Lens Subgraph on The Graph Protocol]]></title><description><![CDATA[🔗 Links

github: andriishupta/thegraph-hello-world
subgraph: andriishupta/hello-world
TheGraph Documentation
Lens Documentation

📰 Published on

Personal blog 💻
Medium ✍️
DEV Community 👩‍💻👨‍💻

✨
Initially, I got familiar with TheGraph by contr...]]></description><link>https://blog.andriishupta.dev/create-lens-subgraph-on-the-graph-protocol</link><guid isPermaLink="true">https://blog.andriishupta.dev/create-lens-subgraph-on-the-graph-protocol</guid><category><![CDATA[#thegraph]]></category><category><![CDATA[lensprotocol]]></category><category><![CDATA[Blockchain]]></category><dc:creator><![CDATA[Andrii Shupta]]></dc:creator><pubDate>Fri, 26 Aug 2022 10:21:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661248130666/ib6LLAyJ6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-links">🔗 Links</h2>
<ul>
<li><a target="_blank" href="https://github.com/andriishupta/thegraph-hello-world">github: andriishupta/thegraph-hello-world</a></li>
<li><a target="_blank" href="https://thegraph.com/hosted-service/subgraph/andriishupta/hello-world">subgraph: andriishupta/hello-world</a></li>
<li><a target="_blank" href="https://thegraph.com/docs/en/developing/creating-a-subgraph/">TheGraph Documentation</a></li>
<li><a target="_blank" href="https://docs.lens.xyz/docs">Lens Documentation</a></li>
</ul>
<h2 id="heading-published-on">📰 Published on</h2>
<ul>
<li><a target="_blank" href="https://andriishupta.dev">Personal blog 💻</a></li>
<li><a target="_blank" href="https://andriishupta.medium.com">Medium ✍️</a></li>
<li><a target="_blank" href="https://dev.to/andriishupta">DEV Community 👩‍💻👨‍💻</a></li>
</ul>
<h2 id="heading-4pyo">✨</h2>
<p>Initially, I got familiar with TheGraph by contributing to <a target="_blank" href="https://twitter.com/developer_dao">DeveloperDAO</a> to a project that did the same - indexing Lens Protocol.
P.S. This tutorial is <strong>NOT</strong> copy-paste of <a target="_blank" href="https://github.com/Developer-DAO/Lens-Graph-Subgraph">existing code</a>, and I created a repository from scratch to understand the basics of TheGraph and how to start. I needed to develop my subgraph to test how events would be indexed.</p>
<h2 id="heading-decentralized-querying">🤓 Decentralized querying</h2>
<blockquote>
<p><a target="_blank" href="https://thegraph.com/en/">The Graph</a> is an indexing protocol for querying networks like Ethereum and IPFS. Anyone can build and publish open APIs, called subgraphs, making data easily accessible.</p>
</blockquote>
<p>Many different tools and APIs help us query blockchain data using centralized API like we used to with web2. My favourites are <a target="_blank" href="https://www.alchemy.com/">alchemy</a> and <a target="_blank" href="https://infura.io/">infura</a>.</p>
<p>But, if we want to go decentralized, we must use decentralized tools.</p>
<blockquote>
<p>All data is stored and processed on open networks with verifiable integrity. TheGraph makes querying this data fast, reliable, and secure.</p>
</blockquote>
<h3 id="heading-lens">Lens</h3>
<blockquote>
<p><a target="_blank" href="https://lens.xyz/">Lens Protocol</a> is a composable and decentralized social graph, ready for you to build on so you can focus on creating a great experience, not scaling your users.</p>
<p>Own your content.
Own your social graph.
Own your data.</p>
</blockquote>
<p>With <a target="_blank" href="https://docs.lens.xyz/docs">Lens API</a>, we could do everything we want with protocol, but it still includes the web2 principle and has a centralized database for different things built on top of Smart Contract data.</p>
<p>If we want to get actual blockchain data, we need to use a protocol like TheGraph.</p>
<p><em>Disclaimer: assumption about the centralized part of Lens API is based on the features that Smart Contract has not, for example: "likes" functionality.</em>
<em>I like Lens API very much and would count on it 99.9% of the time as a personal preference, balancing centralized vs. decentralized tooling</em>.</p>
<h2 id="heading-how-to-create-a-subgraph">👀 How to create a subgraph</h2>
<p><em>In this tutorial, I will give an example of creating a subgraph using <a target="_blank" href="https://thegraph.com/hosted-service">Hosted Service</a></em> - it will be closed in months. Still, there won't be a difference in coding approaches, just in how it is internally deployed. With the Hosted Service, it was easier to use for testing purposes.</p>
<h3 id="heading-graph-inithttpsthegraphcomdocsendeployinghosted-servicecreate-a-subgraph"><a target="_blank" href="https://thegraph.com/docs/en/deploying/hosted-service/#create-a-subgraph">graph init</a></h3>
<ul>
<li>install <a target="_blank" href="https://github.com/graphprotocol/graph-cli">graph-cli</a></li>
<li>run <code>graph init --product hosted-service</code></li>
<li>follow CLI steps where you need to add protocol, name, and contract address</li>
</ul>
<p>You will get a generated project. The main entry point is <strong>subgraph.yaml</strong>.
This is the finished version of my subgraph.</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/thegraph-hello-world/blob/main/subgraph.yaml">source code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661079983070/V0S4t9t0N.png" alt="lens-subgraph-yaml.png" /></p>
<p><em>You can read more on what is <a target="_blank" href="https://thegraph.com/docs/en/developing/creating-a-subgraph/#the-subgraph-manifest">subgraph manifest</a></em></p>
<h4 id="heading-source-block">source block</h4>
<p>Indicates from what address to index. Many contracts use <a target="_blank" href="https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies">Proxy Upgrade Pattern</a>, which helps to fix crucial bugs or update implementation. That is why I have added LensHub ABI(<a target="_blank" href="https://www.alchemy.com/overviews/what-is-an-abi-of-a-smart-contract-examples-and-usage">Application Binary Interface</a>) as source ABI and then changed the address to <a target="_blank" href="https://docs.lens.xyz/docs/deployed-contract-addresses">proxy</a>
<code>startBlock</code> - I chose some random block for testing purposes, so it won't start indexing from the start - it takes more time. Usually, this value is omitted or equals the Contract creation's block.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661248433035/o463or9Z9.png" alt="image.png" /></p>
<p>To get ABI, you can:</p>
<ul>
<li>Copy from Etherscan/Polygonscan whole <a target="_blank" href="https://polygonscan.com/address/0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d#code">Contract ABI</a></li>
<li>Go to <a target="_blank" href="https://remix.ethereum.org/">remix.ethereum.org</a>, copy the github project, and compile the contract</li>
</ul>
<p>I went with a 50/50 approach, such as Lens has <a target="_blank" href="https://github.com/lens-protocol/lens-protocol/blob/main/contracts/libraries/Events.sol"><code>Events.sol</code></a> library that is not compiled as part of the main contract.</p>
<h3 id="heading-graph-codegen"><code>graph codegen</code></h3>
<p>After proper setup, we can run code generation - we will get all types of code to work with.</p>
<p>✨ <a target="_blank" href="https://thegraph.com/docs/en/developing/creating-a-subgraph/">The Graph</a> has excellent documentation, so follow it and find all answers there. ✨ </p>
<h3 id="heading-mindset-shift">Mindset shift</h3>
<p>As a developer who worked with databases, I started to think linearly: entity created -&gt; entity updated. But events could be indexed from <code>startBlock</code> and in non-linear order in time, so even if we index the event like <code>handleProfileImageURISet</code>, we need to check if the entity existed previously(more in the code example).</p>
<p>To find more tips, TheGraph documentation has a section <a target="_blank" href="https://thegraph.com/docs/en/developing/creating-a-subgraph/#defining-entities">"defining entities"</a> - it entirely describes what you should think about when creating your schema.</p>
<blockquote>
<p>Before defining entities, it is important to take a step back and think about how your data is structured and linked.</p>
</blockquote>
<h3 id="heading-code">Code</h3>
<p>As we know - schema and how our data would be created is essential. Let's look at how I have added entity  definition:</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/thegraph-hello-world/blob/main/schema.graphql">source code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661504998223/ctziiwXlR.png" alt="lens-subgraph-schema.png" /></p>
<p><code>Profile</code> is the <code>@entity</code>, including default fields that I took from <a target="_blank" href="https://docs.lens.xyz/docs/events#profilecreated"><code>ProfileCreated</code></a> event and the <code>posts</code> field, which is an <a target="_blank" href="https://thegraph.com/docs/en/developing/creating-a-subgraph/#entity-relationships">entity relationship</a></p>
<p>In this case, it is a "One-To-Many" relationship with the usage of the <a target="_blank" href="https://thegraph.com/docs/en/developing/creating-a-subgraph/#reverse-lookups">Reverse Lookup</a> approach that TheGraph recommends us using.</p>
<blockquote>
<p>For one-to-many relationships, the relationship should always be stored on the 'one' side, and the 'many' side should always be derived. ... will result in dramatically better performance for both indexing and querying the subgraph...</p>
</blockquote>
<p><code>Post</code> is also an <code>@entity</code>. Both have an <code>ID</code>, which should be unique for the subgraph.</p>
<p>In <code>lens-hub.ts</code> are located functions that correspond to events we want to index.</p>
<h4 id="heading-handlecreated"><code>handle*Created</code></h4>
<p>As we see, even for a new Post, we check if Profile already exists or not. I discovered the error I got during subgraph deployment and indexing that was saying something like "profile cannot be null" when I just wanted to load Profile to Post.</p>
<p>TheGraph also supports the "merge" approach - this means that if we create a new instance of Profile and it already exists - it is okay cause the subgraph would try to merge fields. I wanted to be the more precise cause in the examples, and I saw that in every place where we wish to create something - we first check if it could be already created.</p>
<p>Example: I have created a Post, and the subgraph knows that Post should have a Profile. Profile event was way before Post, so we don't have a Profile, and we need to create it; even if you could think - "how a Post could be created without a Profile" - it couldn't, but the event about the Post we could get first to index.</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/thegraph-hello-world/blob/main/src/lens-hub.ts">source code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661508935773/R0tyemPmJ.png" alt="lens-subgraph-profile-created.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661507255597/V5NV1eIv_.png" alt="lens-subgraph-post-created.png" /></p>
<h2 id="heading-testing">✅ Testing</h2>
<p>To check out how it works, you could visit my <a target="_blank" href="https://thegraph.com/hosted-service/subgraph/andriishupta/hello-world">subgraph: andriishupta/hello-world</a>. It has a pre-defined "Test" query that will give you info for both Profiles and Posts. You could modify it to get more or less information in the query window.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661507764847/-3dgrvfq1.png" alt="lens-subgraph-example.png" /></p>
<h2 id="heading-8jzhw">🙇</h2>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[Generate Dummy Data in Strapi]]></title><description><![CDATA[🔗 Links

github: andriishupta/strapi-generate-seed-data
Strapi's video with a general idea of how to "Generate dummy data"

📰 Also published on

Medium
DEV Community 👩‍💻👨‍💻

🤓 Motivation
Strapi is powerful open-source headless CMS that helps p...]]></description><link>https://blog.andriishupta.dev/generate-dummy-data-in-strapi</link><guid isPermaLink="true">https://blog.andriishupta.dev/generate-dummy-data-in-strapi</guid><category><![CDATA[Node.js]]></category><category><![CDATA[Strapi]]></category><dc:creator><![CDATA[Andrii Shupta]]></dc:creator><pubDate>Tue, 16 Aug 2022 11:22:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660648819501/8OAvfpzXN.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-links">🔗 Links</h2>
<ul>
<li>github: <a target="_blank" href="https://github.com/andriishupta/strapi-generate-seed-data">andriishupta/strapi-generate-seed-data</a></li>
<li>Strapi's video with a general idea of how to <a target="_blank" href="https://strapi.io/video-library/generate-dummy-data-in-strapi">"Generate dummy data"</a></li>
</ul>
<h2 id="heading-also-published-on">📰 Also published on</h2>
<ul>
<li><a target="_blank" href="https://andriishupta.medium.com">Medium</a></li>
<li><a target="_blank" href="https://dev.to/andriishupta">DEV Community 👩‍💻👨‍💻</a></li>
</ul>
<h2 id="heading-motivation">🤓 Motivation</h2>
<p><a target="_blank" href="https://strapi.io/">Strapi</a> is powerful open-source headless CMS that helps projects control code customization with extensibility and, at the same time, don't worry about implementing a full-blown Content Management System on their own.</p>
<p>So, after you have set up your Strapi, you want to build Front-End on top of it. You hire front-end developers who are stuck: "Ye, I can query for data via REST and GraphQL, but what data should I see? Could I have an example?"</p>
<p>😬</p>
<p>To avoid this, we would generate example data upfront.</p>
<h2 id="heading-how-to-seed-data">🌱 How to seed data?</h2>
<h3 id="heading-generate-dummy-data">"Generate dummy data"</h3>
<p>There is the <a target="_blank" href="https://strapi.io/video-library/generate-dummy-data-in-strapi">video</a> in Strapi's Video-library that gave me a direction on how to do it.</p>
<p>The idea is simple:</p>
<ul>
<li>use <code>bootstrap</code> <a target="_blank" href="https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/functions.html#bootstrap">function</a></li>
<li>use <a target="_blank" href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service-api.html">Entity Service API</a> for interactions</li>
<li>generate dummy data with <a target="_blank" href="https://fakerjs.dev/">@faker-js/faker</a></li>
</ul>
<h3 id="heading-tip">Tip</h3>
<p>Your case 💯 would be more complicated, so don't forget that you could take almost everything from Strapi's <a target="_blank" href="https://github.com/strapi/strapi">source code</a>.</p>
<p>The flow:</p>
<ul>
<li>find a place on Strapi Admin you want to copy</li>
<li>check URL and Network(in developer's inspection) to understand what is called</li>
<li>find code(start with <em>controller</em>) that corresponds to that calls</li>
<li>enjoy</li>
</ul>
<h2 id="heading-code">🧑‍💻 Code</h2>
<p>We have a simple Todo application(duh) with a Todo collection and a Todo List as a page(single type) that we want to send to the front-end. Also, our Todos has media functionality, so we upload some.</p>
<p>In the bootstrap function, we check for the development environment and decide if we should run seeding or not. Seeding would automatically run on the very first application run(valid when a developer clones an existing repository) and could be re-run with <code>yarn seed</code> to force seed, which clears old and creates new data - <code>FORCE_APP_BOOTSTRAP_ONLY</code>.</p>
<p>🔗<a target="_blank" href="https://github.com/andriishupta/strapi-generate-seed-data/blob/main/src/index.ts#L19">source code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660647934023/_TWY3BT50.png" alt="image.png" /></p>
<h3 id="heading-collection-type">Collection Type</h3>
<p>To create a todo using Entity Service API, we need to call the <code>create</code> method with data that matches our entity. In the current example and during seeding, I have used "bulk promises" to run requests in parallel cause they are not dependent on each other.</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/strapi-generate-seed-data/blob/main/src/_seed/todo.ts#L24">source code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660646448222/2pW3OEmEF.png" alt="image.png" /></p>
<p>And using faker, we fill a todo like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660646542491/WIbJn2A5F.png" alt="image.png" /></p>
<h3 id="heading-single-type">Single Type</h3>
<p>Fulfilling the "Todo List page" is the same as Collection, but keep in mind that it could be only one entry all the time. Also, it contains a Todo relation, so we get five todos to fill it.</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/strapi-generate-seed-data/blob/main/src/_seed/todo-list-page.ts#L14">source code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660646967243/bpcRjZ9IC.png" alt="image.png" /></p>
<h3 id="heading-media-upload">Media Upload</h3>
<p>To attach media on a todo, we first need to upload that media and then link its id to the entity. Code has been copied from <a target="_blank" href="https://github.com/strapi/strapi/blob/master/packages/core/upload/server/controllers/admin-upload.js#L57">Strapi's source code</a>, modified, and I just created a helper function.</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/strapi-generate-seed-data/blob/main/src/_seed/helpers.ts#L52">source code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660647313850/I0_9vSLNj.png" alt="image.png" /></p>
<p>Example in Todo:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660647475450/MwMApc0zn.png" alt="image.png" /></p>
<h2 id="heading-results">✅ Results</h2>
<p>After opening the Admin panel, you will see generated data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660648131990/doM8KcSYp.png" alt="image.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660648140280/96QisGJqs.png" alt="image.png" /></p>
<h2 id="heading-4pyo">✨</h2>
<p>Initially, I implemented this for <a target="_blank" href="https://twitter.com/developer_dao">Developer DAO</a>'s website <a target="_blank" href="https://developerdao.com/">developerdao.com</a>. Original code is located <a target="_blank" href="https://github.com/Developer-DAO/cms">here</a>(archived and moved to monorepo).</p>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[Setup Supabase with Nest.js]]></title><description><![CDATA[❗️⚠️ Disclaimer
This article is created for Supabase v1 and seems not to work with v2 due to the depreciation of some auth methods. I will create a new article for v2 and leave it here. If you have already found a solution — let me know in the commen...]]></description><link>https://blog.andriishupta.dev/setup-supabase-with-nestjs</link><guid isPermaLink="true">https://blog.andriishupta.dev/setup-supabase-with-nestjs</guid><category><![CDATA[supabase]]></category><category><![CDATA[nestjs]]></category><category><![CDATA[JWT]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Andrii Shupta]]></dc:creator><pubDate>Mon, 11 Jul 2022 19:48:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657559134241/GHyZYoCnJ.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-disclaimer">❗️⚠️ Disclaimer</h3>
<p>This article is created for Supabase <strong>v1</strong> and seems not to work with <strong>v2</strong> due to the depreciation of some <strong>auth</strong> methods. I will create a new article for <strong>v2</strong> and leave it here. If you have already found a solution — let me know in the comments! Thanks!</p>
<h2 id="heading-my-expectations-from-you">🤓 My expectations from You</h2>
<ul>
<li><p>You know what the Supabase is</p>
</li>
<li><p>You know the Nest.js framework</p>
</li>
<li><p>You will google what is beyond this tutorial if needed</p>
</li>
</ul>
<h2 id="heading-my-use-case-for-using-supabase-in-nestjs">🤔 My use case for using Supabase in Nest.js</h2>
<p>I needed a polling mechanism that runs every 1 second and does some action. As Auth and DB, I have chosen to use Supabase cause I have seen some tutorials and wanted to try it out.</p>
<p>At first, I wanted to use Next.js and Functions to do those operations by Cron Jobs, but it happens to be that the minimal time frame for Cron Job by Github(as the most accessible Cron provider) is only every 5 minutes.</p>
<p>So I switched to the idea of a server(full) app with Nest.js. (want to deploy on <a target="_blank" href="https://www.heroku.com/">Heroku</a>)</p>
<h2 id="heading-how-to-use-supabase-and-nestjs">🧑‍💻 How to use Supabase and Nest.js</h2>
<p>There is one single example of how to use Supabase as Auth library for your Nest.js application, but:</p>
<ul>
<li><p>it didn't seem straightforward (actual implementation) to me, and I didn't want to use an external package</p>
</li>
<li><p>it doesn't work as I wanted - it didn't have Supabase Client exposed from within the lib</p>
</li>
</ul>
<p>*it is still a good entry if you have never used Passport and need an example - it helped me to understand what to do in my code, so thanks <strong>hiro1107</strong> :)</p>
<p>📑 examples: https://supabase.com/docs/guides/examples</p>
<p>🧑‍💻 Github: https://github.com/hiro1107/nestjs-supabase-auth</p>
<hr />
<p>So I have decided to implement my way for Auth and Client.</p>
<h3 id="heading-could-we-use-supabase-on-the-nodejs-back-end">Could we use Supabase on the Node.js back-end?</h3>
<p>In general, like Firebase, Supabase is a client-side tool that works from the client-side by providing the "anon" user with Row Level Security Policies, but it doesn't force us to use Supabase only on the client-side.</p>
<p><em>With some rules, we can freely leverage the power of Supabase in our Node.js Server.</em></p>
<h2 id="heading-supabase-basic-setup">🍴 Supabase basic setup</h2>
<p>There are a few key points that I want to mention before the code.</p>
<h3 id="heading-rls-policies">RLS Policies</h3>
<p>Enable it when you create tables</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657554076049/QgIUoZAJv.png" alt="Screenshot 2022-07-11 at 17.12.21.png" /></p>
<p>I recommend creating two by default:</p>
<ul>
<li><p>"anon" is rejected by default for ALL actions</p>
</li>
<li><p>ALL actions are only could be done by auth.uid(), if your app is "user-oriented"</p>
</li>
</ul>
<h3 id="heading-userid"><code>user_id</code></h3>
<p>To make your application work with previous policies, don't forget to create the <code>user_id</code> column on each table that you use: it should be NOT null auto-generated <code>auth.uid()</code> field, so in this way, Supabase will always append the correct user to a row.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657561814214/ZMU8JyAlM.png" alt="Screenshot 2022-07-11 at 17.14.39.png" /></p>
<p>You can bypass RLS with Service Keys if needed, but be careful.</p>
<h2 id="heading-nestjs-application">🐱 Nest.js application</h2>
<h3 id="heading-installs">Installs</h3>
<p>To make this work, we need to add a few libs in addition to Supabase:</p>
<pre><code class="lang-plaintext">npm i passport passport-jwt @nestjs/passport @supabase/supabase-js
</code></pre>
<p>passport - handles everything related to Auth, does it magic that we don't need to care about</p>
<p>passport-jwt - has a ready-to-use Strategy for JWT Auth</p>
<p>@nestjs/passport - Nest.js's module for Passport</p>
<h3 id="heading-how-jwt-auth-works-with-passport"><em>How JWT Auth works with Passport</em></h3>
<p>How JWT Auth works go beyond this article, but there are plenty of explanations for using Passport and passport-jwt in Nest.js. You can start by checking Nest.js's <a target="_blank" href="https://docs.nestjs.com/security/authentication">Authentication</a>.</p>
<p>What we need to know for our case: Supabase is JWT-based authorization, which handles everything on its side. On our side, we need to have the correct <code>SUPABASE_JWT_SECRET</code>, which is used to decode JWTs. (located in Settings -&gt; API)</p>
<h3 id="heading-supabase-folder">Supabase folder</h3>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/nestjs-supabase-setup/tree/main/src/common/supabase">Link</a> to folder</p>
<p>This is the main code you could copy to your code base, and it will just work. The module is a regular Nest.js module. Other files deserve a deeper look.</p>
<h3 id="heading-strategy">Strategy</h3>
<blockquote>
<p>Passport has a rich ecosystem of strategies that implement various authentication mechanisms. While simple in concept, the set of Passport strategies you can choose from is large and presents a lot of variety</p>
</blockquote>
<p>Such as Supabase is JWT, we will use a ready-to-use passport-jwt strategy that does all decoding and other things for us.</p>
<p>In this code, we extend PassportStrategy with JWT Strategy and pass config in the <code>super</code> call.</p>
<p><em>strange "extend"</em> <code>PassportStrategy(Strategy)</code> is TypeScript Mixins</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/nestjs-supabase-setup/blob/main/src/common/supabase/supabase.strategy.ts">source-code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657564434316/a84jr72fv.png" alt="strategy-code.png" /></p>
<h3 id="heading-guard">Guard</h3>
<p>With this guard, I have protected the whole application by providing <code>APP_GUARD</code> in app.module.ts - a global way of guarding. You could use <code>UseGuard</code> for routes that need to be protected.</p>
<p>Here we extend AuthGuard with the <code>jwt</code> strategy(this is how passport-jwt named Strategy under the hood). Easy.</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/nestjs-supabase-setup/blob/main/src/common/supabase/supabase.guard.ts">source-code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657564738631/MrgRplFV_.png" alt="guard-code.png" /></p>
<h3 id="heading-service-scoperequest">Service: <code>Scope.REQUEST</code></h3>
<p>This service will <code>createClient</code> for every request and <code>setAuth</code>, so we will have the correct user during all following service calls. Code implemented in "Singleton" manner so we will get the same instance in different places during the same request.</p>
<p>🔗 <a target="_blank" href="https://github.com/andriishupta/nestjs-supabase-setup/blob/main/src/common/supabase/supabase.ts">source-code</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657565661631/ABxIWlDt3.png" alt="service-code.png" /></p>
<p>Why?</p>
<p>Here comes an interesting part that happens with different libraries that hold client-side states:</p>
<p>If we use client-side libs that hold state per user, on server OR SSR apps like Next.js, we need to be careful with those, such as it could be that when we create an instance of a library, it could become available for everyone who calls server/SSR apps.</p>
<p>That is why it is essential to use <code>@Injectable({ scope: Scope.REQUEST })</code> so our Supabase <code>createClient</code> will be created per request, and we will set auth correctly.</p>
<p>Another example: <a target="_blank" href="https://react-query-v3.tanstack.com/guides/ssr#using-hydration">Next.js &amp; SSR with react-query</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657565211083/G5ikEv6lI.png" alt="image.png" /></p>
<p><em>Disclaimer: I haven't tested it for multiple users yet, but I am pretty sure about it.</em> I haven't found other ways to pass Auth with one Client in docs by appending <code>access_token</code> - only <code>setAuth</code> to Client directly.</p>
<p><em>Possible solution</em>: Supabase could tweak auth flow, where with a unique setup, we can pass users in each request. With the Passport, we have the user in <code>req.user</code> and can still access the Authorization header for <code>access_token</code>.</p>
<h2 id="heading-testing-with-postman">📭 Testing with Postman</h2>
<p>After everything is finished - let's try to call our server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657562698046/I5YlGpiD3.png" alt="Screenshot 2022-07-11 at 17.43.46.png" /></p>
<p>As expected, we get a 401 code - this is <em>passport.js</em> does it check for JWT in our <strong>SupabaseGuard</strong></p>
<p>Let's now get a valid <code>access_token</code> and repeat the call:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657563065129/Li2i-5hzv.png" alt="Screenshot 2022-07-11 at 21.10.20.png" /></p>
<p>💪 💪 💪</p>
<p><em>access token available after you log in with a user. In my case, I have just sent "Magic Link" and got</em> <code>acces_token</code> from the URL</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657562947768/MwsRyTLvd.png" alt="Screenshot 2022-07-11 at 21.08.01.png" /></p>
<h2 id="heading-summary-tldr">📋 Summary - TL;DR;</h2>
<ul>
<li><p>install required dependencies</p>
</li>
<li><p>copy <strong>supabase</strong> folder to your project</p>
</li>
<li><p>add 3 SUPABASE_* variables to .env</p>
</li>
<li><p>import <em>supabase.module</em>: in app.module / @Global() auth.module / etc.</p>
</li>
<li><p>provide global <code>APP_GUARD</code> or use it where you need it with <code>UseGuard</code></p>
</li>
<li><p>use <em>supabase.ts</em> in other services by <code>this.supabase.getClient()</code> for Supabase calls</p>
</li>
</ul>
<h3 id="heading-links">🔗 Links</h3>
<ul>
<li><p>Github: https://github.com/andriishupta/nestjs-supabase-setup</p>
</li>
<li><p>Nest.js's <a target="_blank" href="https://docs.nestjs.com/security/authentication">Authentication</a>, including JWT with Passport.js</p>
</li>
<li><p>How to use <a target="_blank" href="https://docs.nestjs.com/guards">Guards</a> in Nest.js</p>
</li>
<li><p>Supabase's Auth <a target="_blank" href="https://github.com/hiro1107/nestjs-supabase-auth">example app with Nest.js</a></p>
</li>
<li><p><a target="_blank" href="https://supabase.com/docs/reference">Supabase's docs</a></p>
</li>
<li><p>Link to <a target="_blank" href="https://blog.devgenius.io/setup-supabase-with-nest-js-85041b03ec3a">Medium's copy of the article</a></p>
</li>
</ul>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[Cross-Origin iframe communication with Window.postMessage]]></title><description><![CDATA[🤔 Why do we need cross-origin iframe communication?
Imagine that you need to integrate with the "3rd party service" that would be used as part of your application.
Both of your companies are just start-ups, and we don't have a complete variety of to...]]></description><link>https://blog.andriishupta.dev/cross-origin-iframe-communication-with-window-post-message</link><guid isPermaLink="true">https://blog.andriishupta.dev/cross-origin-iframe-communication-with-window-post-message</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Web API]]></category><category><![CDATA[CORS]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Andrii Shupta]]></dc:creator><pubDate>Wed, 13 Apr 2022 11:14:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649834031153/CwigGCExb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-why-do-we-need-cross-origin-iframe-communication">🤔 Why do we need cross-origin iframe communication?</h2>
<p>Imagine that you need to integrate with the "3rd party service" that would be used as part of your application.</p>
<p>Both of your companies are just start-ups, and we don't have a complete variety of tools that will make our lives easier, so we choose <code>iframe</code> as the first option. We <em>must</em> integrate what we have now for the beta version. After that, we will refactor the code and will use edge technologies, as our manager promised(😉)</p>
<p>Their app(as an example) could show private information, possibly, some real-time bank details / shipping / trading details, and only available after user authorization.</p>
<h3 id="heading-what-could-be-a-better-solution">🤓 What could be a better solution?</h3>
<p>The best version of integration(IMHO) would be to get a react library with components, hooks, utils, etc., that will do everything for us. For example, check out <a target="_blank" href="https://stripe.com/docs/stripe-js/react">React Stripe.js Components</a>. Second best - take an Open API(example <a target="_blank" href="https://stripe.com/docs/api">Stripe API</a>) and implement our own components.</p>
<h2 id="heading-what-are-we-going-to-build">🤨 What are we going to build?</h2>
<h4 id="heading-idea-summary">💭 Idea summary</h4>
<p>As the Parent app, we want to login within the <code>iframe</code> with some token, so the <code>iframe</code> could show relative information. Every N mins(5 secs in this case), our token would expire, and the <code>iframe</code> needs to request another. As a bonus, we can change a theme from <em>dark</em> to <em>light</em>, which could happen from both sides.</p>
<hr />
<p>Mostly I would list code that is only related to the <code>iframe</code> and <code>Web API</code> part and won't focus on things like an app creation or an explanation of <a target="_blank" href="https://nextjs.org/docs/deployment#managed-nextjs-with-vercel"><em>"how to deploy to Vercel"</em></a>.</p>
<p>The Parent and the Child apps would be our actual implementation of what we need. For the front-end, we are going to use <a target="_blank" href="https://nextjs.org/">Next.js</a> and <a target="_blank" href="https://chakra-ui.com/">Chakra-UI</a> for components. We would deploy apps on <a target="_blank" href="https://vercel.com/">Vercel</a> and <a target="_blank" href="https://www.netlify.com/">Netlify</a>(to be truly cross-origin).</p>
<p>Also, I would use <a target="_blank" href="https://nx.dev/">Nrwl Nx's workspaces</a> to have monorepo, keeping run/build processes seamless.</p>
<h2 id="heading-codeskip-to-this-if-you-dont-want-to-read-the-intro">👨‍💻 Code(skip to this if you don't want to read the Intro)</h2>
<h3 id="heading-the-communicator">🤖 "The Communicator."</h3>
<p>🔗 https://iframe-communicator.vercel.app</p>
<p>🔗 Github: https://github.com/andriishupta/iframe-communicator</p>
<p>It is a "special" app you could use for <strong><em>real-world testing</em></strong> to see how messaging works in your app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649836132954/aL1mxAEx2.png" alt="iframe-communicator.png" /></p>
<h3 id="heading-parent-code">🧑 Parent code</h3>
<p>🔗 <a target="_blank" href="https://cross-origin-iframe-communication-with-nextjs-parent-app.vercel.app/">link</a> to the deployed app</p>
<p>🔗 source code is available for copying <a target="_blank" href="https://github.com/andriishupta/cross-origin-iframe-communication-with-nextjs/blob/main/packages/parent-app/pages/index.tsx">here</a></p>
<p>As for the Parent app, we will surely have <code>iframe</code> rendered on our side. Let's start from it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649697283386/wFp1qPtVI.png" alt="iframe3.png" /></p>
<ul>
<li><strong>iframeRef</strong> is our <a target="_blank" href="https://reactjs.org/docs/hooks-reference.html#useref">React.js reference</a> to the DOM element, so we can later use it</li>
<li><em>onLoad</em> - this would send my initial token</li>
</ul>
<hr />
<p>Next: how we send the message is <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage">Window.postMessage</a></p>
<blockquote>
<p>The window.postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649697531158/kxbxc5-08.png" alt="post-message.png" /></p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> postMessage = <span class="hljs-function">(<span class="hljs-params">message: Message</span>) =&gt;</span> {
    iframeRef.current.contentWindow.postMessage(message, CHILD_APP_URL); <span class="hljs-comment">// OR use '*' to handle all origins</span>
};
</code></pre>
<p><code>postMessage</code> takes a <code>message: Message</code> as the argument - it is our own message <strong>kind</strong> that we selected and agreed with the Child app to pass through:</p>
<blockquote>
<p>The data is serialized using the structured clone algorithm. This means you can pass a broad variety of data objects safely to the destination window without having to serialize them yourself.</p>
</blockquote>
<hr />
<p>To send actual message we are using <code>iframeRef.current.contentWindow</code> as our <code>targetWindow</code>(from documentation) and the function's second parameter is <code>targetOrigin</code>:</p>
<blockquote>
<p>Specifies what the origin of targetWindow must be for the event to be dispatched, either as the literal string "*"</p>
</blockquote>
<p>I know my <code>targetOrigin</code>, so I am passing it and suggesting you not neglect <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#security_concerns">security risks</a>.</p>
<hr />
<p>Last but not least, we want to listen to messages from the Child!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649699194066/DDGLPL0bF.png" alt="listener.png" /></p>
<p>Security and filtering: we accept only our messages that we are sure in</p>
<pre><code><span class="hljs-comment">// skip other messages for security reasons and avoid extensions alerts in console</span>
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">event</span>.origin <span class="hljs-operator">!</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> CHILD_APP_URL) {
  <span class="hljs-keyword">return</span>;
}
</code></pre><p>Now, let's get the data from the <em>MessageEvent</em> and do some checks and act by business logic:</p>
<pre><code><span class="hljs-keyword">if</span> (message?.type <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'token-expired-from-child'</span>) {
  ...
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (message?.type <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'theme-from-child'</span>) {
  ...
} <span class="hljs-keyword">else</span> {
  <span class="hljs-comment">//  in case of some random message</span>
}
</code></pre><p><em>*for more options this code could be improved with switch/case(who likes), ternary operator, or object literals.</em></p>
<p>Finish up by adding a listener and return a callback for removal, so when a component goes down, you navigate to another page, where you don't need to listen for an <code>iframe</code>.</p>
<pre><code>window.addEventListener(<span class="hljs-string">'message'</span>, handler);
<span class="hljs-keyword">return</span> () <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> window.removeEventListener(<span class="hljs-string">'message'</span>, handler);
</code></pre><h3 id="heading-child-code">👶 Child code</h3>
<p>🔗 <a target="_blank" href="https://lustrous-donut-e3b29a.netlify.app">link</a> to the deployed app</p>
<p>🔗 source code is available for copying <a target="_blank" href="https://github.com/andriishupta/cross-origin-iframe-communication-with-nextjs/blob/main/packages/child-app/pages/index.tsx">here</a></p>
<p>The approach is the same for the Child app, with a twist of where to call <em>postMessage</em> - <code>window.parent</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649700352362/knHKl9veb.png" alt="child-post-message.png" /></p>
<hr />
<p>And listening to the messages differs in <code>type</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649700623627/-FeJDv7qp.png" alt="child-listener.png" /></p>
<h2 id="heading-links">🔗 Links</h2>
<p>🎨 Parent app: https://cross-origin-iframe-communication-with-nextjs-parent-app.vercel.app</p>
<p>👨‍💻 Github: https://github.com/andriishupta/cross-origin-iframe-communication-with-nextjs</p>
<hr />
<p>🤖 "The Communicator": https://iframe-communicator.vercel.app</p>
<p>👨‍💻 Github for "The Communicator": https://github.com/andriishupta/cross-origin-iframe-communication-with-nextjs</p>
<h2 id="heading-summary">📝 Summary</h2>
<p>Cross-Origin iframe communication could come in quite handy in specific situations, and we totally could take advantage of two-way messaging to make that even more dynamic. Check for yourself by clicking the examples.</p>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[Starting My Web3 Journey]]></title><description><![CDATA[Hello w3rld!
This article indicates my start of "web3" and the intention to change. I will work on different topics of web3 and try to describe my journey both from a development and personal experience.
The year 2021 started for me with several impo...]]></description><link>https://blog.andriishupta.dev/starting-my-web3-journey</link><guid isPermaLink="true">https://blog.andriishupta.dev/starting-my-web3-journey</guid><dc:creator><![CDATA[Andrii Shupta]]></dc:creator><pubDate>Sat, 01 Jan 2022 21:58:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/95YRwf6CNw8/upload/v1641074721064/oxLTuH2es.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-hello-w3rld">Hello w3rld!</h2>
<p>This article indicates my start of "web3" and the intention to <em>change</em>. I will work on different topics of web3 and try to describe my journey both from a development and personal experience.</p>
<p>The year 2021 started for me with several important things: I have finished renovation in my apartments, changed the company where I worked before. I couldn't even imagine that on March 18th, I would make my first deposit to the Binance and start <em>my journey in crypto</em> (which I would describe in my next article about <em>"how I got into the crypto world"</em>).</p>
<h2 id="heading-who-am-i">Who am I</h2>
<p>I am a Senior Full-Stack Engineer that just left his web2 job and wants to get into web3. By starting this blog and writing in general, I want to encourage myself to start my new chapter of life.</p>
<h2 id="heading-my-intentions">My intentions</h2>
<p>I want to begin it with writing articles, doing open-source, and of course to find my next adventure. My outlook was limited, and I didn't think before about serious this path. I gave some smirks on open-source, dev-twitter, crypto-twitter, and how a lot of ex-google/-facebook going in a different direction.</p>
<h2 id="heading-what-i-want-to-work-on">What I want to work on</h2>
<p>In January 2022, I want to start with something that is currently "mainstream":</p>
<ul>
<li><a target="_blank" href="https://twitter.com/_buildspace">@_buildspace</a></li>
<li><a target="_blank" href="https://twitter.com/thirdweb_">@thirdweb_</a></li>
<li><a target="_blank" href="https://twitter.com/solana">@solana</a> + <a target="_blank" href="https://www.rust-lang.org/">Rust language</a></li>
<li><a target="_blank" href="https://twitter.com/avalancheavax">@avalancheavax</a></li>
<li>...AND for base Solidity Smart Contract development(no links needed)</li>
</ul>
<p>I have already worked on some basic stuff with Rust, deployed locally some stuff tuts from <a target="_blank" href="https://github.com/scaffold-eth/scaffold-eth">scaffold-eth</a>, but it is not enough to get started with serious projects.</p>
<h2 id="heading-open-source">Open-source</h2>
<blockquote>
<p>Contributing to open source can be a rewarding way to learn, teach, and build experience in just about any skill you can imagine. - https://opensource.guide/how-to-contribute/</p>
</blockquote>
<p>Another thing that excites me is Open-Source development - I feel you bring your experience and proficiency to the world.</p>
<h2 id="heading-li4u">...</h2>
<p>I feel like 2022 would be the year of change for many software engineers who choose web3, and I hope it would be a breakthrough for me.</p>
<p>✌️</p>
]]></content:encoded></item></channel></rss>