<?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: Lars Roettig</title>
    <description>The latest articles on DEV Community by Lars Roettig (@larsroettig).</description>
    <link>https://dev.to/larsroettig</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%2F143566%2F9493cb58-0c2d-4bc7-8240-179c7c5228cb.jpeg</url>
      <title>DEV Community: Lars Roettig</title>
      <link>https://dev.to/larsroettig</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/larsroettig"/>
    <language>en</language>
    <item>
      <title>How i learned React?</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Tue, 05 Jan 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/larsroettig/how-i-learned-react-3e44</link>
      <guid>https://dev.to/larsroettig/how-i-learned-react-3e44</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lcM-Hy6G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hplunupx21ee36qm79cn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lcM-Hy6G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hplunupx21ee36qm79cn.jpg" alt="How i learned React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2019 I resolved to learn React because I have seen that PWA will be one of the critical technologies of the future.&lt;/p&gt;

&lt;p&gt;In 2020 has shown that it was the right decision because the headless hype train will roll in soon.&lt;/p&gt;

&lt;p&gt;I know React is not a golden hammer and is maybe not the right choice for your Project.&lt;br&gt;
If you want to more when you should select a PWA Approche, you should read &lt;a href="https://larsroettig.dev/getting-started-with-magento-pwa-studio"&gt;Getting started with Magento PWA Studio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now when you get into headless architecture, there is significantly much to learn and understand.&lt;br&gt;
Because the development of backend and frontend is independent.&lt;/p&gt;

&lt;p&gt;From my perspective, an advantage new frontend developers can use already known technologies like ReactJS without going through the learning curve of Magento.&lt;/p&gt;

&lt;p&gt;But without data from Back-End is not possible to build an online store with actual inventory. So we also need developers to build API between head and backend.&lt;/p&gt;

&lt;p&gt;After almost two years working in React and TypeScriprt in my spare time i am ready to summarize what help me to tame the technology stack.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Foundation before you start with React
&lt;/h2&gt;

&lt;p&gt;If you are not familiar with all ES6 (ECMAScript 2015) Features you should check out&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Good Ressources to learn TypeScript
&lt;/h2&gt;

&lt;p&gt;In my experience with a nice TypeScript Setup, you found already many bugs in development also It reduces the technical dep.&lt;br&gt;
If you haven't used it yet, I strongly recommended you should give it a shot, and you will never use plain JavaScript again if you can prevent it.&lt;/p&gt;

&lt;p&gt;Also, there is a Big shift in React Community Trainers like Kent C. Dodds, Sebastian Springer also recommends using TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript in 50 Lessons by Stefan Baumgartner (39.00 €)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stefan Baumgartner breaks down the quirks of TypeScript into short, manageable lessons.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I would call it the TS Bible a Complete guide for TypeScript.&lt;br&gt;
I highly recommended to read it, especially the chapters on generics and conditional types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.smashingmagazine.com/printed-books/typescript-in-50-lessons/"&gt;https://www.smashingmagazine.com/printed-books/typescript-in-50-lessons/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Good Ressources to learn React.JS
&lt;/h2&gt;

&lt;p&gt;There are incredibly many courses and books to learn to React.&lt;br&gt;
Unfortunately, many are outdated or do not explain enough.&lt;/p&gt;
&lt;h3&gt;
  
  
  Foundation materials
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Beginner's Guide to React (Free)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This course requires little knowledge of Javascript but shows everything newbies need to know to build a small React application.&lt;br&gt;
If you're working longer with React, you can learn a solid foundation of React, so I recommending don't skip it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://egghead.io/courses/the-beginner-s-guide-to-react"&gt;https://egghead.io/courses/the-beginner-s-guide-to-react&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Hooks in Action ($39.99)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Build interfaces in React without writing custom classes.&lt;br&gt;
React Hooks in Action teaches you to use pre-built hooks like useState, useReducer and useEffect, and build your own hooks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I really enjoyed the clear examples you also find many Graphic Materials what descript flow and how to React hooks works.&lt;br&gt;
In this book, you also learn about all the essential things to write maintainable React Code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.manning.com/books/react-hooks-in-action"&gt;https://www.manning.com/books/react-hooks-in-action&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Advanced Materials
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;TypeScript Plus React = Love (Free)&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Fullstack React with TypeScript ($39.99)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I practical guidelines you learn building professional React Application with TypeScript.&lt;/p&gt;

&lt;p&gt;I find the examples very practical and help one deepen the React Pattern and remember My opinion often missing explanations for the basics like how the pattern works in theory with graphics. Without React knowledge, you will not understand many important topics.&lt;/p&gt;

&lt;p&gt;Mainly for 39 $ but is extremely good if you do not know what to build with the newly acquired knowledge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.newline.co/fullstack-react-with-typescript"&gt;https://www.newline.co/fullstack-react-with-typescript&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Full Course
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Epic React (599$)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This course is a 19-hour collection of an interactive self-paced workshop exercise.&lt;/p&gt;

&lt;p&gt;I finish the first 5 sections of it.&lt;br&gt;
From my point of view it has excellent Examples I think you can spend&lt;br&gt;
four full days to understand all sections and build all things with all extra credits, which helps real applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://epicreact.dev/"&gt;https://epicreact.dev/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Helpful React, Blogs and posts to understand:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://epicreact.dev/articles"&gt;https://epicreact.dev/articles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/"&gt;https://kentcdodds.com/blog/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://overreacted.io/a-complete-guide-to-useeffect/"&gt;https://overreacted.io/a-complete-guide-to-useeffect/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://overreacted.io/writing-resilient-components/"&gt;https://overreacted.io/writing-resilient-components/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summerize
&lt;/h2&gt;

&lt;p&gt;In my experience, if you learn a new language or it is essential to train it to get Professional. Train in the Job is not really an option. Mostly it leads to a not maintainable code base, and your Team and customer will be unhappy. From my point of view, it is beneficial to start with contributions to project like &lt;a href="https://github.com/magento/pwa-studio"&gt;PWA-Studio&lt;/a&gt;.&lt;br&gt;
I can recommend before you start a Headless Project, make sure your Team know about all Technologies.&lt;br&gt;
This means your Frontend Team should spend  2-3 days to get familiar with React. Also, you need an Expert what your Team lead and train show the gaps.&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Getting started with PWA Studio Extensibility</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Mon, 29 Jun 2020 22:00:00 +0000</pubDate>
      <link>https://dev.to/larsroettig/getting-started-with-pwa-studio-extensibility-3d5e</link>
      <guid>https://dev.to/larsroettig/getting-started-with-pwa-studio-extensibility-3d5e</guid>
      <description>&lt;p&gt;The 7.0 release improves on the extensibility framework. I want to prove if we can already build a real PWA extension or where we run in limitation. This blogpost contains two parts. The first part is about the technical strategies behind the Extensibility Apis. In the second part, we will write a small extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical strategies
&lt;/h2&gt;

&lt;p&gt;The new extensibility Apis allows extending Build pack, Peregrine, and Venia UI library components. The main goal is developers can make changes in storefront projects or standalone extensions without duplicating or maintaining the PWA-Studio code. The PageBuilder is integrated via targets. It is the first Magento Content plugin. Also, it is an excellent example of your plugins. For replacing or extend already existing ui components, we need a workaround currently. Replacing a part can be dangerous. It is not a compound change, so if two extensions both want to replace the same file, it can lead to errors. Currently, the Core Team doesn't want to support a fallback structure by default. From my perspective, we need a way how a plugin can register its new components to already existing ui components. PWA Studio packages should declare which of their ui-components are safe to replace and make them replaceable. A reliable replacement strategy will help that vendors can build Standalone Marketplace Extensions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Venia UI extension points
&lt;/h3&gt;

&lt;p&gt;Currently, it is allowed to add new routes or create a new richContentRenderers to create new blog plugin based on CMS like NEOS. The richContentRenderers are used to integrate the Magento Page Builder Plugin in PWA Studio.&lt;/p&gt;

&lt;p&gt;Dokumentation Link: &lt;a href="https://github.com/magento/pwa-studio/blob/release/7.0/packages/venia-ui/lib/targets/venia-ui-declare.js"&gt;https://github.com/magento/pwa-studio/blob/release/7.0/packages/venia-ui/lib/targets/venia-ui-declare.js&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Peregrine extension points
&lt;/h3&gt;

&lt;p&gt;We can now wrap any individual Peregrine talons when Peregrine talons are invoked, and/or to modify the behavior and output of those talons. Like the around plugin concept knowen as interceptor pattern of Magento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;targets.of('@magento/peregrine').talons.tap(talons =&amp;gt; {
    talons.App.useApp.wrapWith('./log-wrapper');
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;log-wrapper.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function wrapUseApp(original) {
    return function useApp(...args) {
        console.log('calling useApp with', ...args);
        return original(...args);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Build pack extension points
&lt;/h3&gt;

&lt;p&gt;These extension points are based on the Webpack Compiler Hooks. This the Webpack API is very well documented and often used to build plugins.&lt;/p&gt;

&lt;p&gt;Dokumentation Link: &lt;a href="https://github.com/magento/pwa-studio/blob/release/7.0/packages/peregrine/lib/targets/peregrine-declare.js"&gt;https://github.com/magento/pwa-studio/blob/release/7.0/packages/peregrine/lib/targets/peregrine-declare.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post contains interactive elements that are cannot be displayed on dev.to view it: &lt;a href="https://larsroettig.dev/getting-started-with-pwa-studio-extensibility/"&gt;https://larsroettig.dev/getting-started-with-pwa-studio-extensibility/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to create a GraphQL Mutation Endpoint for Magento 2.3</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Wed, 18 Mar 2020 09:59:56 +0000</pubDate>
      <link>https://dev.to/larsroettig/how-to-create-a-graphql-mutation-endpoint-for-magento-2-3-1mgk</link>
      <guid>https://dev.to/larsroettig/how-to-create-a-graphql-mutation-endpoint-for-magento-2-3-1mgk</guid>
      <description>&lt;p&gt;In my last Magento 2 tutorial, I showed how to build a basic GraphQL module with filtering.The primary purpose of GraphQL is to retrieve data (query), but every complete data exchange format needs a way to change server-based data (mutations).Therefore I want to show now how we can change data or create new pickup stores via the frontend.&lt;/p&gt;

&lt;p&gt;Currently, the Magento 2 GraphQL Endpoint supports only access controls based on customers. This GraphQL will only allow a queryon the customer data if the customer’s token must proived in the header section.&lt;/p&gt;

&lt;p&gt;Since I would like to show only exemplarily how such a thing could look, I did without access control!&lt;/p&gt;

&lt;p&gt;Before we can start here, you can find the first module that we need ground for this tutorial.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/larsroettig/how-to-create-a-graphql-endpoint-for-magento-2-3-2520"&gt;How to create a GraphQL Endpoint for Magento 2.3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/larsroettig/module-graphqlstorepickup/tree/1.0-develop"&gt;Github Repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new php file &lt;code&gt;app/code/LarsRoettig/GraphQLStorePickup/Model/Resolver/CreatPickUpStore.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This Class holds the logic for that endpoint is responsible for any GraphQL call that creates a new pickup store in the Database.Every Resolver Class is forced to implements &lt;code&gt;Magento\Framework\GraphQl\Query\ResolverInterface&lt;/code&gt; to work correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Model\Resolver;

use LarsRoettig\GraphQLStorePickup\Model\CreatePickUpStore as CreatPickUpStoreService;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

class CreatPickUpStore implements ResolverInterface
{
    /**
     * @var CreatPickUpStoreService
     */
    private $creatPickUpStore;

    /**
     * @param CreatPickUpStore $creatPickUpStore
     */
    public function __construct(CreatPickUpStoreService $creatPickUpStore)
    {
        $this-&amp;gt;creatPickUpStore = $creatPickUpStore;
    }

    /**
     * @inheritDoc
     */
    public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
    {
        if (empty($args['input']) || !is_array($args['input'])) {
            throw new GraphQlInputException(__('"input" value should be specified'));
        }

        return ['pick_up_store' =&amp;gt; $this-&amp;gt;creatPickUpStore-&amp;gt;execute($args['input'])];
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;File &lt;code&gt;app/code/LarsRoettig/GraphQLStorePickup/Model/CreatePickUpStore.php&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;The second step is to create a service class that will convert a given array to a pickup store and saves them in the database.A service class help us to have single small bussiness logic that can be used by differnt other php services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Model;

use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterface;
use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterfaceFactory;
use LarsRoettig\GraphQLStorePickup\Api\StoreRepositoryInterface;
use Magento\Framework\Api\DataObjectHelper;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;

class CreatePickUpStore
{

    /**
     * @var DataObjectHelper
     */
    private $dataObjectHelper;
    /**
     * @var StoreRepositoryInterface
     */
    private $storeRepository;
    /**
     * @var StoreInterfaceFactory
     */
    private $storeFactory;

    /**
     * @param DataObjectHelper $dataObjectHelper
     * @param StoreRepositoryInterface $storeRepository
     * @param StoreInterfaceFactory $storeInterfaceFactory
     */
    public function __construct(
        DataObjectHelper $dataObjectHelper,
        StoreRepositoryInterface $storeRepository,
        StoreInterfaceFactory $storeInterfaceFactory
    ) {
        $this-&amp;gt;dataObjectHelper = $dataObjectHelper;
        $this-&amp;gt;storeRepository = $storeRepository;
        $this-&amp;gt;storeFactory = $storeInterfaceFactory;
    }

    /**
     * @param array $data
     * @return StoreInterface
     * @throws GraphQlInputException
     */
    public function execute(array $data): StoreInterface
    {
        try {
            $this-&amp;gt;vaildateData($data);
            $store = $this-&amp;gt;saveStore($this-&amp;gt;createStore($data));
        } catch (\Exception $e) {
            throw new GraphQlInputException(__($e-&amp;gt;getMessage()));
        }

        return $store;
    }

    /**
     * Guard function to handle bad request.
     * @param array $data
     * @throws LocalizedException
     */
    private function vaildateData(array $data)
    {
        if (!isset($data[StoreInterface::NAME])) {
            throw new LocalizedException(__('Name must be set'));
        }
    }

    /**
     * Persists the given store in the data base.
     * +
     * @param StoreInterface $store
     * @return StoreInterface
     * @throws CouldNotSaveException
     */
    private function saveStore(StoreInterface $store): StoreInterface
    {
        $this-&amp;gt;storeRepository-&amp;gt;save($store);

        return $store;
    }

    /**
     * Create a store dto by given data array.
     *
     * @param array $data
     * @return StoreInterface
     * @throws CouldNotSaveException
     */
    private function createStore(array $data): StoreInterface
    {
        /** @var StoreInterface $store */
        $store = $this-&amp;gt;storeFactory-&amp;gt;create();
        $this-&amp;gt;dataObjectHelper-&amp;gt;populateWithArray(
            $store,
            $data,
            StoreInterface::class
        );

        return $store;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;File &lt;code&gt;app/code/LarsRoettig/GraphQLStorePickup/etc/schema.graphqls&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This need to be added to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Mutation {
    createPickUpStores(input: PickUpStoreInput!): PickUpStoreOutput @resolver(class: "\\LarsRoettig\\GraphQLStorePickup\\Model\\Resolver\\CreatPickUpStore") @doc(description: "Create a new pickup store")
}

type PickUpStoreOutput {
    pick_up_store: PickUpStore!
}

input PickUpStoreInput {
    name: String @doc(description: "")
    street: String @doc(description: "")
    street_num: Int @doc(description: "")
    city: String @doc(description: "")
    postcode: String @doc(description: "")
    latitude:Float @doc(description: "")
    longitude: Float @doc(description: "")
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Full File:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Query {
    pickUpStores(
        filter: PickUpStoresFilterInput @doc(description: "")
        pageSize: Int = 5 @doc(description: "How many items should show on the page")
        currentPage: Int = 1 @doc(description: "Allows to ussing paging it start with 1")
    ):PickUpStoresOutput @resolver(class: "\\LarsRoettig\\GraphQLStorePickup\\Model\\Resolver\\PickUpStores") @doc(description: "Allow to query for a pickup store.")
}

type Mutation {
    createPickUpStores(input: PickUpStoreInput!): PickUpStoreOutput @resolver(class: "\\LarsRoettig\\GraphQLStorePickup\\Model\\Resolver\\CreatPickUpStore") @doc(description: "Create a new pickup store")
}

type PickUpStoreOutput {
    pick_up_store: PickUpStore!
}

input PickUpStoreInput {
    name: String @doc(description: "")
    street: String @doc(description: "")
    street_num: Int @doc(description: "")
    city: String @doc(description: "")
    postcode: String @doc(description: "")
    latitude:Float @doc(description: "")
    longitude: Float @doc(description: "")
}

input PickUpStoresFilterInput {
    name: FilterTypeInput @doc(description: "")
    postcode: FilterTypeInput @doc(description: ""),
    street: FilterTypeInput @doc(description: ""),
    street_num: FilterTypeInput @doc(description: ""),
    city: FilterTypeInput @doc(description: ""),
    latitude:FilterTypeInput @doc(description: ""),
    longitude: FilterTypeInput @doc(description: ""),
    or: PickUpStoresFilterInput
}

type PickUpStoresOutput {
    total_count: Int @doc(description: "")
    items: [PickUpStore] @doc(description: "")
}

type PickUpStore {
    entity_id: Int @doc(description: ""),
    name: String @doc(description: ""),
    street: String @doc(description: ""),
    street_num: Int @doc(description: ""),
    city: String @doc(description: ""),
    postcode: String @doc(description: ""),
    latitude:Float @doc(description: ""),
    longitude: Float @doc(description: ""),
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Installation:
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/magento module:enable LarsRoettig_GraphQLStorePickup
bin/magento setup:db-declaration:generate-whitelist --module-name=LarsRoettig_GraphQLStorePickup
bin/magento setup:upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The repo bramch can founded at Github:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/larsroettig/module-graphqlstorepickup/tree/2.0-develop"&gt;https://github.com/larsroettig/module-graphqlstorepickup/tree/2.0-develop&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  How to call your GraphQL Endpoint
&lt;/h4&gt;

&lt;p&gt;Attention the Url &lt;a href="https://your%5C_domain.test/graphql"&gt;https://your\_domain.test/graphql&lt;/a&gt; work only with an valid GraphQL-Request!&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G6B7zHRS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/6468c42fd84a9ef9aa58df78b2df2b39/aaa41/graphql-playground_mutation.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G6B7zHRS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/6468c42fd84a9ef9aa58df78b2df2b39/aaa41/graphql-playground_mutation.jpg" alt="GrapQL Mutation" title="GrapQL Mutation Query"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GraphQL-Mutation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  createPickUpStores(
    input: {
      name: "Mustation Store"
      street: "sweswq"
      street_num: 12
      postcode: "83059"
      latitude: 22.3
      longitude:22.3
    }
  )
  {
    pick_up_store {
      name
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(This article was posted to my blog at &lt;a href="https://larsroettig.dev"&gt;https://larsroettig.dev&lt;/a&gt;. You can &lt;a href="https://larsroettig.dev/how-to-create-a-graph-ql-mutation-endpoint-for-magento-2-3"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Enable Notify me when this product is in stock in Magento 2</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Wed, 18 Mar 2020 09:53:46 +0000</pubDate>
      <link>https://dev.to/larsroettig/enable-notify-me-when-this-product-is-in-stock-in-magento-2-422b</link>
      <guid>https://dev.to/larsroettig/enable-notify-me-when-this-product-is-in-stock-in-magento-2-422b</guid>
      <description>&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iL5aXxbQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/a09ce3b24d29092aabbb330136d6f3ef/aaa41/magento2_notify_frontend.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iL5aXxbQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/a09ce3b24d29092aabbb330136d6f3ef/aaa41/magento2_notify_frontend.jpg" alt="Magento frontend with notify links" title="Magento frontend with notify links"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;p&gt;This feature is available in Magento 2 Open Source, Commerce and B2B&lt;/p&gt;

&lt;p&gt;As Merchant, you can enable this feature for registered customers.It allowed subscribing to two types of alerts, first is price change alert, and the sound is in-stock alert.For each alert example, you can choose a different email template.&lt;/p&gt;

&lt;h3&gt;
  
  
  Allow show Display Out of Stock Products
&lt;/h3&gt;

&lt;p&gt;Stores/Catalog/Inventory/&lt;b&gt;Display Out of Stock Products Option&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jq-ApzP7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/f94f850406e7c9c1ec6be8afe58cefbf/aaa41/display_out_of_stock_products_option.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jq-ApzP7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/f94f850406e7c9c1ec6be8afe58cefbf/aaa41/display_out_of_stock_products_option.jpg" alt="Magento backend display out of stock products option" title="Magento backend display out of stock products option"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;h3&gt;
  
  
  Enable Allow alert when product comes back in stock
&lt;/h3&gt;

&lt;p&gt;Stores/Catalog/Catalog/Product Alerts/Allow Alert When Product Comes Back in Stock&lt;br&gt;
&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2JQdHYyE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/06f2c591789f5691aefc4066c7eaaf66/aaa41/allow_alert_when_product_comes_back_in_Stock.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2JQdHYyE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/06f2c591789f5691aefc4066c7eaaf66/aaa41/allow_alert_when_product_comes_back_in_Stock.jpg" alt="Enable Allow alert when product comes back in stock" title="Enable Allow alert when product comes back in stock"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;h3&gt;
  
  
  Optional Step
&lt;/h3&gt;

&lt;p&gt;With the Frequency settings, it possible to change how often Magento checks for changes that require alerts sent to the subscribers.&lt;/p&gt;

&lt;p&gt;Stores/Catalog/Catalog/Product Alerts Run Settings/&lt;b&gt;Frequency&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The in-stock alert setting creates a link called “Notify me when this product is in stock” for every product that is out of stock. Customers can click the link to subscribe to the alert. When the product is back in stock, customers receive an email notification that the product is available.&lt;/p&gt;

&lt;p&gt;Attention the Mail is only sent by the configured time (Magento cron job).&lt;/p&gt;

&lt;p&gt;Products with alerts have a Product Alerts sections in the Product Information panel that lists the customers who have subscribed to an alarm.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z34enPED--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/d1759479cccedb688b454038db0e8836/aaa41/mail_backend.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z34enPED--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/d1759479cccedb688b454038db0e8836/aaa41/mail_backend.jpg" alt="mail_backend" title="mail_backend"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://docs.magento.com/m1/ce/user_guide/catalog/inventory-product-alert.html"&gt;Magento 1 Documentation Product Alerts Magento 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.magento.com/m1/ce/user_guide/catalog/inventory-product-alert-run-settings.html"&gt;Documentation Scheduling Product Alerts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(This article was posted to my blog at &lt;a href="https://larsroettig.dev"&gt;https://larsroettig.dev&lt;/a&gt;. You can &lt;a href="https://larsroettig.dev/enable-notify-me-when-this-product-is-in-stock-in-magento-2"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Getting started with Magento PWA Studio</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Wed, 11 Mar 2020 21:04:42 +0000</pubDate>
      <link>https://dev.to/larsroettig/getting-started-with-magento-pwa-studio-3ehd</link>
      <guid>https://dev.to/larsroettig/getting-started-with-magento-pwa-studio-3ehd</guid>
      <description>&lt;p&gt;I want to divide this blog post into two parts. The first part is more from the business side. Is PWA the right technology for me?In the second part, I will explain how you can build your own build your own PWA Theme for Magento 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is PWA the right technology for my requirements
&lt;/h2&gt;

&lt;p&gt;As with all software, it should start with the &lt;strong&gt;why&lt;/strong&gt;. What can a customer or a developer expect from a PWA Studio project? In my experience, when new technology appears, stakeholders do not ask about any added business values or requirements. &lt;strong&gt;What&lt;/strong&gt; is the advantage of using this new shining technology? PWA Studio storefronts enhance the user experience, especially if the target customer group uses smartphones or modern browsers. Google page ranking, loading speed, and offline support(to handle short interruptions) are important reasons online businesses should consider PWA storefronts.&lt;/p&gt;

&lt;p&gt;Questions online businesses should ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are the target group of my PWA Project&lt;/li&gt;
&lt;li&gt;Which features I need for an MVP

&lt;ul&gt;
&lt;li&gt;Payments&lt;/li&gt;
&lt;li&gt;Shipping methods&lt;/li&gt;
&lt;li&gt;Language support&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As already mentioned in my previous &lt;a href="https://dev.to/larsroettig/a-review-of-magento-pwa-studio-118a"&gt;blog post&lt;/a&gt;, it is useful to now with a small project to gather experience with the new PWA. But it would be best if you thought about what you need and what helps to earn more money or meet your business goals.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create an own PWA Studio Theme
&lt;/h2&gt;

&lt;p&gt;Basic requisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Essential Experience with React, HTML, CSS, Webpack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From my point of view, there currently two ways to start with a project. Project scaffolding default supported by Magento Core Team and Fallback Studio by Jordan Eisenburger. Fallback Studio creates a wrapper around&lt;a href="https://github.com/magento/pwa-studio" rel="noopener noreferrer"&gt;PWA Studio&lt;/a&gt;). It provides a basic fallback structure. So you can develop storefronts that depend on the venia-concept storefront. It also supports scss.&lt;/p&gt;

&lt;p&gt;You can find the project here: &lt;a href="https://github.com/Jordaneisenburger/fallback-studio" rel="noopener noreferrer"&gt;https://github.com/Jordaneisenburger/fallback-studio&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a PWA Theme with Scaffolding
&lt;/h3&gt;

&lt;p&gt;In this tutorial, we are going to extend the &lt;em&gt;Main&lt;/em&gt; and create our &lt;em&gt;TopBar&lt;/em&gt; component as the first element to our site.&lt;/p&gt;

&lt;p&gt;PWA Studio comes with a Project scaffolding command, and this is a technique for auto-generating support for your project/theme. Early adopters of the PWA Studio project &lt;strong&gt;forked&lt;/strong&gt; , and the Core Team recommends to don’t use this practice. With scaffolding, we should have the opportunity to build our own PWA Theme on top of Magento 2. The full documentation of &lt;a href="[https://magento.github.io/pwa-studio/pwa-buildpack/scaffolding"&gt;https://magento.github.io/pwa-studio/pwa-buildpack/scaffolding/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Command to create a new Project:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn create @magento/pwa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;It should look like:&lt;/strong&gt; &lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flarsroettig.dev%2Fstatic%2Fd61f9cc56a74fbda66133ae6246268fd%2Faaa41%2FCreate_PWA.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%2Flarsroettig.dev%2Fstatic%2Fd61f9cc56a74fbda66133ae6246268fd%2Faaa41%2FCreate_PWA.jpg" alt="Create_PWA" title="Create_PWA"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;
&lt;h4&gt;
  
  
  Overwrite/Extend PWA Studio default component
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Create the library dir and copy main component:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd myproject
mkdir -p src/lib/components/
cp -R node_modules/@magento/venia-ui/lib/components/Main src/lib/components/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Update Main Component:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/lib/components/Main/main.js
import React from 'react'
import { bool, shape, string } from 'prop-types'
import { useScrollLock } from '@magento/peregrine'
import { mergeClasses } from '@magento/venia-ui/lib/classify'import Footer from '@magento/venia-ui/lib/components/Footer'import Header from '@magento/venia-ui/lib/components/Header'
import defaultClasses from './main.css'

const Main = props =&amp;gt; {
    const { children, isMasked } = props;
    const classes = mergeClasses(defaultClasses, props.classes);

    const rootClass = isMasked ? classes.root_masked : classes.root;
    const pageClass = isMasked ? classes.page_masked : classes.page;

    useScrollLock(isMasked);

    return (
        &amp;lt;main className={rootClass}&amp;gt;
            &amp;lt;div&amp;gt;Static Block for TopBar&amp;lt;/div&amp;gt;
            &amp;lt;Header /&amp;gt;
            &amp;lt;div className={pageClass}&amp;gt;{children}&amp;lt;/div&amp;gt;
            &amp;lt;Footer /&amp;gt;
        &amp;lt;/main&amp;gt;
    );
};

export default Main;

Main.propTypes = {
    classes: shape({
        page: string,
        page_masked: string,
        root: string,
        root_masked: string
    }),
    isMasked: bool
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a overwrite webpack plugin:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// webpack.config.js

const path = require('path');
const glob = require('glob');

module.exports = class NormalModuleOverridePlugin {
  constructor(moduleOverrideMap) {
  this.name = 'NormalModuleOverridePlugin';
        this.moduleOverrideMap = moduleOverrideMap;
    }

  requireResolveIfCan(id, options = undefined) {
  try {
  return require.resolve(id, options);
        } catch (e) {
  return undefined;
        }
 }
  resolveModulePath(context, request) {
  const filePathWithoutExtension = path.resolve(context, request);
        const files = glob.sync(`${filePathWithoutExtension}@(|.*)`);
        if (files.length === 0) {
  throw new Error(`There is no file '${filePathWithoutExtension}'`);
        }
  if (files.length &amp;gt; 1) {
  throw new Error(
  `There is more than one file '${filePathWithoutExtension}'`
 );
        }

  return require.resolve(files[0]);
    }

  resolveModuleOverrideMap(context, map) {
  return Object.keys(map).reduce(
 (result, x) =&amp;gt; ({
  ...result,
                [require.resolve(x)]:
                this.requireResolveIfCan(map[x]) ||
 this.resolveModulePath(context, map[x])
 }),
            {}
 );
    }

  apply(compiler) {
  if (Object.keys(this.moduleOverrideMap).length === 0) {
  return;
        }

  const moduleMap = this.resolveModuleOverrideMap(
  compiler.context,
            this.moduleOverrideMap
  );

        compiler.hooks.normalModuleFactory.tap(this.name, nmf =&amp;gt; {
  nmf.hooks.beforeResolve.tap(this.name, resolve =&amp;gt; {
  if (!resolve) {
  return;
                }

  const moduleToReplace = this.requireResolveIfCan(
  resolve.request,
                    { paths: [resolve.context] }
 );
                if (moduleToReplace &amp;amp;&amp;amp; moduleMap[moduleToReplace]) {
  resolve.request = moduleMap[moduleToReplace];
                }

  return resolve;
            });
        });
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create overwrite mapping file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//componentOverrideMapping.js module.exports = componentOverride = {
 [`@magento/venia-ui/lib/components/Main`]: 'src/lib/components/Main' };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Register the webpack plugin:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// webpack.config.js
const {
  configureWebpack,
    graphQL: { getMediaURL, getUnionAndInterfaceTypes }
} = require('@magento/pwa-buildpack');
const { DefinePlugin } = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const moduleOverridePlugin = require('./moduleOverrideWebpackPlugin');
const componentOverrideMapping = require('./componentOverrideMapping');

module.exports = async env =&amp;gt; {
  const mediaUrl = await getMediaURL();

    global.MAGENTO_MEDIA_BACKEND_URL = mediaUrl;

    const unionAndInterfaceTypes = await getUnionAndInterfaceTypes();

    const { clientConfig, serviceWorkerConfig } = await configureWebpack({
  context: __dirname,
        vendor: [
  '@apollo/react-hooks',
            'apollo-cache-inmemory',
            'apollo-cache-persist',
            'apollo-client',
            'apollo-link-context',
            'apollo-link-http',
            'informed',
            'react',
            'react-dom',
            'react-feather',
            'react-redux',
            'react-router-dom',
            'redux',
            'redux-actions',
            'redux-thunk'
 ],
        special: {
  'react-feather': {
  esModules: true
 },
            '@magento/peregrine': {
  esModules: true,
                cssModules: true
 },
            '@magento/venia-ui': {
  cssModules: true,
                esModules: true,
                graphqlQueries: true,
                rootComponents: true,
                upward: true
 }
 },
        env
    });

    /**
* configureWebpack() returns a regular Webpack configuration object. * You can customize the build by mutating the object here, as in * this example. Since it's a regular Webpack configuration, the object * supports the `module.noParse` option in Webpack, documented here: * https://webpack.js.org/configuration/module/#modulenoparse */ clientConfig.module.noParse = [/braintree\-web\-drop\-in/];
    clientConfig.plugins = [
  ...clientConfig.plugins,
        new DefinePlugin({
  /**
* Make sure to add the same constants to * the globals object in jest.config.js. */ UNION_AND_INTERFACE_TYPES: JSON.stringify(unionAndInterfaceTypes),
            STORE_NAME: JSON.stringify('Venia')
 }),
        new HTMLWebpackPlugin({
  filename: 'index.html',
            template: './template.html',
            minify: {
  collapseWhitespace: true,
                removeComments: true
 }
 }) ];

    clientConfig.plugins.push( new moduleOverridePlugin(componentOverrideMapping) );
    return [clientConfig, serviceWorkerConfig];
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Execute Watch Command:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; &lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flarsroettig.dev%2Fstatic%2F4a946b9846829df590bf5f1c57e3b89d%2Fd4ec0%2FOwrite_Test_1.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%2Flarsroettig.dev%2Fstatic%2F4a946b9846829df590bf5f1c57e3b89d%2Fd4ec0%2FOwrite_Test_1.jpg" alt="Owrite_Test_1" title="Owrite_Test_1"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;h4&gt;
  
  
  Create your own PWA Component
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/lib/components/TopBar/topbar.css
.root
{
  background-color: rgb(var(--venia-teal));
  padding: 0.5rem;
  color: #fff;
  display: flex;
  justify-content: center;
}

// src/lib/components/TopBar/topbar.js
import React from 'react'
import { shape, string } from 'prop-types'
import { mergeClasses } from '@magento/venia-ui/lib/classify'

import defaultClasses from './topbar.css'

const TopBar = props =&amp;gt; {
    const classes = mergeClasses(defaultClasses, props.classes);
    return (
        &amp;lt;div className={classes.root}&amp;gt;
 Your first custom react component &amp;lt;/div&amp;gt;
  )
};

TopBar.propTypes = {
    classes: shape({
        root: string,
    })
};

export default TopBar;

// src/lib/components/TopBar/index.js
export { default } from './topbar';

// src/lib/components/Main/main.js
import React from 'react'
import { bool, shape, string } from 'prop-types'
import { useScrollLock } from '@magento/peregrine'

import { mergeClasses } from '@magento/venia-ui/lib/classify'
import Footer from '@magento/venia-ui/lib/components/Footer'
import Header from '@magento/venia-ui/lib/components/Header'
import defaultClasses from './main.css'
import TopBar from "../TopBar";
const Main = props =&amp;gt; {
    const { children, isMasked } = props;
    const classes = mergeClasses(defaultClasses, props.classes);

    const rootClass = isMasked ? classes.root_masked : classes.root;
    const pageClass = isMasked ? classes.page_masked : classes.page;

    useScrollLock(isMasked);

    return (
        &amp;lt;main className={rootClass}&amp;gt;
  &amp;lt;TopBar/&amp;gt; &amp;lt;Header /&amp;gt;
  &amp;lt;div className={pageClass}&amp;gt;{children}&amp;lt;/div&amp;gt;
  &amp;lt;Footer /&amp;gt;
  &amp;lt;/main&amp;gt;
  );
};

export default Main;

Main.propTypes = {
    classes: shape({
        page: string,
        page_masked: string,
        root: string,
        root_masked: string
    }),
    isMasked: bool
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; &lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flarsroettig.dev%2Fstatic%2Fbf16d75fd73091b94004246916e8e74d%2Faaa41%2FOwrite_Test_2.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%2Flarsroettig.dev%2Fstatic%2Fbf16d75fd73091b94004246916e8e74d%2Faaa41%2FOwrite_Test_2.jpg" alt="Owrite_Test_2" title="Owrite_Test_2"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In my opinion, starting a new PWA Studio project using the scaffolding command is the best approach for setting up a maintainable project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips and Tricks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SEO&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For JavaScript applications, it essential to use Server-Side Rendering (SSR). The benefit of using SSR isthe website content can crawl from crawlers that don’t execute JavaScript code. I recommend using tools like &lt;a href="//prerender.io"&gt;prerender.io&lt;/a&gt; or &lt;a href="//seosnap.io"&gt;seosnap.io&lt;/a&gt;.When you use SSR to mind those errors, the request still can returns a 200 status code.You don’t want these to cached by Rendertron or Seosnap your need to set &lt;code&gt;&amp;lt;meta name="render:status_code" content="404" /&amp;gt;&lt;/code&gt; at the appropriate places.&lt;/p&gt;

&lt;p&gt;(This article was posted to my blog at &lt;a href="https://larsroettig.dev" rel="noopener noreferrer"&gt;https://larsroettig.dev&lt;/a&gt;. You can &lt;a href="https://larsroettig.dev/getting-started-with-magento-pwa-studio" rel="noopener noreferrer"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Review of Magento PWA Studio</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Wed, 26 Feb 2020 23:40:15 +0000</pubDate>
      <link>https://dev.to/larsroettig/a-review-of-magento-pwa-studio-118a</link>
      <guid>https://dev.to/larsroettig/a-review-of-magento-pwa-studio-118a</guid>
      <description>&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1bTjPlD4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/e07126a21bad2d2ef181159498f93859/aaa41/PWA_Studio_Teaser.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1bTjPlD4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/e07126a21bad2d2ef181159498f93859/aaa41/PWA_Studio_Teaser.jpg" alt="PWA_Studio_Teaser" title="PWA_Studio_Teaser"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;p&gt;Before we start, I want to provide a short overview of the PWA Studio architecture. With Magento PWA Studio, we should have the opportunity to build a complex Progressive Web Applications on top of Magento 2. Can we already realize &lt;strong&gt;real&lt;/strong&gt; customer &lt;strong&gt;projects&lt;/strong&gt; with PWA Studio? I would like to have a look at that with you. This blog post will be updated at regular intervals.The Magento Core Team selected &lt;strong&gt;React&lt;/strong&gt; ( &lt;strong&gt;JavaScript&lt;/strong&gt; ), &lt;strong&gt;GraphQL&lt;/strong&gt; , &lt;strong&gt;CSS Modules&lt;/strong&gt; as the leading technologies to build this theme to build from scratch.&lt;/p&gt;

&lt;p&gt;Magento PWA Studio uses a Monorepo structure.For those reasons, after checkout, we already see ten subfolders.They packages are most likely unrelated, loosely connected, or connected. To give an example, &lt;strong&gt;venia-ui&lt;/strong&gt; needs elements from &lt;strong&gt;peregrine&lt;/strong&gt;. Let’s take a look at which components we have in the current state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Main Libraries&lt;/strong&gt; If we start our a PWA-Project, we mostly change components from these two libraries to have our own PWA theme.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;peregrine&lt;/strong&gt; - A component library for adding logic to visual elements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;venia-ui&lt;/strong&gt; - Library of React Component for PWA storefront projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Elements for building&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;pwa-buildpack&lt;/strong&gt; - A tooling library to help with PWA storefront development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;upward-spec&lt;/strong&gt; - UPWARD specification and test suite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;upward-js&lt;/strong&gt; - A reference implementation of the UPWARD specification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;babel-preset-peregrine&lt;/strong&gt; - A babel preset plugin that is required to use peregrine components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;graphql-cli-validate-magento-pwa-queries&lt;/strong&gt; - A script to validate your project’s GraphQL queries against a schema&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Other elements&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;venia-styleguide&lt;/strong&gt; - The style guide for venia components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;venia-concept&lt;/strong&gt; - A concept storefront project built using PWA Studio tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pwa-devdocs&lt;/strong&gt; - Source for the documentation site (&lt;a href="http://pwastudio.io/"&gt;http://pwastudio.io/&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Current features in PWA Studio version 5.0
&lt;/h2&gt;

&lt;p&gt;Currently, the PWA Studio offers a small collection of tools and components.For me, it is a library that allows building a custom PWA Theme for Magento.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support Simple and Configurable Product&lt;/li&gt;
&lt;li&gt;Category Page&lt;/li&gt;
&lt;li&gt;CMS Pages and Blocks&lt;/li&gt;
&lt;li&gt;Magento PageBuilder&lt;/li&gt;
&lt;li&gt;Product Detail Page&lt;/li&gt;
&lt;li&gt;Cart&lt;/li&gt;
&lt;li&gt;Checkout&lt;/li&gt;
&lt;li&gt;Page Builder integration&lt;/li&gt;
&lt;li&gt;Braintree payment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Release Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/magento/pwa-studio/releases/tag/v5.0.0"&gt;https://github.com/magento/pwa-studio/releases/tag/v5.0.0&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Release 5.0.1
&lt;/h3&gt;

&lt;p&gt;PWA Studio 5.0.1 is a patch release to fix an Image loading issue. Also, a security fix prevents invalid mutation caching.With &lt;code&gt;fetchPolicy: 'no-cache'&lt;/code&gt; it is possible to define mutation the should not be added to Apollo query cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For more Information see:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.apollographql.com/docs/react/caching/cache-interaction/#bypassing-the-cache"&gt;https://www.apollographql.com/docs/react/caching/cache-interaction/#bypassing-the-cache&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/magento/pwa-studio/releases/tag/v5.0.0"&gt;https://github.com/magento/pwa-studio/releases/tag/v5.0.1&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Features that are currently not supported
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sort and Filters on the category and search page (Planned for v6)&lt;/li&gt;
&lt;li&gt;Payment Methods for Central European Market&lt;/li&gt;
&lt;li&gt;Deployment scripts&lt;/li&gt;
&lt;li&gt;”More” Extension Points

&lt;ul&gt;
&lt;li&gt;build&lt;/li&gt;
&lt;li&gt;env valid&lt;/li&gt;
&lt;li&gt;talon&lt;/li&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Shipping methods&lt;/li&gt;
&lt;li&gt;Wishlist&lt;/li&gt;
&lt;li&gt;Translation support&lt;/li&gt;
&lt;li&gt;Bundle product support&lt;/li&gt;
&lt;li&gt;Multi-Store support of multi-currency, and languages&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Although the project is still in an early stage of development, the PWA Studio already offers a toolkit for creating a PWA theme. Due to the lack of extension points and multilingualism, you will have to write many React extensions yourself, which can make large projects very complicated and expensive.With build things from scratch, it is possible to ignore legacy problems and create new great ideas. On the other hand, it takes a long time to get a stable software anyway with a production-ready feature set.From my point of view, it is good to now with a small project to gather experience with the new PWA Studio even there are already a few bigger projects live.&lt;/p&gt;

&lt;p&gt;(This article was posted to my blog at &lt;a href="https://larsroettig.dev"&gt;https://larsroettig.dev&lt;/a&gt;. You can &lt;a href="https://larsroettig.dev/a-review-of-magento-pwa-studio"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to write proper Software Documentation?</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Mon, 06 Jan 2020 20:42:24 +0000</pubDate>
      <link>https://dev.to/larsroettig/how-to-write-proper-software-documentation-1kj6</link>
      <guid>https://dev.to/larsroettig/how-to-write-proper-software-documentation-1kj6</guid>
      <description>&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7xN2az-j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/fe0ba0877e14285fc241b9ef41337702/2705d/Software_Documentation_Teaser.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7xN2az-j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/fe0ba0877e14285fc241b9ef41337702/2705d/Software_Documentation_Teaser.jpg" alt="Software_Documentation_Teaser" title="Software_Documentation_Teaser"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;p&gt;Whenever I talk to developers at conferences, I hear about the topic of software documentation mostly to the following phrase.Well, we had to finish it quickly, and there was no time left for documentation. But is documentation essential or not and what we should know about this topic?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is Software Documentation underestimated?
&lt;/h2&gt;

&lt;p&gt;In my experience, most developers underestimated the &lt;strong&gt;value&lt;/strong&gt; of proper software documentation. Back in the time as a junior developer, I also took every opportunity to avoid documentation. So the documentation for certain features was the code and me.&lt;/p&gt;

&lt;p&gt;As you can imagine, this behaviour leads to many problems, and I had to realize that the code alone is not enough. Especially if you want to take a vacation or need additional developers in the team, missing documentation is terrible. Unfortunately, writing documentation is not much fun as building new great things for the customer.&lt;/p&gt;

&lt;p&gt;For me, as a developer, documentation, and communication have become one of the essential skills a good software developer needs. But what does it mean to attribute proper documentation, and what is the minimum requirement for us as developers? This question I try to answer in the next section. There are many articles about software documentation and literature. I will summarize things that help me to write better documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements for effective documentation
&lt;/h3&gt;

&lt;p&gt;The first thing I had to understand was that documentation valuable for your &lt;strong&gt;customer&lt;/strong&gt; and &lt;strong&gt;team&lt;/strong&gt;.This enlightenment helped me to get a better feeling if I have to write documentation.&lt;/p&gt;

&lt;p&gt;For new documentation, I try to be a focus on for &lt;strong&gt;whom&lt;/strong&gt; I write the documentation.A typical project team consists of a vast number of stakeholders, including customer employees, product owners, developers, and many more that are needed to develop a project successfully.&lt;/p&gt;

&lt;p&gt;If we define the team in this way, we quickly realize that we need different documentation for the different roles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The editor wants to know how to maintain new features.&lt;/li&gt;
&lt;li&gt;The product owner needs contact persons to coordinate the requirements.&lt;/li&gt;
&lt;li&gt;The developer needs guidance on how to set up the development environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just examples to show how different documentation can be. With the help of the following questions, you can put yourself in the role of the person.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who has to read this documentation?&lt;/li&gt;
&lt;li&gt;What needs the reader to know about this?&lt;/li&gt;
&lt;li&gt;What will the reader get done?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my experience, a little documentation focus on a problem is better than a 70-page document that covers all aspects!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Variation of questions and example answers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For whom am I writing this documentation?

&lt;ul&gt;
&lt;li&gt;So that the editors can maintain the content without help&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What do I want to document?

&lt;ul&gt;
&lt;li&gt;A process of how an editor can edit or change the content in the system.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Readable documentation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From my perspective, software documentation is sometimes not readable, or I can not find any useful information. I search for a way to make my docs better. I found Beth Aitman blog post&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read Tip: &lt;/strong&gt;Writing effective documentation - the Lead Developer Berlin 2019&lt;/p&gt;

&lt;p&gt;6 Tips to make your software documentation great!&lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://bethaitman.com/posts/tld-2019/" rel="nofollow noopener noreferrer"&gt;https://bethaitman.com/posts/tld-2019/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;She has a great stragigie I try it out it work well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write outline first&lt;/li&gt;
&lt;li&gt;Add useful information in bullet point or nots to answering the outline&lt;/li&gt;
&lt;li&gt;Add more details and than structure it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full talk you can find at: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube-nocookie.com/embed/R6zeikbTgVc"&gt;https://www.youtube-nocookie.com/embed/R6zeikbTgVc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example of cupcakes backing documentation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mL7y8lQK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/995bc5134e829af195339c16ed5b9441/ad6c2/cupcake_sample.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mL7y8lQK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/995bc5134e829af195339c16ed5b9441/ad6c2/cupcake_sample.jpg" alt="Example documentation for making cupcakes" title="Example documentation for making cupcakes"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;p&gt;This example shows that a structure helps the user to understand what he gets after backing. Add helpful graphics and pictures in the documentation!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For architecture communication and documentation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I started using the templates from arc42. This template helps to have an excellent structure for this kind of documentation.&lt;/p&gt;

&lt;p&gt;Example Table of Contents by arc42:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Introduction and Goals&lt;/li&gt;
&lt;li&gt;Architecture Constraints&lt;/li&gt;
&lt;li&gt;System Scope and Context&lt;/li&gt;
&lt;li&gt;Solution Strategy&lt;/li&gt;
&lt;li&gt;Building Block View&lt;/li&gt;
&lt;li&gt;Runtime View&lt;/li&gt;
&lt;li&gt;Deployment View&lt;/li&gt;
&lt;li&gt;Concepts&lt;/li&gt;
&lt;li&gt;Design Decisions&lt;/li&gt;
&lt;li&gt;Quality Scenarios&lt;/li&gt;
&lt;li&gt;Technical Risks&lt;/li&gt;
&lt;li&gt;Glossary&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Templates you can download at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arc42.org/download"&gt;https://arc42.org/download&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;For me should have proper software documentation the following attributes. &lt;strong&gt;Maintainable&lt;/strong&gt;, this means easy and quick to adjustable if something is changed in the project. &lt;strong&gt;Up-to-date and correct&lt;/strong&gt; all changes need to be written down. &lt;strong&gt;Understandable and readable&lt;/strong&gt; you should use the same terms every time and have explanations of terms. &lt;strong&gt;Focus&lt;/strong&gt; on the target group of readers answer, the questions of your readers, the documentation should help get things done! &lt;strong&gt;Compact&lt;/strong&gt; and &lt;strong&gt;low cost&lt;/strong&gt; concentrating on the essential facts for your reader.&lt;/p&gt;

&lt;h3&gt;
  
  
  Good ressources over software documentation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bethaitman.com/posts/tld-2019/"&gt;https://bethaitman.com/posts/tld-2019/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=R6zeikbTgVc"&gt;https://www.youtube.com/watch?v=R6zeikbTgVc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leanpub.com/arc42inpractice"&gt;https://leanpub.com/arc42inpractice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arc42.org/"&gt;https://arc42.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(This article was posted to my blog at &lt;a href="https://larsroettig.dev"&gt;https://larsroettig.dev&lt;/a&gt;. You can &lt;a href="https://larsroettig.dev/how-to-write-proper-software-documentation"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to create a GraphQL Endpoint for Magento 2.3</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Sun, 03 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/larsroettig/how-to-create-a-graphql-endpoint-for-magento-2-3-2520</link>
      <guid>https://dev.to/larsroettig/how-to-create-a-graphql-endpoint-for-magento-2-3-2520</guid>
      <description>&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qc_47iFI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/5138abb2995d746ba613de2a24c05826/0f6c6/store-984393_1920.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qc_47iFI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/5138abb2995d746ba613de2a24c05826/0f6c6/store-984393_1920.jpg" alt="Store Sample" title="GrapQL Editor"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;p&gt;In this tutorial, I will show how you can build your GraphQL for Magento 2.3 and extend them with a filter logic. Our use case is a Pickup from Store endpoint what our frontend team needs to create an interactive map.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the story, we have the following acceptance criteria.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a frontend developer, I need Endpoint to search for the next Pickup Store in a Postcode Area. Use a setup script initial import Allow search for Postcode or Name. API will return the following attributes for a Pickup Store&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Arrribute Name&lt;/th&gt;
&lt;th&gt;GraphQL field&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Postcode&lt;/td&gt;
&lt;td&gt;postcode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Street&lt;/td&gt;
&lt;td&gt;street&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Street Number&lt;/td&gt;
&lt;td&gt;street_num&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;City&lt;/td&gt;
&lt;td&gt;city&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Longitude&lt;/td&gt;
&lt;td&gt;longitude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latitude&lt;/td&gt;
&lt;td&gt;latitude&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;System Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installed &lt;a href="https://devdocs.magento.com/guides/v2.3/install-gde/composer.html"&gt;Magento 2.3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PHP 7.1 | 7.2 | 7.3&lt;/li&gt;
&lt;li&gt;Mysql 5.6&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Lokal Development I Recommended use Development Mode: Run the following comand &lt;code&gt;bin/magento deploy:mode:set developer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table of Content:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to create the basis Magento 2 Module&lt;/li&gt;
&lt;li&gt;How add Magento 2 GraphQL specific impelemention&lt;/li&gt;
&lt;li&gt;Github Repo and how to install&lt;/li&gt;
&lt;li&gt;How to use GraphQL with Magento&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  1. How to create the basis Magento 2 Module
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This section is not GraphQL specific and and apply to any Magento2 Module!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this part, we learn how to created a new Database table and fill this with some sample data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write and Repository Pattern for Magento 2&lt;/li&gt;
&lt;li&gt;Write Database Model and Collection&lt;/li&gt;
&lt;li&gt;Write and Setup &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets start with new Folder under &lt;strong&gt;app/code/LarsRoettig/GraphQLStorePickup&lt;/strong&gt; in your installed magento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. registration.php - Path: (app/code/LarsRoettig/GraphQLStorePickup/registration.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

declare(strict_types=1);

Magento\Framework\Component\ComponentRegistrar::register(
    Magento\Framework\Component\ComponentRegistrar::MODULE,
    'LarsRoettig_GraphQLStorePickup',
    __DIR__
);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. module.xml - Path: (app/code/LarsRoettig/GraphQLStorePickup/etc/module.xml)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" ?&amp;gt;
&amp;lt;config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"&amp;gt;
    &amp;lt;module name="LarsRoettig_GraphQLStorePickup" setup_version="1.0.0"&amp;gt;
        &amp;lt;sequence&amp;gt;
            &amp;lt;module name="Magento_GraphQl"/&amp;gt;
        &amp;lt;/sequence&amp;gt;
    &amp;lt;/module&amp;gt;
&amp;lt;/config&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.Create new Database Table with db_schema.xml - Path: (app/code/LarsRoettig/GraphQLStorePickup/etc/db_schema.xml)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"&amp;gt;
    &amp;lt;table name="pickup_stores" resource="default" engine="innodb" comment="Pick Up Stores"&amp;gt;
        &amp;lt;column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="true"
                comment="Entity ID"/&amp;gt;
        &amp;lt;column xsi:type="varchar" name="name" nullable="true" length="64"/&amp;gt;
        &amp;lt;column xsi:type="varchar" name="street" nullable="true" length="64"/&amp;gt;
        &amp;lt;column xsi:type="int" name="street_num" nullable="true"/&amp;gt;
        &amp;lt;column xsi:type="varchar" name="city" nullable="true" length="64"/&amp;gt;
        &amp;lt;column xsi:type="varchar" name="postcode" nullable="true" length="10"/&amp;gt;
        &amp;lt;column xsi:type="decimal" name="latitude" default="0" scale="4" precision="20" /&amp;gt;
        &amp;lt;column xsi:type="decimal" name="longitude" default="0" scale="4" precision="20" /&amp;gt;
        &amp;lt;constraint xsi:type="primary" referenceId="PRIMARY"&amp;gt;
            &amp;lt;column name="entity_id"/&amp;gt;
        &amp;lt;/constraint&amp;gt;
    &amp;lt;/table&amp;gt;
&amp;lt;/schema&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Store Interface - Path: (app/code/LarsRoettig/GraphQLStorePickup/Api/Data/StoreInterface.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Api\Data;

/**
 * Represents a store and properties
 *
 * @api
 */
interface StoreInterface
{
    /**
     * Constants for keys of data array. Identical to the name of the getter in snake case
     */
    const NAME = 'name';
    const STREET = 'street';
    const STREET_NUM = 'street_num';
    const CITY = 'city';
    const POSTCODE = 'postcode';
    const LATITUDE = 'latitude';
    const LONGITUDE = 'longitude';

    /**#@-*/

    public function getName(): ?string;

    public function setName(?string $name): void;

    public function getStreet(): ?string;

    public function setStreet(?string $street): void;

    public function getStreetNum(): ?int;

    public function setStreetNum(?int $streetNum): void;

    public function getCity(): ?string;

    public function setCity(?string $city): void;

    public function getPostCode(): ?int;

    public function setPostcode(?int $postCode): void;

    public function getLatitude(): ?float;

    public function setLatitude(?float $latitude): void;

    public function getLongitude(): ?float;

    public function setLongitude(?float $longitude): void;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Model - Path: (app/code/LarsRoettig/GraphQLStorePickup/Model/Store.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Model;

use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterface;
use LarsRoettig\GraphQLStorePickup\Model\ResourceModel\Store as StoreResourceModel;
use Magento\Framework\Model\AbstractExtensibleModel;

class Store extends AbstractExtensibleModel implements StoreInterface
{

    protected function _construct()
    {
        $this-&amp;gt;_init(StoreResourceModel::class);
    }

    public function getName(): ?string
    {
        return $this-&amp;gt;getData(self::NAME);
    }

    public function setName(?string $name): void
    {
        $this-&amp;gt;setData(self::NAME, $name);
    }

    public function getStreet(): ?string
    {
        return $this-&amp;gt;getData(self::STREET);
    }

    public function setStreet(?string $street): void
    {
        $this-&amp;gt;setData(self::STREET, $street);
    }

    public function getStreetNum(): ?int
    {
        return $this-&amp;gt;getData(self::STREET_NUM);
    }

    public function setStreetNum(?int $streetNum): void
    {
        $this-&amp;gt;setData(self::STREET_NUM, $streetNum);
    }

    public function getCity(): ?string
    {
        return $this-&amp;gt;getData(self::CITY);
    }

    public function setCity(?string $city): void
    {
        $this-&amp;gt;setData(self::CITY, $city);
    }

    public function getPostCode(): ?int
    {
        return $this-&amp;gt;getData(self::POSTCODE);
    }

    public function setPostcode(?int $postCode): void
    {
        $this-&amp;gt;setData(self::POSTCODE, $postCode);
    }

    public function getLatitude(): ?float
    {
        return $this-&amp;gt;getData(self::LATITUDE);
    }

    public function setLatitude(?float $latitude): void
    {
        $this-&amp;gt;setData(self::LATITUDE, $latitude);
    }

    public function getLongitude(): ?float
    {
        return $this-&amp;gt;getData(self::LONGITUDE);
    }

    public function setLongitude(?float $longitude): void
    {
        $this-&amp;gt;setData(self::LONGITUDE, $longitude);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Resource Model - Path: (app/code/LarsRoettig/GraphQLStorePickup/Model/ResourceModel/Store.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
use Magento\Framework\Model\ResourceModel\PredefinedId;

class Store extends AbstractDb
{
    /**
     * Provides possibility of saving entity with predefined/pre-generated id
     */
    use PredefinedId;

    /**#@+
     * Constants related to specific db layer
     */
    private const TABLE_NAME_STOCK = 'pickup_stores';
    /**#@-*/

    /**
     * @inheritdoc
     */
    protected function _construct()
    {
        $this-&amp;gt;_init(self::TABLE_NAME_STOCK, 'entity_id');
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Resource Collection - Path: (app/code/LarsRoettig/GraphQLStorePickup/Model/ResourceModel/StoreCollection.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Model\ResourceModel;

use LarsRoettig\GraphQLStorePickup\Model\ResourceModel\Store as StoreResourceModel;
use LarsRoettig\GraphQLStorePickup\Model\Store as StoreModel;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;

class StoreCollection extends AbstractCollection
{
    /**
     * @inheritdoc
     */
    protected function _construct()
    {
        $this-&amp;gt;_init(StoreModel::class, StoreResourceModel::class);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. StoreRepositoryInterface - Path: (app/code/LarsRoettig/GraphQLStorePickup/Api/StoreRepositoryInterface.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Api;

use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterface;
use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Api\SearchResultsInterface;

/**
 * @api
 */
interface StoreRepositoryInterface
{
    /**
     * Save the Store data.
     *
     * @param \Magento\InventoryApi\Api\Data\SourceInterface $source
     * @return void
     * @throws \Magento\Framework\Exception\CouldNotSaveException
     */
    public function save(StoreInterface $store): void;

    /**
     * Find Stores by given SearchCriteria
     * SearchCriteria is not required because load all stores is useful case
     *
     * @param \Magento\Framework\Api\SearchCriteriaInterface|null $searchCriteria
     * @return \Magento\InventoryApi\Api\Data\SourceSearchResultsInterface
     */
    public function getList(SearchCriteriaInterface $searchCriteria = null): SearchResultsInterface;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. StoreRepository - Path: (app/code/LarsRoettig/GraphQLStorePickup/Model/StoreRepository.php)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A repository is an architecture layer that handles communication between the application and the data source (DataBase). Repository Pattern helps to switch to another data source or making structural changes to the existing data source.&lt;/p&gt;

&lt;p&gt;For all my repositories, usually, i have an interface that helps to decouple the implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Model;

use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterface;
use LarsRoettig\GraphQLStorePickup\Api\StoreRepositoryInterface;
use LarsRoettig\GraphQLStorePickup\Model\ResourceModel\Store as StoreResourceModel;
use LarsRoettig\GraphQLStorePickup\Model\ResourceModel\StoreCollection;
use LarsRoettig\GraphQLStorePickup\Model\ResourceModel\StoreCollectionFactory;
use Magento\Framework\Api\Search\SearchCriteriaBuilder;
use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface;
use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Api\SearchResultsInterface;
use Magento\Framework\Api\SearchResultsInterfaceFactory;
use Magento\Framework\Exception\CouldNotSaveException;

class StoreRepository implements StoreRepositoryInterface
{
    /**
     * @var StoreCollectionFactory
     */
    private $storeCollectionFactory;
    /**
     * @var CollectionProcessorInterface
     */
    private $collectionProcessor;
    /**
     * @var SearchCriteriaBuilder
     */
    private $searchCriteriaBuilder;
    /**
     * @var SearchResultsInterfaceFactory
     */
    private $storeSearchResultsInterfaceFactory;
    /**
     * @var StoreResourceModel
     */
    private $storeResourceModel;

    public function __construct(
        StoreCollectionFactory $storeCollectionFactory,
        CollectionProcessorInterface $collectionProcessor,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        SearchResultsInterfaceFactory $storeSearchResultsInterfaceFactory,
        StoreResourceModel $storeResourceModel
    ) {
        $this-&amp;gt;storeCollectionFactory = $storeCollectionFactory;
        $this-&amp;gt;collectionProcessor = $collectionProcessor;
        $this-&amp;gt;searchCriteriaBuilder = $searchCriteriaBuilder;
        $this-&amp;gt;storeSearchResultsInterfaceFactory = $storeSearchResultsInterfaceFactory;
        $this-&amp;gt;storeResourceModel = $storeResourceModel;
    }

    /**
     * @inheritDoc
     */
    public function getList(SearchCriteriaInterface $searchCriteria = null): SearchResultsInterface
    {
        /** @var StoreCollection $storeCollection */
        $storeCollection = $this-&amp;gt;storeCollectionFactory-&amp;gt;create();
        if (null === $searchCriteria) {
            $searchCriteria = $this-&amp;gt;searchCriteriaBuilder-&amp;gt;create();
        } else {
            $this-&amp;gt;collectionProcessor-&amp;gt;process($searchCriteria, $storeCollection);
        }
        /** @var SearchResultsInterface $searchResult */
        $searchResult = $this-&amp;gt;storeSearchResultsInterfaceFactory-&amp;gt;create();
        $searchResult-&amp;gt;setItems($storeCollection-&amp;gt;getItems());
        $searchResult-&amp;gt;setTotalCount($storeCollection-&amp;gt;getSize());
        $searchResult-&amp;gt;setSearchCriteria($searchCriteria);

        return $searchResult;
    }

    /**
     * @inheritDoc
     */
    public function save(StoreInterface $store): void
    {
        try {
            $this-&amp;gt;storeResourceModel-&amp;gt;save($store);
        } catch (\Exception $e) {
            throw new CouldNotSaveException(__('Could not save Source'), $e);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;9. Create di.xml to link interface to impelemention - Path: (app/code/LarsRoettig/GraphQLStorePickup/etc/di.xml)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"&amp;gt;
    &amp;lt;preference for="LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterface" type="LarsRoettig\GraphQLStorePickup\Model\Store"/&amp;gt;
    &amp;lt;preference for="LarsRoettig\GraphQLStorePickup\Api\StoreRepositoryInterface" type="\LarsRoettig\GraphQLStorePickup\Model\StoreRepository"/&amp;gt;
&amp;lt;/config&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;10. Setup Patch with Sample Data - Path: (app/code/LarsRoettig/GraphQLStorePickup/Setup/Patch/Data/InitializePickUpStores.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Setup\Patch\Data;

use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterface;
use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterfaceFactory;
use LarsRoettig\GraphQLStorePickup\Api\StoreRepositoryInterface;
use Magento\Framework\Api\DataObjectHelper;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class InitializePickUpStores implements DataPatchInterface
{
    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;
    /**
     * @var StoreInterfaceFactory
     */
    private $storeInterfaceFactory;
    /**
     * @var StoreRepositoryInterface
     */
    private $storeRepository;
    /**
     * @var DataObjectHelper
     */
    private $dataObjectHelper;

    /**
     * EnableSegmentation constructor.
     *
     * @param ModuleDataSetupInterface $moduleDataSetup
     */
    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        StoreInterfaceFactory $storeInterfaceFactory,
        StoreRepositoryInterface $storeRepository,
        DataObjectHelper $dataObjectHelper
    ) {
        $this-&amp;gt;moduleDataSetup = $moduleDataSetup;
        $this-&amp;gt;storeInterfaceFactory = $storeInterfaceFactory;
        $this-&amp;gt;storeRepository = $storeRepository;
        $this-&amp;gt;dataObjectHelper = $dataObjectHelper;
    }

    /**
     * {@inheritdoc}
     */
    public static function getDependencies()
    {
        return [];
    }

    /**
     * {@inheritdoc}
     * @throws Exception
     * @throws Exception
     */
    public function apply()
    {
        $this-&amp;gt;moduleDataSetup-&amp;gt;startSetup();
        $maxStore = 50;

        $citys = ['Rosenheim', 'Kolbermoor', 'München', 'Erfurt', 'Berlin'];

        for ($i = 1; $i &amp;lt;= $maxStore; $i++) {

            $storeData = [
                StoreInterface::NAME =&amp;gt; 'Brick and Mortar ' . $i,
                StoreInterface::STREET =&amp;gt; 'Test Street' . $i,
                StoreInterface::STREET_NUM =&amp;gt; $i * random_int(1, 100),
                StoreInterface::CITY =&amp;gt; $citys[random_int(0, 4)],
                StoreInterface::POSTCODE =&amp;gt; $i * random_int(1000, 9999),
                StoreInterface::LATITUDE =&amp;gt; random_int(4757549, 5041053) / 100000,
                StoreInterface::LONGITUDE =&amp;gt; random_int(1157549, 1341053) / 100000,
            ];
            /** @var StoreInterface $store */
            $store = $this-&amp;gt;storeInterfaceFactory-&amp;gt;create();
            $this-&amp;gt;dataObjectHelper-&amp;gt;populateWithArray($store, $storeData, StoreInterface::class);
            $this-&amp;gt;storeRepository-&amp;gt;save($store);
        }

        $this-&amp;gt;moduleDataSetup-&amp;gt;endSetup();
    }

    /**
     * {@inheritdoc}
     */
    public function getAliases()
    {
        return [];
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  2. How add Magento 2 GraphQL specific impelemention
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.Create GraphQL Schema File - Path: (app/code/LarsRoettig/GraphQLStorePickup/etc/schema.graphqls)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This the &lt;em&gt;schema.graphql&lt;/em&gt; contains the following information&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defines the structure of queries and mutations.&lt;/li&gt;
&lt;li&gt;Determines which attributes can be used for input and output in GraphQL queries and mutations. Requests and responses contain separate lists of valid attributes.&lt;/li&gt;
&lt;li&gt;Points to the resolvers that verify and process the input data and response.&lt;/li&gt;
&lt;li&gt;Serves as the source for displaying the schema in a GraphQL browser.&lt;/li&gt;
&lt;li&gt;Defines which objects are cached.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full Magento Dokumentation:&lt;a href="https://devdocs.magento.com/guides/v2.3/graphql/develop/create-graphqls-file.html"&gt;https://devdocs.magento.com/guides/v2.3/graphql/develop/create-graphqls-file.html&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Query {
    pickUpStores(
        filter: PickUpStoresFilterInput @doc(description: "")
        pageSize: Int = 5 @doc(description: "How many items should show on the page")
        currentPage: Int = 1 @doc(description: "Allows to ussing paging it start with 1")
    ):pickUpStoresOutput @resolver(class: "\\LarsRoettig\\GraphQLStorePickup\\Model\\Resolver\\PickUpStores") @doc(description: "The Impelemention to resolve PickUp stores")
}

input PickUpStoresFilterInput {
    name: FilterTypeInput @doc(description: "")
    postcode: FilterTypeInput @doc(description: ""),
    latitude:FilterTypeInput @doc(description: ""),
    longitude: FilterTypeInput @doc(description: ""),
    or: PickUpStoresFilterInput
}

type pickUpStoresOutput {
    total_count: Int @doc(description: "")
    items: [PickUpStore] @doc(description: "")
}

type PickUpStore {
    name: String @doc(description: ""),
    street: String @doc(description: ""),
    street_num: Int @doc(description: ""),
    city: String @doc(description: ""),
    postcode: String @doc(description: ""),
    latitude:Float @doc(description: ""),
    longitude: Float @doc(description: ""),
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.Create GraphQL Resolver File - Path: (app/code/LarsRoettig/GraphQLStorePickup/Model/Resolver/PickUpStores.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Model\Resolver;

use LarsRoettig\GraphQLStorePickup\Api\StoreRepositoryInterface;
use LarsRoettig\GraphQLStorePickup\Model\Store\GetList;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\Builder as SearchCriteriaBuilder;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

class PickUpStores implements ResolverInterface
{

    /**
     * @var GetListInterface
     */
    private $storeRepository;
    /**
     * @var SearchCriteriaBuilder
     */
    private $searchCriteriaBuilder;

    /**
     * PickUpStoresList constructor.
     * @param GetList $storeRepository
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     */
    public function __construct(StoreRepositoryInterface $storeRepository, SearchCriteriaBuilder $searchCriteriaBuilder)
    {
        $this-&amp;gt;storeRepository = $storeRepository;
        $this-&amp;gt;searchCriteriaBuilder = $searchCriteriaBuilder;
    }

    /**
     * @inheritdoc
     */
    public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
    {

        $this-&amp;gt;vaildateArgs($args);

        $searchCriteria = $this-&amp;gt;searchCriteriaBuilder-&amp;gt;build('pickup_stores', $args);
        $searchCriteria-&amp;gt;setCurrentPage($args['currentPage']);
        $searchCriteria-&amp;gt;setPageSize($args['pageSize']);
        $searchResult = $this-&amp;gt;storeRepository-&amp;gt;getList($searchCriteria);

        return [
            'total_count' =&amp;gt; $searchResult-&amp;gt;getTotalCount(),
            'items' =&amp;gt; $searchResult-&amp;gt;getItems(),
        ];
    }

    /**
     * @param array $args
     * @throws GraphQlInputException
     */
    private function vaildateArgs(array $args): void
    {
        if (isset($args['currentPage']) &amp;amp;&amp;amp; $args['currentPage'] &amp;lt; 1) {
            throw new GraphQlInputException(__('currentPage value must be greater than 0.'));
        }

        if (isset($args['pageSize']) &amp;amp;&amp;amp; $args['pageSize'] &amp;lt; 1) {
            throw new GraphQlInputException(__('pageSize value must be greater than 0.'));
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.Create Dependencies Injection File (di.xml) - Path: (app/code/LarsRoettig/GraphQLStorePickup/etc/di.xml)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This file we need to inject our FilterArgument Class that maps the graph attribute for filtering. Currently there is no general implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"&amp;gt;
    &amp;lt;preference for="LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterface" type="LarsRoettig\GraphQLStorePickup\Model\Store"/&amp;gt;
    &amp;lt;preference for="LarsRoettig\GraphQLStorePickup\Api\StoreRepositoryInterface" type="\LarsRoettig\GraphQLStorePickup\Model\StoreRepository"/&amp;gt;
    &amp;lt;type name="Magento\Framework\GraphQl\Query\Resolver\Argument\FieldEntityAttributesPool"&amp;gt;
        &amp;lt;arguments&amp;gt;
            &amp;lt;argument name="attributesInstances" xsi:type="array"&amp;gt;
                &amp;lt;item name="pickup_stores" xsi:type="object"&amp;gt;
                    \LarsRoettig\GraphQLStorePickup\Model\Resolver\FilterArgument
                &amp;lt;/item&amp;gt;
            &amp;lt;/argument&amp;gt;
        &amp;lt;/arguments&amp;gt;
    &amp;lt;/type&amp;gt;
&amp;lt;/config&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Create FilterArgument File - Path: (app/code/LarsRoettig/GraphQLStorePickup/Model/Resolver/FilterArgument.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

namespace LarsRoettig\GraphQLStorePickup\Model\Resolver;

use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\ConfigInterface;
use Magento\Framework\GraphQl\Query\Resolver\Argument\FieldEntityAttributesInterface;

class FilterArgument implements FieldEntityAttributesInterface
{
    /** @var ConfigInterface */
    private $config;

    public function __construct(ConfigInterface $config)
    {
        $this-&amp;gt;config = $config;
    }

    public function getEntityAttributes(): array
    {
        $fields = [];
        /** @var Field $field */
        foreach ($this-&amp;gt;config-&amp;gt;getConfigElement('PickUpStore')-&amp;gt;getFields() as $field) {
            $fields[$field-&amp;gt;getName()] = '';
        }

        return array_keys($fields);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Installation:
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/magento module:enable LarsRoettig_GraphQLStorePickup
bin/magento setup:upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The repo can founded at Github:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/larsroettig/module-graphqlstorepickup"&gt;https://github.com/larsroettig/module-graphqlstorepickup&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. How to use GraphQL
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Test for your new Endpoint (Client Sample Call)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I recommend as Testing client tool to use &lt;a href="https://altair.sirmuel.design/"&gt;Altair GraphQL Client&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Endpoint Url: &lt;a href="https://your_domain.test/graphql"&gt;https://your_domain.test/graphql&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W6_qowMD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/4cbd147816395f3268022e2da78289a1/0f6c6/GraphQL_Playground.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W6_qowMD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/4cbd147816395f3268022e2da78289a1/0f6c6/GraphQL_Playground.jpg" alt="GraphQL_Playground Sample" title="GrapQL Editor"&gt;&lt;/a&gt;&lt;br&gt;
      &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple Query without an filter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  pickUpStores {
    total_count
      items {
        name
        street
        street_num
        postcode
      }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Query with an filter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  pickUpStores(
    filter: { name: { like: "Brick and Mortar 1%" } }
    pageSize: 2
    currentPage: 1
  ) {
    total_count
    items {
      name
      street
      postcode
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Query with an longitude filter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  pickUpStores(
    filter: { longitude: {
    gt: "11.66"
  }
   }
    pageSize: 2
    currentPage: 1
  ) {
    total_count

    items {
      name
      street
      postcode
      latitude
      longitude
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(This article was posted to my blog at &lt;a href="https://larsroettig.dev"&gt;https://larsroettig.dev&lt;/a&gt;. You can &lt;a href="https://larsroettig.dev/how-to-create-a-graph-ql-endpoint-for-magento-2-3"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/p&gt;

</description>
      <category>magento</category>
      <category>magento2</category>
      <category>graphql</category>
    </item>
    <item>
      <title>Book Review of Object Design Style Guide by Matthias Noback</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Wed, 16 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/larsroettig/book-review-of-object-design-style-guide-by-matthias-noback-1974</link>
      <guid>https://dev.to/larsroettig/book-review-of-object-design-style-guide-by-matthias-noback-1974</guid>
      <description>&lt;h1&gt;
  
  
  Book Review of Object Design Style Guide by Matthias Noback
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As Software Developers, we need to know how a suitable object looks like if working with an object-oriented programming language like PHP, Java, C#. To learn the syntax of the programming language (classes, methods, properties, etc.), it doesn’t take too much effort, but with a proper design for your objects, it mutch more complex.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I’m always looking for ways to make the job easier, and less demanding. I’m writing tests for my code, to prevent regressions. I keep my code simple, so debugging it will be easier. By writing this book, I’ve tried to do the same thing. Following the rules in this guide will free up the mental energy you’ll need for the more difficult parts of object design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Matthias Noback - Object Design Style Guide&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this book is for?
&lt;/h2&gt;

&lt;p&gt;This book is for programmers with at least some basic knowledge of an object-oriented programming language. You should understand the language’s possibilities regarding class design. That is, I expect you to know what it means to define a class, instantiate it, extend it, mark it as abstract, define a method, call it, define parameters and parameter types, define return types, define properties and their types, etc.I also expect you to have some actual experience with all of this, even if it’s not much. I think you should be able to read this book if you’ve just finished a basic programming course, but also if you’ve been working with classes for years.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is in this book
&lt;/h2&gt;

&lt;p&gt;The book contains nine sections:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating services&lt;/li&gt;
&lt;li&gt;Creating other objects&lt;/li&gt;
&lt;li&gt;Manipulating objects&lt;/li&gt;
&lt;li&gt;Using objects&lt;/li&gt;
&lt;li&gt;Retrieving information&lt;/li&gt;
&lt;li&gt;Performing tasks&lt;/li&gt;
&lt;li&gt;Dividing responsibilities&lt;/li&gt;
&lt;li&gt;Changing the behavior of services&lt;/li&gt;
&lt;li&gt;A field guide to objects&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;I can highly recommended. Grab a copy now!&lt;/strong&gt; This book has helped me better understand object design and deepen architectural patterns. It is an excellent complement to clean code. I was able to understand the examples much better through generalization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link: &lt;a href="https://www.manning.com/books/object-design-style-guide"&gt;https://www.manning.com/books/object-design-style-guide&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>bookreview</category>
    </item>
    <item>
      <title>Four pillars to improve the quality of your E-Commerce Project or Module</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Thu, 08 Aug 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/larsroettig/four-pillars-to-improve-the-quality-of-your-e-commerce-project-or-module-33el</link>
      <guid>https://dev.to/larsroettig/four-pillars-to-improve-the-quality-of-your-e-commerce-project-or-module-33el</guid>
      <description>&lt;p&gt;For every Developer, it is essential to make sure that code works. Nobody likes if the live or staging system has a fatal error or whole page/website doesn’t work anymore after a deployment.&lt;/p&gt;

&lt;p&gt;In this blog post, I will share my learnings from Magento Community Team and my experience what I did in the past. For me, they are four crucial pillars to make sure you get fewer blocker tickets for your new Module/Projects. The four areas are clean code, testing, and automation as well as continuous process improvement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qzK_uDpo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/cddf5e6700a8c25b8bd1cc61cb52752f/a111b/businessman-3300907_1920.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qzK_uDpo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/cddf5e6700a8c25b8bd1cc61cb52752f/a111b/businessman-3300907_1920.jpg" alt="businessman-3300907_1920" title="businessman-3300907\_1920"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean Code
&lt;/h3&gt;

&lt;p&gt;In my experience, Clean Code helps to reduce the cost of maintaining, writing tests, on board developers to the project.&lt;/p&gt;

&lt;p&gt;My favorite quote from Martin Fowler is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Any fool can write code that a computer can understand. Good programmers write code that humans can understand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The means any developer should write for code that humans can understand. Usually, Developers read more code than we write in the average development/lifetime of a project.&lt;/p&gt;

&lt;p&gt;This short example from a &lt;a href="https://learning.oreilly.com/library/view/clean-code/9780136083238/"&gt;Clean Code Book&lt;/a&gt; shows the value of Clean Code for new Implementations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code before Refactoring:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FunnyName&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Demo data
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$theList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getThem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// what means getThem ?&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;theList&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// what is theList there ?&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// what 0 and 4 there ?&lt;/span&gt;
                &lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$x&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="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// list of what ?&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;&lt;strong&gt;Code after Refactoring:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GameBoard&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="no"&gt;STATUS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="no"&gt;FLAGGED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Demo data
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$cells&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;STATUS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;STATUS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Returns all flagged game board cells.
     * @return array
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFlaggedCells&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$flaggedCells&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;cells&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$cell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cell&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;STATUS_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;FLAGGED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$flaggedCells&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$cell&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="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$flaggedCells&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Clean Code&lt;/strong&gt; is an excellent book that all programmers should read,&lt;/p&gt;

&lt;p&gt;The rules from Clean Code Book can apply to your old code by refactoring. I recommend reducing the technical debt with your sprint Tickets as subtasks. Estimated these subtasks and define a benefit for your team or customer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A benefit can be:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We reduce the change time for the next change on this feature.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before you refactor you should cover your Implementation with Intitragtionstests. In an existing framework like Magento, it is sometimes not easy to apply rules from a Book. With Magento 2 it is more comfortable to build clean code. You can use features like Dependency Injection. In an example, &lt;a href="https://github.com/magento/inventory"&gt;Magento Inventory (MSI)&lt;/a&gt; already use Pattern like Command Query Responsibility Segregation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read Tip:&lt;/strong&gt; Object Design Style Guide by Matthias Noback&lt;/p&gt;

&lt;p&gt;Object Design Style Guide is a good foundation book. Applying best practices for object design means that your code will be easy to read, write, and maintain. All Code Examples in this book are in a generalized object-oriented programming language. &lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://www.manning.com/books/object-design-style-guide" rel="nofollow noopener noreferrer"&gt;https://www.manning.com/books/object-design-style-guide&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Backward compatible development
&lt;/h4&gt;

&lt;p&gt;If you develop Module for the Magento Market place. It is important to know how to develop backward compatible. I strongly recommend following the rules of this guideline:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devdocs.magento.com/guides/v2.3/contributor-guide/backward-compatible-development/"&gt;https://devdocs.magento.com/guides/v2.3/contributor-guide/backward-compatible-development/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;For production-ready software, it is required to have tests that verify the software behaves as expected. You can do to this with myriads of manual software testers. But the cost and maintains are expansive for manual software testing also the feedback is slow.&lt;br&gt;&lt;br&gt;
In the IBM research “Minimizing Code Defects to Improve Software Quality and Lower Development Costs” is a good statement:&lt;/p&gt;

&lt;p&gt;The costs of discovering defects after release are signed up to 30 times more than if you catch them in the design and architectural phase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MqktmXpj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/506f0768e425f79f3399b7d5349d6acd/dbb61/The%2520EconomicImpactsSoftwareTesting.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MqktmXpj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/506f0768e425f79f3399b7d5349d6acd/dbb61/The%2520EconomicImpactsSoftwareTesting.png" alt="Costs of discovering defects after release" title="Costs of discovering defects after release "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This statement leads me to we need different types of automated tests to reduce the feedback time. But you as a developer don’t like run tests that take hours before you can push. To split test Mike Cohn came up with a concept “Test Pyramid” in his book &lt;a href="https://www.oreilly.com/library/view/succeeding-with-agile/9780321660534/"&gt;&lt;em&gt;Succeeding with Agile&lt;/em&gt;&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;If you like to know more about Test Pyramid you should read :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html"&gt;The Practical Test Pyramid&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MoF0ni5k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/60c09a82c09001b4da9f3a3c67a97bfe/a111b/TestPyramid.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MoF0ni5k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/60c09a82c09001b4da9f3a3c67a97bfe/a111b/TestPyramid.jpg" alt="Picture from TestPyramid" title="Picture from TestPyramid "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the ground we have Unit-Tests it followed by Integration tests and User Interface test at the top.&lt;/p&gt;

&lt;h4&gt;
  
  
  Unit tests
&lt;/h4&gt;

&lt;p&gt;Unit tests are relatively easy to create also quick to run. We can use them to achieve good coverage and detect most errors at a very early stage of development. Unit-Test should run before we commit your code the version. Ideally, they even develop with TDD or follow the principles of Clean Code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Integration tests
&lt;/h4&gt;

&lt;p&gt;Integration tests can be automated relatively well these tests required an installed Magento with Database. An install can take time should not run locally.&lt;/p&gt;

&lt;p&gt;Documentation for setup and running integrations test with Magento 2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devdocs.magento.com/guides/v2.3/test/integration/integration_test_execution.html"&gt;https://devdocs.magento.com/guides/v2.3/test/integration/integration_test_execution.html&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  User Interface (UI) tests
&lt;/h4&gt;

&lt;p&gt;UI tests can be complex and tricky to run automatically. Also, the automation maintenance is very time-intensive, therefore you should consider well if automation makes sense. Tools like Selenium or Cypress I use by many projects. For UI Test I can recommend evaluated two tools and find the best fit for your project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Mutations testing
&lt;/h4&gt;

&lt;p&gt;With the help of the &lt;a href="https://github.com/infection/infection"&gt;infection library&lt;/a&gt;, it is possible to check how resilient the test suite is. The library runs the units tests on the manipulated code to calculate the Mutation Score Indicator.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt; this step is an extension but should be done on the CI-System because it can take a long time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Smoke Testing
&lt;/h4&gt;

&lt;p&gt;Manuelle Testing is expansive but covers some complex it can be to difficult by automation. I recommend collecting a test-case step by step in a system currently we using currently only google docs. Better it is to use as test case management software and run later by automated tests.&lt;/p&gt;

&lt;h4&gt;
  
  
  Coding Standards
&lt;/h4&gt;

&lt;p&gt;Most developer teams define programming style (Coding Standard). Coding standard allows getting better understandable code. That can reduce the on boarding time for new developers. The Coding Standard Tools (PHP_CodeSniffer) should also run on commit via git hooks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Learn to write tests and use Test Driven Development &lt;/li&gt;
&lt;li&gt;Tests are not free but very helpful &lt;/li&gt;
&lt;li&gt;Code Coverage only shows what has not yet been executed &lt;/li&gt;
&lt;li&gt;Use Code Coverage to find gaps in the test-suite &lt;/li&gt;
&lt;li&gt;Bugs in Production are extremely expensive &lt;/li&gt;
&lt;li&gt;Find the errors best during development &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Allure Report
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p7tqp_6Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/ba973a6b23e789c8b996b2e92e329d1e/dbb61/Allure.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p7tqp_6Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://larsroettig.dev/static/ba973a6b23e789c8b996b2e92e329d1e/dbb61/Allure.png" alt="Screen Shot Allure Framework" title="Screen Shot Allure Framework"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Allure Framework is a test report tool that shows a representation of performed tests. The representation can be much essential to get an overview of failing tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation can be found at:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devdocs.magento.com/mftf/docs/reporting.html"&gt;https://devdocs.magento.com/mftf/docs/reporting.html&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;With automation, it is possible to save time and money over the project time. For setup, you will have minor one-time expenses. I think over project live time it is a good investment in quality. With CI-System like &lt;a href="https://about.gitlab.com/"&gt;Gitlab&lt;/a&gt;, it is possible to set up automatic reviews. Automatic reviews can reduce the time and rejection rate for review.&lt;/p&gt;

&lt;p&gt;To get best from of automation we need checks for before we push. To setup git hooks I recommend tools like &lt;a href="https://github.com/"&gt;GrumPHP&lt;/a&gt; or &lt;a href="https://github.com/CaptainHookPhp/captainhook"&gt;Captian Hook.&lt;/a&gt; The following tests should run before any push:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commit Message&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/magento/magento-coding-standard"&gt;Coding Standard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unit Tests

&lt;p&gt;&lt;strong&gt;Read Tip:&lt;/strong&gt; How to Write a Git Commit Message&lt;/p&gt;
&lt;p&gt;A Blog post about seven rules for a great Git commit message&lt;/p&gt;
&lt;p&gt;Link: &lt;a href="https://chris.beams.io/posts/git-commit/" rel="nofollow noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://chris.beams.io/posts/git-commit/"&gt;https://chris.beams.io/posts/git-commit/&lt;/a&gt;&lt;/p&gt;

### Continuous Improvement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Continuous Improvement is a foundational principle agile. In the agile manifesto is defined with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At regular intervals, the team reflects on how&lt;/p&gt;

&lt;p&gt;to become more effective, then tunes and adjusts&lt;/p&gt;

&lt;p&gt;its behavior accordingly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That suggests to have regular meeting with all member to speak about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What was great? - let’s keep it&lt;/li&gt;
&lt;li&gt;What is not working? - find ways do it rightly&lt;/li&gt;
&lt;li&gt;What we should to more?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not only is the continuous improvement necessary for the team. There should also be time for self-improvement to getting a better engineer.&lt;/p&gt;

&lt;p&gt;But for me there is more programming is a kind of mastery, when you train, you get better. You can learn the foundations by reading books and blog entries, the basics help you understand patterns. On the other hand, training is essential coding kata are the choice for practice. To detect arias to improvement help to use peer feedback or mentoring if you are more a junior developer.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>softwaretesting</category>
      <category>softwarequality</category>
    </item>
    <item>
      <title>Create GraphQL Endpoint for Magento 2.3 — Part 1</title>
      <dc:creator>Lars Roettig</dc:creator>
      <pubDate>Tue, 18 Dec 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/larsroettig/create-graphql-endpoint-for-magento-2-3-part-1-3mi</link>
      <guid>https://dev.to/larsroettig/create-graphql-endpoint-for-magento-2-3-part-1-3mi</guid>
      <description>&lt;p&gt;In this tutorial, we will implement a sample module with an essential endpoint without the database. At Tutorial 2 we will extend the test module with Declarative Schema for a new table, use data patch to import sample data to get a more dynamic endpoint.&lt;/p&gt;

&lt;p&gt;But before we should take a short look at what is GraphQL, for me it is a powerful query language for API’s and convenient for javascript or Progressive Web App solutions (PWA). Magento 2 use GraphQL to connect there new PWA-Theme &lt;a href="https://magento-research.github.io/pwa-studio/venia-pwa-concept/setup/" rel="noopener noreferrer"&gt;(Venia Storefront)&lt;/a&gt; with Magento.&lt;/p&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installed &lt;a href="https://devdocs.magento.com/guides/v2.3/install-gde/composer.html" rel="noopener noreferrer"&gt;Magento 2.3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PHP 7.1 or 7.2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recommended (Development):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bin/magento deploy:mode:set developer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets start with new Folder under &lt;strong&gt;app/code/Test/GraphQL&lt;/strong&gt; in your installed magento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create new module registration.php - Path: (app/code/Test/GraphQL/registration.php)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

declare(strict_types=1);

// register our new Test_GraphQL
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Test_GraphQL',
    __DIR__
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2 Create new module.xml - Path: (app/code/Test/GraphQL/etc/module.xml)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" ?&amp;gt;
&amp;lt;config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"&amp;gt;
   &amp;lt;module name="Test_GraphQL" setup_version="0.0.1"&amp;gt;
      &amp;lt;sequence&amp;gt;
         &amp;lt;module name="Magento_GraphQl"/&amp;gt;
      &amp;lt;/sequence&amp;gt;
   &amp;lt;/module&amp;gt;
&amp;lt;/config&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Create an GraphQL Schema File - Path: (app/code/Test/GraphQL/etc/schema.graphqls)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Query {
    pickUpStores:pickUpStoresOutput @resolver(class: "\\Test\\GraphQL\\Model\\Resolver\\Store") @doc(description: "")
}
type pickUpStoresOutput {
    total_count: Int @doc(description: "")
    items: [pickUpStore] @doc(description: "")
}
type pickUpStore {
    name: String @doc(description: ""),
    street: String @doc(description: ""),
    street_num: String @doc(description: ""),
    city: String @doc(description: ""),
    postcode: String @doc(description: ""),
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Implement a service class to handle a request by clients- Path (app/code/Test/GraphQL/Model/Resolver/Store.php)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;! Importent&lt;/em&gt; &lt;code&gt;@resolver(class:&lt;/code&gt; in &lt;em&gt;schema.graphqls&lt;/em&gt; must be the &lt;a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md" rel="noopener noreferrer"&gt;PS-0&lt;/a&gt; path from your php service class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

namespace Test\GraphQL\Model\Resolver;

use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

class Store implements ResolverInterface
{
    /**
     * @inheritdoc
     */
    public function resolve(
        Field $field,
        $context,
        ResolveInfo $info,
        array $value = null,
        array $args = null
    ) {
        $stores = [
            [
                'name' =&amp;gt; 'Brick and Mortar Kolbermoor',
                'street' =&amp;gt; 'JosefMeier Straße',
                'street_num' =&amp;gt; '1002',
                'postcode' =&amp;gt; '83059',
            ],
            [
                'name' =&amp;gt; 'Brick and Mortar Erfurt',
                'street' =&amp;gt; 'Max Meier Straße',
                'street_num' =&amp;gt; '102',
                'postcode' =&amp;gt; '99338',
            ],
        ];
        return [
            'total_count' =&amp;gt; count($stores),
            'items' =&amp;gt; $stores
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Installation:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/magento module:enable Test_GraphQL
bin/magento setup:upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test for your new Endpoint (Client Sample Call)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I recommend as Testing client tool to use &lt;a href="https://altair.sirmuel.design/" rel="noopener noreferrer"&gt;Altair GraphQL Client&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/3d8fad0f73996f9b2d1483944afd833a/00212/grapql.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flarsroettig.dev%2Fstatic%2F3d8fad0f73996f9b2d1483944afd833a%2Fdbb61%2Fgrapql.png" title="GrapQL Editor" alt="image from GrapQL Editor"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Endpoint Url: &lt;strong&gt;&lt;a href="https://your_domain.test/graphql" rel="noopener noreferrer"&gt;https://your_domain.test/graphql&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An Test Query:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  pickUpStores {
    total_count
      items {
        name
        street
        street_num
        postcode
      }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Example Module:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://gitlab.com/larsroettig/test_graphql/tree/v1" rel="noopener noreferrer"&gt;https://gitlab.com/larsroettig/test_graphql/tree/v1&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>magento2</category>
      <category>magento</category>
    </item>
  </channel>
</rss>
