<?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: Michael Bromley</title>
    <description>The latest articles on DEV Community by Michael Bromley (@michlbrmly).</description>
    <link>https://dev.to/michlbrmly</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F419452%2F1fe84d6b-36a9-45a4-9179-b86657cd6b50.png</url>
      <title>DEV Community: Michael Bromley</title>
      <link>https://dev.to/michlbrmly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michlbrmly"/>
    <language>en</language>
    <item>
      <title>Lightning Fast Headless Commerce with Vendure and Remix</title>
      <dc:creator>Michael Bromley</dc:creator>
      <pubDate>Wed, 25 May 2022 11:43:03 +0000</pubDate>
      <link>https://dev.to/michlbrmly/lightning-fast-headless-commerce-with-vendure-and-remix-4jbj</link>
      <guid>https://dev.to/michlbrmly/lightning-fast-headless-commerce-with-vendure-and-remix-4jbj</guid>
      <description>&lt;p&gt;&lt;a href="https://remix.run/"&gt;Remix&lt;/a&gt; is a new full-stack JavaScript framework which focuses on web standards, modern web app UX,&lt;br&gt;
and which promises to help you &lt;strong&gt;build better websites&lt;/strong&gt;. In this post we'll explore how Remix is ideally suited to&lt;br&gt;
headless commerce.&lt;/p&gt;



&lt;p&gt;First of all, if you don't know the term "headless commerce", it just means e-commerce applications where the storefront communicates with the commerce backend via an API. &lt;strong&gt;Vendure&lt;/strong&gt; is one such "headless" server - it deals with all the product, order &amp;amp; customer data and logic, and the storefront interacts with it via its GraphQL API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uw7zjRGx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.vendure.io/blog/2022/05/lightning-fast-headless-commerce-with-vendure-and-remix/lighthouse-score.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uw7zjRGx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.vendure.io/blog/2022/05/lightning-fast-headless-commerce-with-vendure-and-remix/lighthouse-score.webp" alt="Screenshot" width="880" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been aware of Remix for a while, but it was only after reading&lt;br&gt;
their &lt;a href="https://remix.run/blog/remix-vs-next"&gt;blog post comparing Remix to Next.js&lt;/a&gt; that I really sat up and paid&lt;br&gt;
attention. I soon discovered that it could be an ideal framework on which to build a headless commerce storefront:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it supports server-rendering by default&lt;/li&gt;
&lt;li&gt;it ships minimal Javascript to the browser, keeping initial loads fast&lt;/li&gt;
&lt;li&gt;it has native support for prefetching to speed up page loads&lt;/li&gt;
&lt;li&gt;it encourages graceful error handling&lt;/li&gt;
&lt;li&gt;it runs on edge servers (more on this later)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In fact, I was so impressed with what I saw that I decided to make Vendure&lt;br&gt;
an &lt;strong&gt;&lt;a href="https://remix.run/conf#sponsors"&gt;official sponsor&lt;/a&gt; of the inaugural Remix Conf&lt;/strong&gt;!&lt;/p&gt;
&lt;h2&gt;
  
  
  React made simple
&lt;/h2&gt;

&lt;p&gt;As a React newbie, I wasn't sure what I was letting myself in for - I've dabbled with Next.js, but I'm not afraid to&lt;br&gt;
admit that some of the more advanced uses of hooks still confuse me. I was really happy to discover that the whole&lt;br&gt;
design of Remix meant I very rarely needed to reach for anything more complex than &lt;code&gt;useState&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;For the initial proof of concept I had the help of a React-savvy friend to get&lt;br&gt;
things started, and after sharing my progress on Twitter I got&lt;br&gt;
some &lt;a href="https://twitter.com/kentcdodds/status/1522596597565038592"&gt;invaluable tips from Kent from the Remix team&lt;/a&gt; (shout&lt;br&gt;
out to Kent for his incredible work supporting and boosting the Remix community!)&lt;/p&gt;

&lt;p&gt;After that I found I was able to move quickly, even with my limited React experience! The more notoriously complex&lt;br&gt;
aspects of building a React app - wrangling build tools, dealing with state management libraries - seem to be completely&lt;br&gt;
side-stepped by Remix's opinionated approach to the app-building experience.&lt;/p&gt;
&lt;h2&gt;
  
  
  Effortless server rendering
&lt;/h2&gt;

&lt;p&gt;E-commerce is the archetypal example of the need for server-side rendering (SSR) of web applications. Why? Because&lt;br&gt;
ensuring that search engine crawlers can read our pages is &lt;em&gt;essential&lt;/em&gt; to driving traffic to our shop. Back in the early&lt;br&gt;
days of JavaScript web apps, we had some &lt;em&gt;interesting&lt;/em&gt; solutions to this problem - anyone else remember using headless&lt;br&gt;
Chrome to crawl our sites and generate static HTML files? On the other hand, build-time static site generators like Gatsby can become difficult to scale to stores with hundreds or thousands of products.&lt;/p&gt;

&lt;p&gt;Thankfully, most modern JS frameworks have some kind of built-in support for SSR. Remix is a great example of this. The&lt;br&gt;
server and client code exists in the same file and passing data from the server to the client is a matter of returning&lt;br&gt;
an object from the &lt;code&gt;loader&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Not only does this approach make your pages SEO-ready by default, it also allows you to limit the browser bundle to &lt;em&gt;only&lt;/em&gt; that code &lt;em&gt;strictly needed on the client&lt;/em&gt;. This can massively reduce the amount of JavaScript sent to the browser,&lt;br&gt;
significantly reducing load times and speeding up the storefront experience.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bye-bye client libraries
&lt;/h2&gt;

&lt;p&gt;Since Remix is a full-stack framework, it is able to load data directly from a database rather than requiring an HTTP&lt;br&gt;
API like most front end frameworks. I was curious to see how it would work with Vendure's GraphQL API as a data source.&lt;/p&gt;

&lt;p&gt;I was very pleasantly surprised to find that it works &lt;em&gt;really&lt;/em&gt; well! I would usually reach for a full-featured GraphQL&lt;br&gt;
client with a normalized cache like Apollo Client or Urql, but by fully embracing the Remix way, &lt;strong&gt;plain old &lt;code&gt;fetch&lt;/code&gt;&lt;br&gt;
worked perfectly&lt;/strong&gt;. The usual issues of client state getting out of sync (which I typically solved with a normalized&lt;br&gt;
client cache) are solved by Remix's method of revalidating any data that might have changed.&lt;/p&gt;

&lt;p&gt;Not only does this &lt;em&gt;significantly&lt;/em&gt; simplify data handling, it also completely removes the need to ship any kind of&lt;br&gt;
GraphQL client library to the browser!&lt;/p&gt;
&lt;h2&gt;
  
  
  Living on the Edge
&lt;/h2&gt;

&lt;p&gt;Since a Remix app is both a server &lt;em&gt;and&lt;/em&gt; a client application, we can't just host it like a simple static website. It&lt;br&gt;
actually &lt;em&gt;executes JavaScript&lt;/em&gt; when a new request comes in. So how do we host it?&lt;/p&gt;

&lt;p&gt;One option is to run it as a traditional Express app. But due to the smart platform-agnostic design of Remix, it can run&lt;br&gt;
in &lt;a href="https://remix.run/docs/en/v1/pages/technical-explanation#http-handler-and-adapters"&gt;any Node.js server&lt;/a&gt; like Vercel,&lt;br&gt;
Netlify or AWS Architect. Furthermore, it can run on non-Node.js platforms like Cloudflare Workers or Deno Deploy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://workers.cloudflare.com/"&gt;Cloudflare Workers&lt;/a&gt; is a particularly exciting technology - it allows you to run code&lt;br&gt;
at "the edge" - which means a network of servers distributed all around the world. So if a customer in Sydney visits&lt;br&gt;
your store, they will be served by a Cloudflare server right there in Sydney. Likewise in Vienna, Lagos, Seattle or any&lt;br&gt;
of the 250+ locations worldwide. This can &lt;em&gt;dramatically&lt;/em&gt; reduce the latency of requests, making your storefront &lt;strong&gt;lightning fast&lt;/strong&gt; (as you'll see in the demo below!).&lt;/p&gt;
&lt;h2&gt;
  
  
  Show me!
&lt;/h2&gt;

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

&lt;p&gt;&lt;strong&gt;Yes, the video above is in real-time!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Vendure server is a default installation running on a $5 Digital Ocean droplet backed by SQLite. No special caching or performance tricks - just a completely vanilla install.&lt;/p&gt;

&lt;p&gt;The Remix storefront is running on Cloudflare Pages. It feels like a static website, but it's fully dynamic.&lt;/p&gt;

&lt;p&gt;The combination of Remix's performance-first design running at the edge really has to be seen to be believed. &lt;strong&gt;Try it for yourself!&lt;/strong&gt; 👇&lt;/p&gt;

&lt;h3&gt;
  
  
  🛒 &lt;a href="https://remix-storefront.vendure.io/"&gt;remix-storefront.vendure.io&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  👨‍💻 &lt;a href="https://github.com/vendure-ecommerce/storefront-remix-starter"&gt;github.com/vendure-ecommerce/storefront-remix-starter&lt;/a&gt;
&lt;/h3&gt;




&lt;p&gt;&lt;em&gt;Special thanks to &lt;a href="https://twitter.com/EdoRivai"&gt;Edo Rivai&lt;/a&gt; for doing the initial work on the Remix storefront repo - your React expertise got me started in the right direction! Also thanks is due to Conor Burns &amp;amp; Timur Dogan of &lt;a href="https://0xcb.dev/"&gt;0xcb.dev&lt;/a&gt; who first got it running on Cloudflare Pages&lt;/em&gt; 🙏.&lt;/p&gt;

</description>
      <category>remix</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Towards Vendure v2.0</title>
      <dc:creator>Michael Bromley</dc:creator>
      <pubDate>Tue, 15 Mar 2022 21:19:00 +0000</pubDate>
      <link>https://dev.to/michlbrmly/towards-vendure-v20-1aao</link>
      <guid>https://dev.to/michlbrmly/towards-vendure-v20-1aao</guid>
      <description>&lt;p&gt;Today sees the release of version 1.5 of &lt;a href="https://www.vendure.io/"&gt;Vendure&lt;/a&gt;, the open-source headless commerce framework. This release sees Vendure reach a point of high stability &amp;amp; maturity, with all major APIs completed and almost a year of bug fixes and refinements behind us.&lt;/p&gt;

&lt;p&gt;Just 10 months after the v1.0 launch, Vendure is now being used in production in dozens of stores, from small &lt;a href="https://www.vendure.io/case-study/pinelab/"&gt;boutique print shops&lt;/a&gt; to huge &lt;a href="https://www.vendure.io/case-study/klekt/"&gt;Europe-wide marketplaces&lt;/a&gt; to &lt;a href="https://www.vendure.io/case-study/swile/"&gt;billion-dollar startups&lt;/a&gt; and yes, even &lt;a href="https://www.vendure.io/case-study/ibm/"&gt;giants like IBM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With a active and growing community, Vendure is truly a &lt;strong&gt;mature, proven and production-ready headless commerce platform&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So what's next? Let's talk about the future. &lt;strong&gt;Let's talk about Vendure v2.0!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What's special about v2.0? Well, there are a number of changes and features I’d like to introduce which I cannot, since they would require breaking changes. I try my best to follow &lt;a href="https://semver.org/"&gt;semantic versioning&lt;/a&gt;, which means that all v1.x.x releases should be backwards-compatible. In other words, updating the Vendure package versions should not require any changes to your existing code. So far we’ve done a pretty good job of this!&lt;/p&gt;

&lt;p&gt;However, certain changes simply cannot be made without changing the database schema, updating dependent libraries with breaking API changes, or altering parts of the Vendure data model. Here are some examples of breaking changes which need to wait until v2.0:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updating the underlying libraries that Vendure is built on to their latest versions, namely &lt;strong&gt;NestJS&lt;/strong&gt;, &lt;strong&gt;GraphQL&lt;/strong&gt;, &lt;strong&gt;Apollo Server&lt;/strong&gt; &amp;amp; &lt;strong&gt;Angular&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Modifying the data model to support &lt;strong&gt;multiple stock locations&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Adding support for &lt;strong&gt;bundle products&lt;/strong&gt; (allowing custom products to be assembled from disparate product variants)&lt;/li&gt;
&lt;li&gt;Improving support for true &lt;strong&gt;multivendor marketplaces&lt;/strong&gt; - this will be a major focus of the next version, since there is huge demand for it and there seems to be very few alternatives out there at present. If you are interested in this feature, I invite you to share ideas &amp;amp; feedback in &lt;a href="https://github.com/vendure-ecommerce/vendure/issues/1329"&gt;this issue&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Removing deprecated APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the above and more are planned for Vendure v2.0. You can see the status of these issues in our &lt;a href="https://github.com/vendure-ecommerce/vendure/projects/3"&gt;roadmap&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is also possible to start testing these changes now by using the &lt;code&gt;@next&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @vendure/core@next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install a version like &lt;code&gt;2.0.0-next.1&lt;/code&gt;, which reflects the &lt;a href="https://github.com/vendure-ecommerce/vendure/tree/major"&gt;major branch of the Vendure repo&lt;/a&gt;. Changes in these pre-release versions can be found in the &lt;a href="https://github.com/vendure-ecommerce/vendure/blob/major/CHANGELOG_NEXT.md"&gt;CHANGELOG_NEXT.md file&lt;/a&gt;. I’m using the &lt;code&gt;@next&lt;/code&gt; version in my own Vendure projects, but the usual caveats about using pre-release software apply!&lt;/p&gt;

&lt;p&gt;I have no set timeline for the release of v2.0, but I would expect it to be ready within the next six months 🤞.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and if you'd like to find out more about Vendure, head over to our &lt;a href="https://www.vendure.io/docs/getting-started/"&gt;Getting Started guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>headless</category>
      <category>webdev</category>
      <category>news</category>
    </item>
    <item>
      <title>GraphQL Fundamentals: Hands-On</title>
      <dc:creator>Michael Bromley</dc:creator>
      <pubDate>Mon, 17 Jan 2022 11:16:52 +0000</pubDate>
      <link>https://dev.to/michlbrmly/graphql-fundamentals-hands-on-30lk</link>
      <guid>https://dev.to/michlbrmly/graphql-fundamentals-hands-on-30lk</guid>
      <description>&lt;p&gt;In this post we will explore some of the fundamental concepts of GraphQL in a hands-on way. The goal of this post is to allow the beginner to gain a familiarity with the basic features of GraphQL. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The best way to learn is to do&lt;/strong&gt;. So this tutorial will be light on theory and heavy on practical exercises. &lt;/p&gt;

&lt;p&gt;So we'll need a real graphql server to play with. Let's use &lt;a href="https://www.vendure.io" rel="noopener noreferrer"&gt;Vendure&lt;/a&gt;, an open-source GraphQL e-commerce framework. I chose Vendure because it is really easy to set up - all you need is to make sure you have &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; installed. Plus I built it so I know the API quite well 😉&lt;/p&gt;

&lt;p&gt;To install a local instance of Vendure, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx @vendure/create my-shop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and follow the prompts. Select SQLite and use the defaults for all other prompts. Installation should take about 5 minutes and then you'll have a full, production-grade GraphQL server pre-populated with sample data ready to play with! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhlginhsfg9pvuhyq5333.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhlginhsfg9pvuhyq5333.gif" alt="Installing the Vendure GraphQL server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once installation is complete, open up &lt;a href="http://localhost:3000/shop-api" rel="noopener noreferrer"&gt;http://localhost:3000/shop-api&lt;/a&gt; in your browser. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: if you are unable to install Vendure locally for any reason (e.g. you are on a mobile device), you can still follow along with this article by using the public demo server at &lt;a href="https://demo.vendure.io/shop-api" rel="noopener noreferrer"&gt;demo.vendure.io/shop-api&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You should see the GraphQL Playground - an interactive interface for working directly with the GraphQL server. This is what we'll be using for all the exercises on this article. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fx9mfosupk3zq5lhb5b4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx9mfosupk3zq5lhb5b4w.png" alt="GraphQL Playground"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Your first query
&lt;/h2&gt;

&lt;p&gt;GraphQL allows us to fetch data by sending &lt;em&gt;queries&lt;/em&gt;. Queries are similar to GET requests in a REST API. Let's write our first query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy this into the left pane of the playground and then press the play button. You should see the response in the right pane:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laptop"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! You executed your first graphql operation! &lt;/p&gt;

&lt;p&gt;What did we do here? Let's analyze each part of this. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;query&lt;/code&gt;: First of all we are declaring that we are making a &lt;em&gt;query&lt;/em&gt;. This is in contrast to a &lt;em&gt;mutation&lt;/em&gt; (which we will cover below). Technically you can omit that &lt;code&gt;query&lt;/code&gt; keyword, but we'll keep using it just to be more explicit.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;product&lt;/code&gt;: Next we are specifying the query we wish to use: &lt;em&gt;product&lt;/em&gt;. Each GraphQL server defines a set of possible queries. Since Vendure is an e-commerce server, it exposes queries related to products, orders, customers, etc. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id: 1&lt;/code&gt;: We then pass an argument to our query, specifying the ID of the product we want to return. You can think of this very much like a function call. Just like function calls, GraphQL queries can take zero, one or more arguments. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ id, name }&lt;/code&gt;: We finally specify the fields we want to return. Fields are like &lt;em&gt;properties&lt;/em&gt; on a JavaScript object. In this case, we want to know just the ID and name of the product. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Selecting fields
&lt;/h2&gt;

&lt;p&gt;One of the big benefits of GraphQL over REST APIs is that you can specify the exact data you need, and the server will return those &lt;em&gt;and only those&lt;/em&gt; fields. This means you can avoid sending too much data over the wire, leading to faster data transfer and lower bandwidth usage. &lt;/p&gt;

&lt;p&gt;Let's try adding some more fields to our query. Add the &lt;code&gt;slug&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; fields to the selection, and press the play button. You should see that these two new fields are added to the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laptop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"slug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Now equipped with seventh-generation Intel Core processors, ..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's try an experiment: what happens if we add a field to our selection that does not actually exist on our product. Try adding the field &lt;code&gt;age&lt;/code&gt;, and you'll get the following result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"errors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cannot query field &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; on type &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Product&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;. Did you mean &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"locations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"column"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Schema &amp;amp; Types
&lt;/h2&gt;

&lt;p&gt;This highlights another important property of GraphQL: it is &lt;em&gt;statically typed&lt;/em&gt;. That is to say, the exact fields available, and the types of data they can hold (strings, numbers, dates etc.) are explicitly defined in a &lt;strong&gt;schema&lt;/strong&gt;. The schema, in fact, defines all available queries and mutations, and the exact type of objects they can return. &lt;/p&gt;

&lt;p&gt;This is an extremely powerful property of GraphQL and allows things like auto-complete and automatic validation of data you send to the server.&lt;/p&gt;

&lt;p&gt;You have already seen the auto-complete as you typed the field names above. You can also see &lt;em&gt;all&lt;/em&gt; available fields on a given object by pressing &lt;code&gt;ctrl + space&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fx62cshbp26cpdmqlsfsi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx62cshbp26cpdmqlsfsi.gif" alt="Autocomplete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the bottom of the auto-complete popup, in orange text, you'll see the &lt;em&gt;type&lt;/em&gt; of that field. GraphQL types are analogous to &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Primitive" rel="noopener noreferrer"&gt;primitives&lt;/a&gt; in JavaScript, &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Boolean&lt;/code&gt;, &lt;code&gt;Int&lt;/code&gt;, &lt;code&gt;Float&lt;/code&gt; &amp;amp; &lt;code&gt;ID&lt;/code&gt;. In GraphQL these are known as &lt;em&gt;scalar types&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;When a field represents a more complex data type, GraphQL supports &lt;em&gt;object types&lt;/em&gt;. In fact, we've been working with an object type all along - the &lt;code&gt;Product&lt;/code&gt; object! That's right, &lt;em&gt;queries&lt;/em&gt; themselves have a type. In this case, the &lt;code&gt;product&lt;/code&gt; query has the type &lt;code&gt;Product&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;📖 &lt;em&gt;Reference: &lt;a href="https://graphql.org/learn/schema/#scalar-types" rel="noopener noreferrer"&gt;graphql.org Scalar Types&lt;/a&gt;, &lt;a href="https://graphql.org/learn/schema/#object-types-and-fields" rel="noopener noreferrer"&gt;graphql.org Object Types&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Nested Objects
&lt;/h2&gt;

&lt;p&gt;Another of the major benefits of GraphQL is that a single query allows you to fetch an object &lt;em&gt;plus nested relations&lt;/em&gt;. What would require several individual http requests using a REST API can be achieved in &lt;strong&gt;a single GraphQL query&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;To illustrate that, let's update our query to select all the variants of our Laptop product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;slug&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;variants&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we run this, we'll get the requested fields on &lt;em&gt;each&lt;/em&gt; of the laptop variants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laptop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"slug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Now equipped with seventh-generation Intel Core processors, ..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"variants"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laptop 13 inch 8GB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"L2201308"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;129900&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laptop 15 inch 8GB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"L2201508"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;139900&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laptop 13 inch 16GB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"L2201316"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;219900&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laptop 15 inch 16GB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"L2201516"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;229900&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a REST API, we'd typically need to make 5 separate requests to get all that data - one for the product, and one for each of the 4 variants!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-on: Queries
&lt;/h2&gt;

&lt;p&gt;Now that we know the fundamental concepts of GraphQL queries, spend some time exploring the Vendure API! Use the &lt;code&gt;ctrl + space&lt;/code&gt; hotkey to bring up the available queries and their fields.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Frnfq4xdwqwws7mj6fbv0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Frnfq4xdwqwws7mj6fbv0.gif" alt="Exploring the available queries"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutations
&lt;/h2&gt;

&lt;p&gt;Mutations are the counterpart to queries, and as the name suggests, they are used to &lt;em&gt;mutate&lt;/em&gt; (change) data. Mutations are similar to POST or PUT requests in a REST API.&lt;/p&gt;

&lt;p&gt;Let's execute a mutation. Paste this into the left hand panel of the playground:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;mutation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;addItemToOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productVariantId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;totalQuantity&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;totalWithTax&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ErrorResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;errorCode&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press the play button and you'll see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"addItemToOrder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AddingItems"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"totalQuantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"totalWithTax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;155880&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's once again break down each part of the mutation syntax:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;mutation&lt;/code&gt;: declares that we are dealing with a mutation as opposed to a query. Unlike with queries, this keyword is &lt;em&gt;not&lt;/em&gt; optional. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;addItemToOrder&lt;/code&gt;: the name of the mutation as declared by our schema. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;productVariantId: 1&lt;/code&gt;: like queries, mutations can (and usually do) take arguments. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;... on Order&lt;/code&gt;: this is known as an inline fragment. Since things might go wrong when adding an item to an order (e.g. insufficient stock), the mutation will return either an &lt;code&gt;Order&lt;/code&gt; object, or an &lt;code&gt;ErrorResult&lt;/code&gt; object. This syntax is like saying &lt;em&gt;"if it returns an Order, then give me the ID, state, totalQuantity &amp;amp; totalWithTax fields. If it returns an ErrorResult, then give me the errorCode and message fields."&lt;/em&gt; You can try this out by entering &lt;code&gt;quantity: -1&lt;/code&gt; and observing what happens.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see, mutations share all the same parts as a query. In fact, the only real difference is the &lt;code&gt;mutation&lt;/code&gt; keyword at the start. Just like with queries, they have arguments and they return a type. In this case the type is a combination of several object types (known in GraphQL as a &lt;em&gt;union&lt;/em&gt; type, a more advanced topic out of the scope of this tutorial). &lt;/p&gt;

&lt;p&gt;📖 &lt;em&gt;Reference: &lt;a href="https://graphql.org/learn/queries/#mutations" rel="noopener noreferrer"&gt;graphql.org Mutations&lt;/a&gt;, &lt;a href="https://graphql.org/learn/schema/#union-types" rel="noopener noreferrer"&gt;graphql.org Union Types&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-on: Mutations
&lt;/h2&gt;

&lt;p&gt;Now you can explore for yourself how mutations work using the GraphQL playground. With the initial &lt;code&gt;mutation { }&lt;/code&gt; keyword in place, pressing &lt;code&gt;ctrl + space&lt;/code&gt; will now bring up auto-complete on all available mutations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F1faoebkt45gmecvd9gps.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F1faoebkt45gmecvd9gps.gif" alt="Exploring mutations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's a challenge for you:&lt;/strong&gt; see if you are able to successfully execute the &lt;code&gt;adjustOrderLine&lt;/code&gt; mutation in order to change the quantity of laptops in your order. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post we've covered how to set up a full-featured GraphQL server using Vendure, and then learned the basics of queries and mutations. These two concepts form the basis of everything you'll be doing with GraphQL.&lt;/p&gt;

&lt;p&gt;But of course this is more that you can learn - fragments, interfaces, named operations, variables, aliases and more. If you like the style of this tutorial and would like to see a follow-up that takes the next step into these more advanced topics, please leave a comment below!&lt;/p&gt;

&lt;p&gt;And if you enjoyed working with Vendure - &lt;a href="https://github.com/vendure-ecommerce/vendure" rel="noopener noreferrer"&gt;check out the GitHub repo&lt;/a&gt; and leave a star! 🙏&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What makes e-commerce apps so hard to build?</title>
      <dc:creator>Michael Bromley</dc:creator>
      <pubDate>Sun, 16 Jan 2022 14:59:52 +0000</pubDate>
      <link>https://dev.to/michlbrmly/what-makes-e-commerce-apps-so-hard-to-build-2b6j</link>
      <guid>https://dev.to/michlbrmly/what-makes-e-commerce-apps-so-hard-to-build-2b6j</guid>
      <description>&lt;p&gt;E-commerce is a cornerstone of the internet economy. There are millions of e-commerce applications out there and more being built every day. For such a common type of application, they are famously hard to get right.&lt;/p&gt;

&lt;p&gt;In this post I'll outline some of the factors that make e-commerce applications the &lt;em&gt;final boss&lt;/em&gt; of web apps, and then discuss some of the solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problems
&lt;/h2&gt;

&lt;p&gt;If you want to build an e-commerce app, you need to think about:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SEO. This is critical. Thus you need to carefully consider &lt;a href="https://blog.logrocket.com/ssg-vs-ssr-in-next-js/"&gt;SSR vs SSG&lt;/a&gt;, caching, invalidation, url design, redirects.&lt;/li&gt;
&lt;li&gt;Performance. Long loading times or sluggish response to input will drive away customers and impact SEO (see 1). Bundles need to be kept lean. And remember, marketing plans to later add 3MB of JS via Google Tag Manager 🙃.&lt;/li&gt;
&lt;li&gt;You have an impatient audience who can go elsewhere. This is not some intranet app that users are obliged to use. You need to win them over with a superior user experience.&lt;/li&gt;
&lt;li&gt;You are dealing with financial transactions. Bugs can be very consequential! A rounding error on a high-traffic site can get ugly 😬.&lt;/li&gt;
&lt;li&gt;Storefront apps are complex. Beyond basic product list/detail/checkout, you have search, filtering, wishlists, auth + accounts, gift cards, promotions, taxes, shipping, and on and on.&lt;/li&gt;
&lt;li&gt;Integrations. A typical e-commerce app will minimally integrate with one or more payment providers, shipping providers, then maybe taxes, recommendations, CMS, reviews, emails etc.&lt;/li&gt;
&lt;li&gt;Legacy systems. Many businesses run on tech that cannot easily be changed. So your shiny new app will have to talk via SOAP or CSV files or do daily data imports from some server in head office.&lt;/li&gt;
&lt;li&gt;The messy real world. Payments will fail, customers will call to change an order, refund or return. Stock levels will get out of sync with the warehouse. It's a concatenation of edge cases.&lt;/li&gt;
&lt;li&gt;Scaling. Black Friday/Cyber Monday should not take down your website! But you also don't want to pay for a maxed-out server all year round.&lt;/li&gt;
&lt;li&gt;Internationalization. Are you selling in multiple countries? OK now you need to think about multiple languages, multiple currencies and exchange rates, display formats and (worst of all) multiple sets of tax rules.&lt;/li&gt;
&lt;li&gt;Taxes. I know I already just mentioned them, but getting tax compliance right is so hard that it deserves its own bullet point.&lt;/li&gt;
&lt;li&gt;A long shelf life. The typical e-commerce application needs to be operational for many years, even a decade or more. Especially when a lot of work has been done to integrate with existing systems, the cost of migrating to an entirely new platform is high. Therefore they need to be able to adapt to tomorrow's technology landscape. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Solutions
&lt;/h2&gt;

&lt;p&gt;There is no single solution to &lt;em&gt;all&lt;/em&gt; of these problems. Rather, there are a number of approaches which offer different trade-offs. Broadly, we can think of three axes of solution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SaaS vs Framework&lt;/li&gt;
&lt;li&gt;Monolithic vs Headless&lt;/li&gt;
&lt;li&gt;Proprietary vs Open source&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  SaaS vs Framework
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;SaaS platforms&lt;/strong&gt; take care of the operational issues, at least in theory. Even giants like Shopify can still have outages but in general they deal with traffic spikes well and let you forget about servers. Moreover, SaaS platforms free your team from needing to worry about upgrades and maintenance headaches.&lt;/p&gt;

&lt;p&gt;With widespread adoption, the leading SaaS platforms include much of the typical functionality required by most businesses, thereby cutting down the amount of custom development needed. For smaller and simpler use-cases, they can be a complete solution, and there are often existing integrations for most popular services for payments, shipping, taxes etc. &lt;/p&gt;

&lt;p&gt;Where they can fall down is when it comes to very particular business requirements. Remember those csv imports from that one supplier? Or the custom order flow demanded by the business model? You can end up having to write a lot of custom code, sometimes fighting against the platform. Or else cobbling together a Rube Goldberg collection of third-party extensions which becomes expensive in terms of money &lt;em&gt;and&lt;/em&gt; maintenance.&lt;/p&gt;

&lt;p&gt;SaaS examples: Shopify, BigCommerce, Commercetools, Swell&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;E-commerce frameworks&lt;/strong&gt; provide the building blocks for developers to create completely custom applications. Those tricky integrations with back-office systems and those specialized workflows can be &lt;em&gt;custom built&lt;/em&gt; by extending the core functionality of the framework.&lt;/p&gt;

&lt;p&gt;Frameworks typically require at least some custom implementation work, potentially driving up initial costs. Furthermore they need to be hosted, meaning that you are responsible for operations and keeping your store live over Black Friday. On the other hand, savings can be had in ongoing costs, as many frameworks do not require a yearly license to operate.&lt;/p&gt;

&lt;p&gt;Framework examples: Magento, Saleor, Vendure, WooCommerce, Shopware&lt;/p&gt;

&lt;h3&gt;
  
  
  Monolith vs Headless
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Monoliths&lt;/strong&gt; refer to applications in which the front-end storefront part is an inseparable part of the backend platform. Typically, the same platform will be generating the storefront based on a templating or theme system. Monolithic architecture has been around for a long time and is the most common way of building e-commerce apps. &lt;br&gt;
Monolith examples: Shopify, Magento, WooCommerce.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Headless&lt;/strong&gt; platforms, on the other hand, do not handle the storefront at all. Rather, they provide APIs (typically REST or GraphQL) which expose all e-commerce functionality, allowing a storefront to be created to the exact needs of the business, using the latest technologies.&lt;/p&gt;

&lt;p&gt;Headless architecture removes the technological lock-in of monolithic solutions, de-coupling the storefront app(s) from the commerce backend. This can allow merchants to take full advantage of the latest techniques to produce fast websites with a great user experience. It also allows a single backend to power web, mobile, point-of-sale and other apps simultaneously. &lt;/p&gt;

&lt;p&gt;From a developer perspective, headless frees up teams to use the technologies and workflows that suit them best. No more limitations of a restrictive theme system. No more being bound to non-optimal processes imposed by the backend. &lt;/p&gt;

&lt;p&gt;The major challenge with headless is that you get no storefront out of the box. Presenting raw JSON to customers won't fly! Building a storefront is a large undertaking, so the up-from implementation cost will be higher than with monolithic solutions which include a storefront. &lt;/p&gt;

&lt;p&gt;To mitigate this factor, there are an increasing number of storefront projects which have done all the hard work of implementing a modern commerce front end app, allowing you to plug them in to the headless backend of your choice. Examples include &lt;a href="https://www.vuestorefront.io/"&gt;Vue Storefront&lt;/a&gt; and Vercel's &lt;a href="https://nextjs.org/commerce"&gt;Next.js Commerce&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In recent years, headless architecture has been gaining a lot of interest to the point that many of the traditionally monolithic solutions have either added support for headless (Shopify, Magento) or have completely shifted focus.&lt;/p&gt;

&lt;p&gt;Headless examples: Commercetools, Swell, Vendure, Crystallize&lt;/p&gt;

&lt;h3&gt;
  
  
  Proprietary vs Open Source
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Proprietary&lt;/strong&gt; platforms do not make their code available, or make it available only under a commercial license. All of the SaaS platforms fall under this category, and there are also some proprietary frameworks - especially at the higher end of the market. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open source&lt;/strong&gt; projects have long played a major role in e-commerce. Especially at the mid-market, open source solutions like WooCommerce and Magento still dominate. &lt;/p&gt;

&lt;p&gt;The advantages of open source platforms include pricing, a potentially larger developer community (and thus hiring pool), the ability to modify the code to fix issues and some degree of protection from vendor lock-in. &lt;/p&gt;

&lt;p&gt;The trade-offs with open source solutions are the same as with frameworks in general, as open source solutions are typically self-hosted frameworks. Proprietary platforms may also be able to offer better customer support and things like service level agreements, which are not always available for open-source products.&lt;/p&gt;

&lt;p&gt;Many open source projects also offer a hosted version, which combines some of the strengths of SaaS with the control offered by frameworks. &lt;/p&gt;

&lt;h2&gt;
  
  
  Vendure
&lt;/h2&gt;

&lt;p&gt;I started building &lt;a href="https://www.vendure.io/"&gt;Vendure&lt;/a&gt; as an attempt to solve the particular combination of problems that our business had encountered. Vendure is an open-source headless commerce framework. Now that we've covered each of these terms, you should have an appreciation of the problems it is solving and the trade-offs that it makes. &lt;/p&gt;

&lt;p&gt;It handles all typical e-commerce functionality (and we spent a very long time getting taxes right!), whilst providing extension points which allow virtually any custom functionality to be added.&lt;/p&gt;

&lt;p&gt;It embraces modern tooling, including TypeScript and GraphQL, and is built on one of the most popular and widely-used Node.js frameworks - &lt;a href="https://nestjs.com/"&gt;NestJS&lt;/a&gt;. A primary goal of Vendure is to provide an outstanding developer experience which allows developers to build rapidly and have fun whilst doing so! &lt;/p&gt;

&lt;p&gt;It has integrations with &lt;a href="https://docs.vuestorefront.io/vendure/"&gt;Vue Storefront&lt;/a&gt; and &lt;a href="https://github.com/vercel/commerce/blob/main/framework/vendure/README.md"&gt;Next.js Commerce&lt;/a&gt;, meaning you can get up and running with a basic full stack headless commerce store in literally minutes. It is used in production on projects of all sizes, from solo founder-built shops to rapidly-growing startups to Fortune 500 enterprises.&lt;/p&gt;

&lt;p&gt;So if you are looking to start an e-commerce project and you think that a headless, open-source framework would be a good fit for your requirements, &lt;a href="https://www.vendure.io/docs/getting-started/"&gt;get started with Vendure&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>development</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Open Source win: IBM shifts legacy commerce systems to my one-man OSS project</title>
      <dc:creator>Michael Bromley</dc:creator>
      <pubDate>Fri, 17 Dec 2021 08:58:10 +0000</pubDate>
      <link>https://dev.to/michlbrmly/open-source-win-ibm-shifts-legacy-commerce-systems-to-my-one-man-oss-project-4n9b</link>
      <guid>https://dev.to/michlbrmly/open-source-win-ibm-shifts-legacy-commerce-systems-to-my-one-man-oss-project-4n9b</guid>
      <description>&lt;p&gt;For the past 3.5 years I've been working on an open-source e-commerce platform, &lt;a href="https://www.vendure.io/" rel="noopener noreferrer"&gt;Vendure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's in a niche known as "headless commerce" which is really hot right now, so I've had lots of interest from investors over the past year. However, I'm determined to see how far I can take things as a bootstrapped indie-hacker.&lt;/p&gt;

&lt;p&gt;Yesterday was a major milestone as I was able to announce that &lt;a href="https://www.vendure.io/case-study/ibm/" rel="noopener noreferrer"&gt;IBM have adopted Vendure&lt;/a&gt; to replace an outdated, proprietary system that had been slowing them down and causing huge expense in terms of license fees as well as lost developer productivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.vendure.io%2Fcase-study%2Fibm%2Fibm-header.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.vendure.io%2Fcase-study%2Fibm%2Fibm-header.jpg" alt="case study image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is really exciting because it shows just how much progress the open-source movement has made, that even the largest enterprises are willing to bet on lean, relatively new projects like Vendure - a single-person open-source project!&lt;/p&gt;

&lt;p&gt;It's a sign that the technology stack &lt;em&gt;is&lt;/em&gt; important. Developer experience, maintainability, documentation, openness - all these things actually contribute to the cost of running a system. So from both a technical &lt;em&gt;and&lt;/em&gt; financial viewpoint, OSS solutions increasingly make more sense.&lt;/p&gt;

&lt;p&gt;There's that old phrase, "nobody got fired for buying IBM". Well, I'm hoping that this will make it clear that my project is a safe choice, no matter the company size.&lt;/p&gt;

&lt;p&gt;Just thought I'd share the success!&lt;/p&gt;

&lt;p&gt;If you want to know more about Vendure, I recently wrote a &lt;a href="https://dev.to/michlbrmly/set-up-a-nodejs-e-commerce-app-in-10-minutes-with-vendure-287b"&gt;short intro tutorial&lt;/a&gt;, and I plan a more in-depth series of tutorials in the coming weeks.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>startup</category>
    </item>
    <item>
      <title>Set up a Node.js e-commerce app in 10 minutes with Vendure</title>
      <dc:creator>Michael Bromley</dc:creator>
      <pubDate>Mon, 13 Dec 2021 21:21:31 +0000</pubDate>
      <link>https://dev.to/michlbrmly/set-up-a-nodejs-e-commerce-app-in-10-minutes-with-vendure-287b</link>
      <guid>https://dev.to/michlbrmly/set-up-a-nodejs-e-commerce-app-in-10-minutes-with-vendure-287b</guid>
      <description>&lt;p&gt;&lt;a href="https://www.vendure.io/" rel="noopener noreferrer"&gt;Vendure&lt;/a&gt; is a modern headless e-commerce framework written in TypeScript and built on top of the excellent &lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt; framework.&lt;/p&gt;

&lt;p&gt;By "headless" we mean that it exposes an API (GraphQL in the case of Vendure), which allows you to build your storefront using your favourite front-end technology, be it Next.js, Vue, Svelte, or anything else you like!&lt;/p&gt;

&lt;p&gt;Headless e-commerce has a somewhat justified reputation of being more complex and development-intensive than off-the-shelf SaaS solutions like Shopify. But with Vendure we aim to cut down your development time to the bare minimum with a combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a rich set of features&lt;/li&gt;
&lt;li&gt;integrations with existing solutions&lt;/li&gt;
&lt;li&gt;optimal developer experience&lt;/li&gt;
&lt;li&gt;modern technologies and workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this tutorial I will take you step-by-step through setting up a fully-functional headless e-commerce server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fgyhi1rash5j42cpd5i51.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fgyhi1rash5j42cpd5i51.jpg" alt="Screenshot of the Vendure Admin UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To create your app, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @vendure/create my-shop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will guide you through the setup by asking you a series of questions. Select the following options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;√ Which database are you using? 
  » SQLite
√ Which programming language will you be using? 
  » TypeScript
√ Populate with some sample product data? 
  » yes
√ What identifier do you want to use for the superadmin user? 
  » superadmin
√ What password do you want to use for the superadmin user?
  » superadmin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go make yourself a drink or check your dev.to feed for a few minutes while we install all the dependencies and scaffold your app!&lt;/p&gt;

&lt;p&gt;Once everything is done you should see this message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Success! Created a new Vendure server at &amp;lt;path&amp;gt;/my-shop

We suggest that you start by typing:

    cd my-shop
    npm start

Happy hacking!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And... that's it! &lt;code&gt;cd&lt;/code&gt; into the newly-created directory and run &lt;code&gt;npm start&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Congratulations - you now have a fully-functional headless e-commerce server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it out
&lt;/h2&gt;

&lt;p&gt;Let's test out our shiny new GraphQL API! Go to &lt;a href="http://localhost:3000/shop-api" rel="noopener noreferrer"&gt;http://localhost:3000/shop-api&lt;/a&gt; and paste the following query into the left-hand pane of the GraphQL Playground app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;totalItems&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;featuredAsset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;preview&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Play around with the API - because it's GraphQL, you'll get rich code-completion so you don't need to try to guess what fields are available. Press &lt;code&gt;ctrl/cmd + space&lt;/code&gt; to get a list of available fields at any location.&lt;/p&gt;

&lt;p&gt;Next, you can head to &lt;a href="http://localhost:3000/admin" rel="noopener noreferrer"&gt;http://localhost:3000/admin&lt;/a&gt; where you can login with the credentials &lt;code&gt;superadmin&lt;/code&gt;, &lt;code&gt;superadmin&lt;/code&gt;. This will grant you access to the Vendure Admin UI - a full-featured interface for managing every aspect of your store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storefront
&lt;/h2&gt;

&lt;p&gt;Vendure only provides the backend part. What about the storefront? You'll need one of those if you want anybody to be able to buy your stuff.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fl95dspcc3xm4c6vs922p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fl95dspcc3xm4c6vs922p.jpg" alt="Vendure/Vercel Commerce integration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Building a custom storefront from scratch can be a big task, but luckily we've got a couple of great options for you to get you up-and-running in no time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.vuestorefront.io/" rel="noopener noreferrer"&gt;Vue Storefront&lt;/a&gt; is an industry-leading storefront library built on &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue&lt;/a&gt; &amp;amp; &lt;a href="https://nuxtjs.org/" rel="noopener noreferrer"&gt;Nuxt.js&lt;/a&gt;. The &lt;a href="https://www.vendure.io/integration/vue-storefront/" rel="noopener noreferrer"&gt;official Vue Storefront / Vendure integration&lt;/a&gt; allows you to set up a slick, modern and performant store-front in minutes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/commerce" rel="noopener noreferrer"&gt;Next.js Commerce&lt;/a&gt; is a starter kit that gets you set up with a modern storefront built by the Vercel team. The project also comes with a &lt;a href="https://github.com/vercel/commerce/blob/main/framework/vendure/README.md" rel="noopener noreferrer"&gt;Vendure integration&lt;/a&gt;, and you can see a live demo of it at &lt;a href="https://vendure.vercel.store/" rel="noopener noreferrer"&gt;vendure.vercel.store&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Build your own! Vendure is an excellent back-end to use when learning a new framework. It runs everywhere, uses few resources, and exposes a full, production-grade API to build against. Why not test out that latest framework by building a minimal e-commerce storefront?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;While Vendure is simple to set up, it is by no means a "light" or "toy" solution. In fact, it is one of the most extensible and &lt;a href="https://www.vendure.io/features/" rel="noopener noreferrer"&gt;feature-rich&lt;/a&gt; of all the e-commerce frameworks out there, and is used in production by Fortune 500 companies, billion-dollar start-ups and solo-developed boutique shop projects alike!&lt;/p&gt;

&lt;p&gt;To dive into the possibilities offered by Vendure, check out our extensive &lt;a href="https://www.vendure.io/docs/" rel="noopener noreferrer"&gt;developer documentation&lt;/a&gt;, and if you run into any trouble, please join our &lt;a href="https://join.slack.com/t/vendure-ecommerce/shared_invite/enQtNzA1NTcyMDY3NTg0LTMzZGQzNDczOWJiMTU2YjAyNWJlMzdmZGE3ZDY5Y2RjMGYxZWNlYTI4NmU4Y2Q1MDNlYzE4MzQ5ODcyYTdmMGU" rel="noopener noreferrer"&gt;Slack community&lt;/a&gt; where you'll find the help you need.&lt;/p&gt;

&lt;p&gt;Finally, here's a presentation I gave at a recent conference which covers more of the background and goals of the Vendure project. Thanks for reading!&lt;/p&gt;

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

</description>
      <category>typescript</category>
      <category>node</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
