<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Miro for Developers</title>
    <description>The latest articles on DEV Community by Miro for Developers (@mirodevelopers).</description>
    <link>https://dev.to/mirodevelopers</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7000%2F73a1d043-1590-452c-8cca-193d9ff5387d.png</url>
      <title>DEV Community: Miro for Developers</title>
      <link>https://dev.to/mirodevelopers</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mirodevelopers"/>
    <language>en</language>
    <item>
      <title>Bring visual collaboration to life with Postman and Miro APIs</title>
      <dc:creator>William Bishop</dc:creator>
      <pubDate>Wed, 30 Aug 2023 10:40:52 +0000</pubDate>
      <link>https://dev.to/mirodevelopers/bring-visual-collaboration-to-life-with-postman-and-miro-apis-435c</link>
      <guid>https://dev.to/mirodevelopers/bring-visual-collaboration-to-life-with-postman-and-miro-apis-435c</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="//https%3A%2F%2Fblog.postman.com%2Fbring-visual-collaboration-to-life-with-postman-and-miro-apis%2F"&gt;Postman blog&lt;/a&gt; on August 18th, 2023.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With the power of Postman, the options for dynamically creating content with third-party platforms and tools are seemingly endless. This was the inspiration for a recent &lt;a href="https://www.youtube.com/watch?v=gu9-kwi8Dns"&gt;Postman livestream&lt;/a&gt; exploring how we can leverage the &lt;a href="https://developers.miro.com/"&gt;Miro Developer Platform's&lt;/a&gt; REST APIs to create content on a Miro board - all from within Postman.&lt;/p&gt;

&lt;p&gt;Before diving into the details of how you can streamline your workflow with Postman and unlock new possibilities in Miro, let's start with a quick primer: what is visual collaboration in Miro? Well, simply put, it's a collection of connected activities that allow you to communicate and collaborate across formats, tools, channels, and time zones - without the constraints of physical location, meeting space, and whiteboards.&lt;/p&gt;

&lt;p&gt;The Miro Developer Platform allows you to extend the power of visual collaboration and interact with Miro boards via its &lt;a href="https://developers.miro.com/reference/api-reference"&gt;robust suite of REST APIs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JZNjnMni--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vifrst8g8q2ojhe1an6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JZNjnMni--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vifrst8g8q2ojhe1an6p.png" alt="Miro board with sticky notes and planning workflows" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;In order to use the Miro REST API with Postman, you’ll need to first make sure you have a Miro account and some developer credentials to generate an access_token. You can find all the necessary details to get started &lt;a href="https://developers.miro.com/docs/rest-api-build-your-first-hello-world-app"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Miro Postman Collection
&lt;/h3&gt;

&lt;p&gt;To make things even easier, you can leverage the &lt;a href="https://www.postman.com/miro-developer-platform/workspace/miro-developer-platform/collection/20467754-1a7d3514-f19f-4a86-9001-d694f160da3d"&gt;Miro Developer Platform public collection&lt;/a&gt; in Postman, which includes an authorization helper to make getting an access token a breeze. By simply entering any Miro endpoint into Postman, you’ll see an option to set up a new authorization method, providing a frictionless experience for accessing Miro’s APIs (more details on this awesome new helper &lt;a href="https://blog.postman.com/easier-api-authentication-in-postman/"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hwxv0r-7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68x79p62xse52oh8jd5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hwxv0r-7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68x79p62xse52oh8jd5f.png" alt="Authorization helper in Postman" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating sticky notes dynamically from Postman
&lt;/h2&gt;

&lt;p&gt;Once you’ve authorized and have your access_token saved to your Postman environment, you’re ready to make a request to the Miro API.&lt;/p&gt;

&lt;p&gt;But rather than just make a single request that, for instance, creates a sticky note on a Miro board, let’s take advantage of &lt;a href="https://learning.postman.com/docs/sending-requests/variables/"&gt;Postman variables&lt;/a&gt; and the &lt;a href="https://learning.postman.com/docs/collections/running-collections/intro-to-collection-runs/"&gt;Postman Collection Runner&lt;/a&gt; feature to automate a number of requests, using some content from outside of Postman.&lt;/p&gt;

&lt;p&gt;To do this, we can navigate to the Sticky Notes folder in the Miro Developer Platform collection, and leverage the &lt;a href="https://developers.miro.com/reference/create-sticky-note-item"&gt;Create Sticky Note Item&lt;/a&gt; endpoint. Navigate to the &lt;strong&gt;Body&lt;/strong&gt; tab in Postman, and you’ll see some JSON already populated for the body of the request. For the content field in the request body, we can create a new environment variable—&lt;code&gt;{{content}}&lt;/code&gt;. We can do the same for the x, y fields in the position object—&lt;code&gt;{{x}}&lt;/code&gt; and &lt;code&gt;{{y}}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, in the request URL, we will need to pass the ID of a Miro board under the team we authorized when we set up our authorization initially. If there aren’t any boards, simply create a new one from the Miro dashboard.&lt;/p&gt;

&lt;p&gt;Hit &lt;strong&gt;Save&lt;/strong&gt; and let’s populate these variables from some content outside of Postman.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K_l8HRuY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1mqbv9l1vd1ojmf3aw2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K_l8HRuY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1mqbv9l1vd1ojmf3aw2q.png" alt="Miro REST API request in Postman" width="800" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate sticky notes from CSV file
&lt;/h2&gt;

&lt;p&gt;To start, we’ll need a .csv file that we can work with. Let’s create a basic .csv file where the first line is our header, and the following lines are the content and coordinates that we will feed into our requests in Postman to create sticky notes via the Miro API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--12JpN7vA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/53fphn3tujsi90f2drdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--12JpN7vA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/53fphn3tujsi90f2drdk.png" alt="CSV content for import from file to Postman variables" width="790" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we’ve got our .csv file set up, we can use the Postman Collection Runner to select the request we’ve already set up for the &lt;a href="https://developers.miro.com/reference/create-sticky-note-item"&gt;Create sticky note item&lt;/a&gt; endpoint and choose a number of iterations. We’ll do just a few iterations, and select the .csv file we created for the Data File Type. Hit &lt;strong&gt;Run Miro Developer Platform&lt;/strong&gt; and go to the Miro board you specified in the &lt;em&gt;Create sticky note item&lt;/em&gt; request earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X7ammi4P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/388w7pielase1gxg96ph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X7ammi4P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/388w7pielase1gxg96ph.png" alt="Sticky notes generated via CSV in Miro" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Voila!&lt;/em&gt; We can see our new stickies being generated from our .csv file as the Postman Collection Runner initiates.&lt;/p&gt;

&lt;p&gt;While this is a simple example, you can imagine how many possibilities there are to combine the power of Postman and Miro to generate and manipulate content on a Miro board! But don't just take my word for it - you can take it even further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expand your workflow with Postman Flows and Miro
&lt;/h2&gt;

&lt;p&gt;Interested in exploring further automation? Check out how we leveraged &lt;a href="https://learning.postman.com/docs/postman-flows/gs/flows-overview/"&gt;Postman Flows&lt;/a&gt; to add some more complexity to our variables and inputs in an effort to create even more dynamic workflows between Postman and Miro.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gu9-kwi8Dns"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  That's a wrap!
&lt;/h2&gt;

&lt;p&gt;In addition to the capabilities we demonstrated here, there's so much more you can do with Postman and the &lt;a href="https://developers.miro.com/"&gt;Miro Developer Platform&lt;/a&gt;. Want to keep going? You can also build applications with Miro's &lt;a href="https://developers.miro.com/docs/miro-web-sdk-introduction"&gt;Web SDK&lt;/a&gt; for a frontend experience directly on a Miro board, and use Miro's &lt;a href="https://developers.miro.com/reference/api-reference"&gt;REST API&lt;/a&gt; for authorization and further automation.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://blog.postman.com/bring-visual-collaboration-to-life-with-postman-and-miro-apis/"&gt;Postman blog&lt;/a&gt; on August 18th, 2023.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>postman</category>
      <category>restapi</category>
      <category>miro</category>
      <category>integration</category>
    </item>
    <item>
      <title>How the Miro Developer Platform leverages contract testing</title>
      <dc:creator>Elena de Graaf</dc:creator>
      <pubDate>Mon, 15 May 2023 16:12:29 +0000</pubDate>
      <link>https://dev.to/mirodevelopers/how-the-miro-developer-platform-leverages-contract-testing-5416</link>
      <guid>https://dev.to/mirodevelopers/how-the-miro-developer-platform-leverages-contract-testing-5416</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Design-first approach at Miro&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developers.miro.com/" rel="noopener noreferrer"&gt;Miro Developer Platform 2.0&lt;/a&gt; was launched last year, and since then we’ve been working on improving the quality and consistency of our REST API. To achieve this, we decided to embrace a design-first approach. For us, it meant designing the API before actually implementing it, and making sure that the quality was high during the whole development process.&lt;/p&gt;

&lt;p&gt;This meant we needed an efficient way to verify compliance between the API and its description in OAS (&lt;a href="https://www.openapis.org/" rel="noopener noreferrer"&gt;OpenAPI Specification&lt;/a&gt;) files.&lt;/p&gt;

&lt;p&gt;In this post, I’ll share why we landed on contract testing as the solution. Contract testing is a fast, lightweight form of API testing that ensures two separate services are compatible and can communicate with each other by checking the consistency with a set of rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Switching from code generation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Previously, we generated OAS files from the code, using annotations on controllers and models. At the time, this allowed us to transition from writing the documentation manually to some degree of automation. However, the solution was hacky and required us to jump through a lot of hoops to generate the OAS files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;Operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nx"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Get specific connector"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Retrieves information for a specific connector on a board."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="nx"&gt;ApiResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="nx"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Connector retrieved"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
               &lt;span class="nx"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="na"&gt;ConnectorWithLinks&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
           &lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;],&lt;/span&gt;
   &lt;span class="nx"&gt;operationId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"get-connector"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;fun&lt;/span&gt; &lt;span class="nx"&gt;getConnectorById&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The early version of the API was not designed according to &lt;a href="https://swagger.io/specification/" rel="noopener noreferrer"&gt;OpenAPI standards&lt;/a&gt; and had problems like conflicting endpoints and overly complex models. The main components of the design-first approach were quite difficult to implement, so we decided to switch the source of truth from the code-generated OAS files to permanent, curated ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How do we keep it in sync?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;However, switching the source of truth presented a new problem. When the OAS files were generated from the code, we could at least partially guarantee that we were serving what we were promising. For example, the endpoint description could not have been generated if it didn’t exist in the code. Now, there was no way to tell if the OAS file had the paths and schemas that actually existed.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Looking for a solution&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Of course, we have end-to-end tests. Why not reuse them to verify that the API looks as expected? They cover the functionality anyway, so why not add a little schema validation to the mix?&lt;/p&gt;

&lt;p&gt;This idea is great, but it has the same flaw as the previous situation — it’s based on trust and leaves room for human error: New endpoint, but tests are not added? New parameter added, but tests are not updated because it’s out of critical path? The whole new experimental API appeared with no new tests and no intention to write them yet?&lt;/p&gt;

&lt;p&gt;Writing a set of tests just to verify the compliance between the API and its description in OAS seemed even more far-fetched — not only did it have the same flaws, but it would also require us to do the same work all over again.&lt;/p&gt;

&lt;p&gt;And this is how we arrived at the idea of generating tests from the OAS file.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How can a test be generated?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Our OAS has all the necessary data to successfully generate a request and validate the schema of the response. The request body can be built from schemas and the provided example/default values. If we don’t go into the details (and we don’t just yet), the logic for one resource is pretty easy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;First, find the endpoint that creates the resource (for example, the widget).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the id from the response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Re-use it in all other endpoints (get widget by id, update widget).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find the endpoint to delete it and execute it last.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdsbkjsf9sav0l1shlpk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdsbkjsf9sav0l1shlpk.png" alt="Image description" width="800" height="523"&gt;&lt;/a&gt;    &lt;/p&gt;

&lt;p&gt;But the devil is in the details, and the most pressing questions would be: What if it’s more than one resource? How do we guarantee that, say, the widget is created before the board is deleted?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Level-method model&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At this point we cared about two things: the method (POST should go first, DELETE — last) and the order of resource creation (boards before widgets). It may seem to have a simple solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24fqn8p0xe8l6xp00why.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24fqn8p0xe8l6xp00why.png" alt="Image description" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can easily identify the endpoints that create/delete the resources by method; that’s the first point of comparison. When we look at the path, we see that some resources appear before others. By naming them resource 1 and resource 2 (3, 4 or however far the craziness can get us), we get the second point. Then we only have to sort in the form of an arrow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxr4bbav2rjcwmw13q2o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxr4bbav2rjcwmw13q2o.png" alt="Image description" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This idea was simple, easy to understand, and worked great as a proof of concept, but it introduced more problems than it solved, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Representing the order in a simple manner possible with two levels of resources, worsens with three levels, and becomes not maintainable after it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not all POST endpoints create resources. For example, attaching a tag to the item is also a POST endpoint, but it has to happen after both items and tags are created.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding additional order — for example, if the endpoint has &lt;strong&gt;parent_item_id&lt;/strong&gt;, it has to be created after a frame is created — seems impossible without blowing up the complexity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We needed a more powerful way of sorting the relationships between endpoints, and that led us to a dependency graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Dependency graph&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Who would have thought to represent dependencies with a graph, right? In any case, it seemed like a very plausible solution: A directed graph can handle relationships of any complexity. It’s very clear what should be executed first. And there’s no need to rely on strict pre-defined ordering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccgjzvub189i73ujlt3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccgjzvub189i73ujlt3y.png" alt="Image description" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But how do we build a graph? Do we take the very first endpoint and put it in the graph, then take the next one and try to determine its relationship with the first node? That might work — and guarantee that the board is not deleted before we’re done with widgets on it. But at some point this approach would require traversing the entire graph to figure out the relationships with all other nodes. Despite the fact that we’ll never have that amount of endpoints for it to become a real performance problem, it does not help with the complexity, so we probably need another approach.&lt;/p&gt;

&lt;p&gt;Luckily, the level-method ordering approach highlighted not just the problems, but also the way we can use components of the url to determine the relationships. So instead of trying to fit the endpoint into the graph, we’re going to build the graph around it based on what this particular endpoint needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Walkthrough&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s take a simple endpoint: add a tag to an item. By looking at the endpoint, we can see that before it can be executed, we need to have a board, an item, and a tag already created. We’re going to have a special kind of node — “creational” nodes — and will create a lot of “empty” nodes like this. They can be populated with an actual url template when we get to it, but the node needs to exist before, so it can be used as a dependency.&lt;/p&gt;

&lt;p&gt;What are the steps to building a dependency graph for this endpoint?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a graph node for current operation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the node creates the resource, save it to the map of resources and their corresponding creation nodes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For each required parameter or resource in the api path:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Find the node that knows how to create the required resource from the map above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;…or create an empty node that will be populated when the creation operation is parsed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add a dependency on it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What if the endpoint deletes the resource entirely? Instead of adding extra complexity to the algorithm, we save them separately, in a “cleanup queue.”&lt;/p&gt;

&lt;p&gt;Now we have a graph of all the endpoints, plus a cleanup queue with delete endpoints sorted by the level of the resource being deleted. To test all the endpoints as parameters in the test, we need to put them in a simple sorted list. The initial idea was to use a graph and modified topological search, but with the graph construction that we use, the sorting is simplified to a BFS plus polling the cleanup queue in the end.&lt;/p&gt;

&lt;p&gt;As you may have noticed in the above example, an endpoint node can have a dependency on more than one other node, for example, both tags and items. And they, in return, can depend on multiple other nodes. The simple BFS will create duplicates at best, and unexpected ordering in the worst-case scenario. Plus, even duplicates can be detrimental: A second tag is created with the same example value provided in OAS, and this request ends with 400 because duplicated tags are not allowed.&lt;/p&gt;

&lt;p&gt;The solution for this, however, would be simple: If some node meets a child with more than one parent, it ignores it and detaches itself from a child, leaving nodes that appear later to take care of. This is the cruel reality of child care in computer science.&lt;/p&gt;

&lt;p&gt;Of course, there are still some limitations to what can possibly be automated. Here are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If the resource cannot be created via API (e.g. organizations for enterprise API), it has to be created before the test runs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the endpoint has a parameter (e.g. &lt;strong&gt;tag_id&lt;/strong&gt; or &lt;strong&gt;parent_item_id&lt;/strong&gt; or &lt;strong&gt;parent_id&lt;/strong&gt;), you need to map it to some resource first (e.g. &lt;strong&gt;tag_id&lt;/strong&gt; to &lt;strong&gt;tags&lt;/strong&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Likewise, if another resource is mentioned in the request body, it has to be created (e.g. widgets for connectors) or mapped to an existing resource.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Customizations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The whole solution consists of 4 parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The OAS files describing the Miro API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test generation logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creation of the components that can be generated automatically&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The tests themselves&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Plugins&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The test generation logic is a separate library that only needs to change when a new feature is required for all test suites, for example, when we decide to also make requests with missing required parameters to test error responses. All custom modifications, including providing new OAS files, have to go through plugins.&lt;/p&gt;

&lt;p&gt;Plugins offer a set of customizations to the owner of the API. For example, mapping resources to parameters, or retrying logic for some endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Other types of tests&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The initial set of tests contained only positive tests that check that a successful response is returned and the response schema is exactly as it is described in the OAS file. However, there are a number of possibilities to create other types of tests, from the already mentioned missing required parameter checks, to testing the expected error responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Automation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The tool is as good as its automation, so the API testing tool is scheduled to run frequently and to notify the team about the results. This solution also unlocked not just publishing the documentation automatically right after the change, but also preparing OAS files, for example, removing endpoints marked as drafts.&lt;/p&gt;

&lt;p&gt;There you have it. With OAS contract testing, we can verify compliance between the API and its description in OAS files.&lt;/p&gt;

&lt;p&gt;Do you have ideas or a different approach to API testing? Let us know in the comments — we’re interested in what you have to say!&lt;/p&gt;

&lt;p&gt;Are you interested in joining our team? Then check out our &lt;a href="https://miro.com/careers/open-positions/" rel="noopener noreferrer"&gt;open positions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, don’t forget to &lt;a href="https://developers.miro.com/" rel="noopener noreferrer"&gt;try the Miro Developer Platform&lt;/a&gt; for yourself.&lt;/p&gt;

</description>
      <category>openapi</category>
      <category>oas</category>
      <category>api</category>
      <category>testing</category>
    </item>
    <item>
      <title>Harnessing the power of React Server Components + Miro in NextJS</title>
      <dc:creator>William Bishop</dc:creator>
      <pubDate>Tue, 04 Oct 2022 12:49:58 +0000</pubDate>
      <link>https://dev.to/mirodevelopers/harnessing-the-power-of-react-server-components-miro-3h50</link>
      <guid>https://dev.to/mirodevelopers/harnessing-the-power-of-react-server-components-miro-3h50</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was updated October 2023 to reflect the latest React Server Component capabilities.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  An in-depth look at React Server Components and how you can take advantage of this now stable feature using our NextJS starter app.
&lt;/h3&gt;

&lt;p&gt;With the introduction of React 18 in 2022, React Server Components (RSC) were initially introduced as an experimental feature. Since then, they've matured into a stable capability with a lot of great benefits. Follow along as we explore the basics of what React Server Components are, how to effectively build them in the context of our NextJS sample app, and what to expect from RSC in the near future as the capability continues to evolve!&lt;/p&gt;

&lt;p&gt;We’ll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Benefits and limitations of RSC&lt;/li&gt;
&lt;li&gt;Quickstart: Writing a React Server Component&lt;/li&gt;
&lt;li&gt;Current and future state of RSC&lt;/li&gt;
&lt;li&gt;RSC x Miro (explore our sample app!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  React Server Components: Why use them?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmattfeeohjeot4bipxxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmattfeeohjeot4bipxxl.png" alt="Side-by-side comparison of frontend bundle size when leveraging MomentJS with RSC" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s a reason that React has invested time and resources developing React Server Components (and partnered with Vercel/NextJS): they’re efficient, in-demand by developers, and offer simple ways to improve the overall performance of any dependency-heavy application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html"&gt;React Server Components&lt;/a&gt; render server-side first. By rendering React components server-side first, it means we can enjoy each of the benefits below. 🤓&lt;/p&gt;

&lt;h4&gt;
  
  
  Improved performance
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Reduce the load time for apps with big bundles&lt;/li&gt;
&lt;li&gt;Since RSC are not included in the app bundle, they don’t contribute to its size, meaning smaller bundles and apps overall (see the MomentJS example above)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Direct access to your backend
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;RSC allow direct access to your backend and database, enabling fast data fetching&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  More dynamic than standard server side rendering
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;RSC can be re-fetched multiple times to re-render data (unlike traditional server side rendering, which typically happens once—on initialization)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Use them alongside client and shared components
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can use a mix of client side and server side components (denoted by their extension), as needed. &lt;a href="https://shopify.dev/custom-storefronts/hydrogen/framework/react-server-components"&gt;Shopify&lt;/a&gt; does a great job of visualizing this:
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hcdk279mtzc30malv2m.png" alt="Shopify Graphic" width="800" height="454"&gt;
(Source: Shopify, Custom Storefronts / Hydrogen / Framework / RSC)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As with any newer capability, there are going to be aspects that are continuing to evolve, or perhaps some unanswered questions about which direction things are headed in the future. We’ll call out what we &lt;strong&gt;do&lt;/strong&gt; know later on, but it’s a good time to be explicit about some current limitations (as of this writing):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Again, RSC are continuing to evolve, stay up to date on the latest in the official &lt;a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components"&gt;NextJS documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;RSC are not intended for the interactivity that a typical frontend or set of client-side components would offer. They should be used thoughtfully, and aren’t an answer to all our frontend woes!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s strongly recommended to stick to the NextJS structure for leveraging RSC (instead of trying to create your own, standalone react server component bundles), due to the complexity and evolving nature of RSC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get your hands dirty
&lt;/h2&gt;

&lt;p&gt;With the stable release of RSC in NextJS, we decided to get our hands dirty and have some fun. &lt;/p&gt;

&lt;p&gt;And speaking of sticking to the NextJS structure/boilerplate for leveraging React Server Components, that’s exactly what we’ve done in our &lt;a href="https://github.com/miroapp/rsc-workshop/tree/moment-time"&gt;Miro app&lt;/a&gt;. In addition to testing out RSC, we wanted to add a little bit of our own twist to things. So, we created a Miro-inspired application that both helped us explore RSC and create a more visually robust app. As a bonus, we used Miro as our authorization provider in order to kill two birds with one stone. 😎&lt;/p&gt;

&lt;p&gt;You can clone the &lt;a href="https://github.com/miroapp/rsc-workshop/tree/moment-time"&gt;moment-time branch of our GitHub repo&lt;/a&gt; and start playing around. To get up and running:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo&lt;/li&gt;
&lt;li&gt;From the root, run &lt;code&gt;git checkout origin/moment-time&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.env&lt;/code&gt; file with the following credentials:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MIRO_CLIENT_ID=""
MIRO_CLIENT_SECRET=""
MIRO_REDIRECT_URL="http://localhost:3000/auth/redirect/"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Reference the &lt;code&gt;README.md&lt;/code&gt; for steps to generate Miro Client ID and Miro Client Secret&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm run start&lt;/code&gt; and visit localhost:3000&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before diving into our starter app, you’ll want to make sure you’re up to speed with the basic conventions for writing react components, and it doesn’t hurt to review the official NextJS documentation on &lt;a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components"&gt;React Server Components&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;By default, any components included in the &lt;code&gt;app&lt;/code&gt; directory of your NextJS app will be rendered on the server as React Server Components. See an example in our app's &lt;code&gt;page.tsx&lt;/code&gt; file, where we import a large package, MomentJS. But because this component is within the app directory, it will render server-side first and the frontend bundle size will remain untouched.&lt;/p&gt;

&lt;p&gt;You can also use client components within the &lt;code&gt;app&lt;/code&gt; directory, but you will need to be explicit about this in your component file. This requires the &lt;code&gt;use client&lt;/code&gt; directive to ensure the file is loaded client side. See an example of this in our &lt;a href="https://github.com/miroapp/rsc-workshop/blob/moment-time/app/TimeDifference.tsx"&gt;TimeDifference.tsx&lt;/a&gt; file, where we create a client component to show the change in time in realtime. This is an example of how you might use client components to complement server components — for situations where you want to add interactivity (think of timers, stock updates, flight details, etc.).&lt;/p&gt;

&lt;h3&gt;
  
  
  Write your first React Server Component
&lt;/h3&gt;

&lt;p&gt;Write your first React Server Component in NextJS, in just a few simple steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inside your NextJS project, navigate to the &lt;code&gt;app&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;Create a new component&lt;/li&gt;
&lt;li&gt;Call this component from the main &lt;code&gt;index.js&lt;/code&gt; page (or if you're using our sample app, &lt;code&gt;page.tsx&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This component should render server-side first. To verify, load &lt;code&gt;page.tsx&lt;/code&gt; (or whatever page you wish to call the component in) and check out the page’s source code. You’ll see your server component reflected directly in the html markdown.&lt;/p&gt;

&lt;h3&gt;
  
  
  Miro Sample App
&lt;/h3&gt;

&lt;p&gt;Let’s take a look at a specific example in &lt;a href="https://github.com/miroapp/rsc-workshop/blob/moment-time/app/page.tsx"&gt;our sample app here&lt;/a&gt;. We’re leveraging the &lt;a href="https://www.npmjs.com/package/moment"&gt;moment.js NPM package&lt;/a&gt; to generate today’s date-time server-side. In our &lt;code&gt;page.tsx&lt;/code&gt; file, we’re importing MomentJS and returning it in our HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// app/page.tsx
import moment from 'moment'
[...]

return (
  &amp;lt;div className="grid wrapper"&amp;gt;
    &amp;lt;time&amp;gt;
    {moment().format('MMMM Do YYYY, h:mm:ss a')}
    &amp;lt;/time&amp;gt;
  [...]
  &amp;lt;/div&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when we go to our app and inspect the page source, we’ll see our server component has been directly injected into the HTML on our frontend:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxc8v9m3zheu2105xt7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxc8v9m3zheu2105xt7b.png" alt="Image description" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In contrast, when we look at &lt;code&gt;TimeDifference.tsx&lt;/code&gt; in our sample app, we are using the &lt;code&gt;use client&lt;/code&gt; directive at the top of the file to ensure the component is loaded client-side. You'll notice in the page source this is reflected as follows, since the time difference is rendered client-side:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1t4ao4xo9427ro40hljf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1t4ao4xo9427ro40hljf.png" alt="Image description" width="800" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Further exploration
&lt;/h3&gt;

&lt;p&gt;Okay, so we’ve talked a bit about RSC and we’ve seen how we’re using it in our &lt;a href="https://github.com/miroapp/rsc-workshop/tree/moment-time"&gt;Miro sample app&lt;/a&gt;—but this is just the tip of the iceberg!&lt;/p&gt;

&lt;p&gt;We’ve used the &lt;a href="https://www.npmjs.com/package/moment"&gt;MomentJS&lt;/a&gt; example to leverage RSC in our app, but there are other use cases that you can test out. Here are a couple of ideas to keep the momentum going:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new server component in our sample app that leverages a different dependency. For example, any larger NPM packages are great candidates to keep server-side!&lt;/li&gt;
&lt;li&gt;Take an existing or older React app of your own and groom through your components to see if you’re currently including any heavy dependencies on your frontend. If so, try and convert these to server-side components!&lt;/li&gt;
&lt;li&gt;Show us what you build!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The state of RSC: Now and next
&lt;/h2&gt;

&lt;p&gt;We’ve only scratched the surface of using React Server Components, but there’s so much more that can be done to leverage their efficient, performance-improving abilities. &lt;/p&gt;

&lt;p&gt;Luckily, the NextJS team thinks so too, so they’ve included it in their latest stable releases and we can look forward to more improvements in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the next big thing with NextJS and Miro
&lt;/h2&gt;

&lt;p&gt;If you found this quickstart on using React Server Components and our sample app helpful, let’s keep it going!&lt;/p&gt;

&lt;p&gt;Build any app or integration that leverages React + Miro’s &lt;a href="https://developers.miro.com/reference/api-reference"&gt;REST API&lt;/a&gt;, &lt;a href="https://developers.miro.com/docs/miro-web-sdk-introduction"&gt;Web SDK&lt;/a&gt;, or &lt;a href="https://developers.miro.com/docs/miro-live-embed-introduction"&gt;Live Embed&lt;/a&gt;, and share it with us on our developer community &lt;a href="https://discord.gg/NMnP3WwEbn"&gt;Discord server&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;Any functioning app that leverages one of these Miro capabilities is eligible to potentially be promoted more broadly in our community, and we’d love to share some exclusive Miro swag with you. 🚀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9yxqedzjxqmhn03dfz2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9yxqedzjxqmhn03dfz2r.png" alt="Sample Apps Graphic" width="800" height="418"&gt;&lt;/a&gt;&lt;br&gt;
Check out our other &lt;a href="https://github.com/miroapp/app-examples"&gt;sample apps&lt;/a&gt; for some more inspiration. We can’t wait to see what you build!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Did you like seeing how you can leverage the Miro Developer Platform in conjunction with React? For more inspiration or questions, follow along with our &lt;a href="https://community.miro.com/developer-platform-and-apis-57"&gt;Developer Community&lt;/a&gt; on &lt;a href="https://www.youtube.com/channel/UC37GT5mtEbYmnxXlKTIJ-rw"&gt;YouTube&lt;/a&gt;, &lt;a href="https://github.com/miroapp/app-examples"&gt;GitHub&lt;/a&gt;, and &lt;a href="https://discord.gg/NMnP3WwEbn"&gt;Discord&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>miro</category>
      <category>nextjs</category>
      <category>rest</category>
    </item>
  </channel>
</rss>
