A complete Vuejs smart queries example to use hypi cli

In this tutorial, We will explain and demonstrate how to use Hypi CLI inside Vuejs 2 typescript app with smart queries and apollo Smart Query | Vue Apollo

Create Vue App
You can create a vuejs typescript project using the Vue-cli from here

Run vue create vue2-smart-queries
Choose manually select features and configure them as follow

OR you can use the ready-made app from here

Getting Started with Hypi cli
Install Hypi cli
npm install -g @hypi/cli

In this example, we will use the apollo client as the graphql client and the vue smart queries

"apollo-boost": "^0.4.9",
"graphql": "^15.5.1",
"graphql-tag": "^2.12.5",
"vue-apollo": "^3.0.7",
"vue-apollo-smart-ops": "^0.0.3",

OR install them using the command line
npm install --save vue-apollo vue-apollo-smart-ops graphql graphql-tag apollo-boost
Let’s start using Hypi CLI now.

Config
This command helps you configure the CLI. If you are using the cloud version of Hypi then you don’t need to use this but if you’re on-premise then it helps you set the Hypi API URL that the CLI will send API requests to

$ hypi config https://hypi.on-premise-domain.com
$ hypi config -a=https://hypi.on-premise-domain.com
$ hypi config --api_domain=https://hypi.on-premise-domain.com

Make sure to login again after each time you change your config through the Config command

Login
The next step is to log in to your Hypi account
On the command line, go to your Vuejs application folder. Login to your Hypi account using hypi login command.
hypi login Login with a user name and password
hypi login -d Login with organization namespace and Authorization token from here Hypi.Tink
After successful login, the user config file will be placed in ~/.config/hypi/config.json . In case of Windows, the file will be created in \Users\user\AppData\Local

Init
Use the init command to initialize a new hypi App and Instance in your vuejs project folder.
hypi init
.hypi folder will be created with app.yaml, instance.yaml and schema.graphql files which contains information about App, Instance and the graphql schema

Make sure to write your graphql schema inside the schema.graphql file

In our example we will use the following schema
Update /.hypi/schema.graphql with the following schema

type Product {
    title: String!
    description: String!
    price: Float
}

Sync
The next step is to sync your local schema and get the full schema.
run the following command
hypi sync
after successful sync, generated-schema.graphql file gets generated in the .hypi folder that has full hypi schema.

Generate
Now it is time to generate the Vuejs graphql code
The first step is to create your graphql queries and mutations inside /src/graphql

We will add queries for all the crud operations

  1. Find all products /src/graphql/products.graphql
query products($arcql: String!) {
    find(type: Product, arcql: $arcql) {
        edges {
            node {
               ...ProductFields
            }
        }
    }
}

fragment ProductFields on Product {
   hypi {
        id
    }
    title
    description
}
  1. Add Product /src/graphql/products-mutation.graphql
mutation upsert($values:HypiUpsertInputUnion!) {
  upsert(values:$values)
    {
        id
    }
}
  1. Get Product by Id /src/graphql/get-product.graphql
query getProduct($id: String!) {
    get(type: Product, id: $id) {
           ...ProductFields
    }
}

fragment ProductFields on Product {
   hypi {
        id
    }
    title
    description
}
  1. Delete Product /src/graphql/delete-product.graphql
mutation delete(
$arcql: String!
$clearArrayReferences: Boolean = false) {
  delete(type: Product, arcql: $arcql, clearArrayReferences: $clearArrayReferences)
}

Now after you created the graphql queries and mutations, use the command generate to generate the Vuejs graphql code so that you can use Hypi APIs within your project.

 hypi generate vuejs
 hypi generate -p=vuejs
 hypi generate --platform=vuejs

You will be asked whether to generate code for smart queries or composition API. Choose smart queries for this tutorial
After running the command, graphql.ts files get created in the \src\generated folder.

Inside graphql.ts file, you will find the vuejs smart queries to be used inside your vue components

 * @example
 * const { success, data, errors } = deleteMutation(this, {
 *   variables: {
 *     arcql: // value for 'arcql'
 *     clearArrayReferences: // value for 'clearArrayReferences'
 *   },
 * });
 */
export const deleteMutation = createMutationFunction<
  DeleteMutation,
  DeleteMutationVariables,
  ApolloError
>(DeleteDocument);
 * @example
 * {
 *   apollo: {
 *     getProduct: useGetProductQuery({
 *       variables: {
 *         id: // value for 'id'
 *       },
 *       loadingKey: 'loading',
 *       fetchPolicy: 'no-cache',
 *     }),
 *   }
 * }
 */
export const useGetProductQuery = createSmartQueryOptionsFunction<
  GetProductQuery,
  GetProductQueryVariables,
  ApolloError
>(GetProductDocument);
 * @example
 * const { success, data, errors } = updateProductsMutation(this, {
 *   variables: {
 *     values: // value for 'values'
 *   },
 * });
 */
export const updateProductsMutation = createMutationFunction<
  UpdateProductsMutation,
  UpdateProductsMutationVariables,
  ApolloError
>(UpdateProductsDocument);
 * @example
 * {
 *   apollo: {
 *     products: useProductsQuery({
 *       variables: {
 *         arcql: // value for 'arcql'
 *       },
 *       loadingKey: 'loading',
 *       fetchPolicy: 'no-cache',
 *     }),
 *   }
 * }
 */
export const useProductsQuery = createSmartQueryOptionsFunction<
  ProductsQuery,
  ProductsQueryVariables,
  ApolloError
>(ProductsDocument);

Now you are ready to create your Vuejs TypeScript application using Hypi APIs!
Using Vuejs smart queries

Inside src/views, Add Products.vue file. This file will access the generated graphql smart queries .

Here is the content of the entire file. You may modify this file to use your own hooks. /src/views/Products.vue

<template>
  <div>
    <div class="row mb-3">
      <div class="col-sm-2">
        <router-link :to="{ name: 'AddProduct' }" class="btn btn-primary"
          >Add Product</router-link
        >
      </div>
    </div>
    <div v-if="loading > 0">
      <div class="alert alert-info" role="alert">Loading...</div>
    </div>
    <table v-else class="table table-hover">
      <thead>
        <tr>
          <td>title</td>
          <td>description</td>
          <td>price</td>
          <td colspan="2">Actions</td>
        </tr>
      </thead>

      <tbody>
        <tr v-for="product in products" :key="product.node.hypi.id">
          <td>{{ product.node.title }}</td>
          <td>{{ product.node.description }}</td>
          <td>{{ product.node.price }}</td>
          <td>
            <router-link
              :to="{
                name: 'EditProduct',
                params: { id: product.node.hypi.id },
              }"
              class="btn btn-success"
              >Edit</router-link
            >
          </td>
          <td>
            <button
              class="btn btn-danger btn-sm"
              @click.prevent="removeProduct(product.node.hypi.id)"
            >
              Remove
            </button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>

import { useProductsQuery, deleteMutation } from '../generated/graphql';

export default {
  apollo: {
    products: useProductsQuery({
      variables: {
        arcql: '*',
      },
      loadingKey: 'loading',
      update: (data) => data.find.edges,
    }),
  },
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  data() {
    return {
      products: null,
      loading: 0,
    };
  },
  methods: {
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    async removeProduct(productId) {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { success, data, errors } = await deleteMutation(
        this,
        {
          variables: {
            arcql: `hypi.id = '${productId}'`,
          },
        },
        this.$apollo,
      );
      if (errors) {
        // eslint-disable-next-line no-alert
        alert('Failed to delete message');
      }
      if (success) {
        this.$router.push({ name: 'Products' });
        this.$router.go(0);
      }
    },
  },
};
</script>

The full complete example is available here for the rest of crud operations

After you finish, run the project using npm run serve.