メインコンテンツまでスキップ

Vue Graphql

Hxb-Vue-graphql

Get Started

Initialize

Create an application Vue:

vue create vue-graphql-hxb
  • When prompted to pick a preset, you can simply select like this:
    ? Please pick a preset: Manually select features
    ? Check the features needed for your project: Choose Vue version, Babel, Linter
    ? Choose a version of Vue.js that you want to start the project with 3.x
    ? Pick a linter / formatter config: Basic
    ? Pick additional lint features: Lint on save
    ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
    ? Save this as a preset for future projects? (y/N) n
  • Then option choice Yarn

-Install package

  • Using optional yarn package

      yarn add react graphql apollo-boost vue-class-component vue-property-decorator @apollo/client @vue/apollo-composable 
    yarn add -D eslint babel-eslint eslint-plugin-vue vue-cli-plugin-vue-next @vue/eslint-config-typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript @vue/cli-plugin-babel @vue/cli-plugin-eslint @vue/cli-plugin-typescript @vue/cli-service

  • File package.json like this:

    {
    "name": "vue-graphql",
    "version": "0.1.0",
    "private": true,
    "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
    },
    "dependencies": {
    "@apollo/client": "^3.4.17",
    "@vue/apollo-composable": "^4.0.0-alpha.15",
    "apollo-boost": "^0.4.9",
    "core-js": "^3.6.5",
    "graphql": "^16.0.1",
    "react": "^17.0.2",
    "vue": "^3.0.0-beta.1",
    "vue-class-component": "^7.2.3",
    "vue-property-decorator": "^9.1.2"
    },
    "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^4.18.0",
    "@typescript-eslint/parser": "^4.18.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-typescript": "^4.5.15",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0-beta.1",
    "@vue/eslint-config-typescript": "^7.0.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0-alpha.0",
    "typescript": "~4.1.5",
    "vue-cli-plugin-vue-next": "~0.1.4"
    },
    "eslintConfig": {
    "root": true,
    "env": {
    "node": true
    },
    "extends": [
    "plugin:vue/vue3-essential",
    "eslint:recommended",
    "@vue/typescript"
    ],
    "parserOptions": {
    "parser": "@typescript-eslint/parser"
    },
    "rules": {}
    },
    "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
    ]
    }

-Config to using typescript and Connect Vue with grahpql through apollo

  • Create file .eslintrc.js like this:

    module.exports = {
    root: true,
    env: {
    node: true
    },
    'extends': [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/typescript/recommended'
    ],
    parserOptions: {
    ecmaVersion: 2020
    },
    rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
    }
    }
  • Create file tsconfig.json like this:

    {
    "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": [
    "webpack-env"
    ],
    "paths": {
    "@/*": [
    "src/*"
    ]
    },
    "lib": [
    "esnext",
    "dom",
    "dom.iterable",
    "scripthost"
    ]
    },
    "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
    ],
    "exclude": [
    "node_modules"
    ]
    }
  • In main.ts import package @apollo/client:

    import { createApp, h, provide } from "vue";
    import {
    ApolloClient,
    ApolloLink,
    InMemoryCache,
    from,
    HttpLink,
    } from "@apollo/client/core";
    import { DefaultApolloClient } from "@vue/apollo-composable";
    import App from "./App.vue";
  • In main.ts add authentication token and connect to uri api and cache fields:

    const token = localStorage.getItem('token');
    const additiveLink = from([
    new ApolloLink((operation, forward) => {
    operation.setContext(({ headers }: any) => ({
    headers: {
    ...headers,
    authorization: token ? `Bearer ${token}` : null
    }
    }));
    return forward(operation);
    }),
    new HttpLink({ uri: "https://hxb-graph.hexabase.com/graphql" })
    ]);

    const apolloClient = new ApolloClient({
    link: additiveLink,
    cache: new InMemoryCache()
    });
  • In main.ts wrap vue app with provide

    const app = createApp({
    setup() {
    provide(DefaultApolloClient, apolloClient)
    },
    render: () => h(App)
    });

    app.mount("#app");
  • In shims-vue.d.ts to config ReturnType like this:

    declare module '*.vue' {
    import type { defineComponent } from 'vue'
    const component: ReturnType<typeof defineComponent>;
    export default component
    }
  • creaet file shims-tsx.d.ts like this:

    import Vue, { VNode } from 'vue'

    declare global {
    namespace JSX {
    // tslint:disable no-empty-interface
    interface Element extends VNode {}
    // tslint:disable no-empty-interface
    interface ElementClass extends Vue {}
    interface IntrinsicElements {
    [elem: string]: any
    }
    }
    }

-Example Query/Mutation Graphql with Hexabase:

-Create UI:

  • At template In file main.ts create button choice optional is workspaces and check condition show Workspaces component:

      <div class="app">
    <header>
    <div class="title">
    <img alt="hexabase logo" src="./assets/hexabase.png">
    </div>
    <div class="order">
    <button @click="handleClick('workspaces')">Workspaces</button>
    <button @click="handleClick('applicationdatastore')">ApplicationDatastore</button>
    </div>
    </header>

    <Workspaces v-if="choice =='workspaces'" />
  • Then import Workspace component and handle button:

    import { defineComponent, ref } from 'vue';
    import Workspaces from './components/Workspace.vue'

    export default defineComponent({
    name: 'App',
    components: { Workspaces },
    setup() {
    let choice = ref<string>('')
    const handleClick = (term: string) => {
    choice.value = term
    }
    return { choice, handleClick }
    }
    });
    </script>
  • Add style like this:

    header {
    text-align: center;
    }
    header .order {
    margin-top: 20px;
    }
    button {
    margin: 0 10px;
    color: #1195c9;
    border: 3px solid #1195c9;
    background: #d5f0ff;
    padding: 8px 16px;
    border-radius: 4px;
    cursor: pointer;
    font-weight: bold;
    }
    header .title{
    /* display: flex; */
    justify-content: center;
    }
    header img {
    width: 100%;
    max-width: 250px;
    margin-right: 20px;
    }

-Create graphql:

  • Create folder graphql and then create file workspaces.ts:

    • import package and create sentence query and mutation
    import { gql } from "@apollo/client/core";

    export const GET_WORKSPACES = gql` query {
    workspaces {
    workspaces {
    workspace_name
    workspace_id
    },
    current_workspace_id
    }
    }`

    export const ADD_WORKSPACE = gql`
    mutation createWorkspace($createWorkSpaceInput: CreateWorkSpaceInput!) {
    createWorkspace(createWorkSpaceInput: $createWorkSpaceInput) {
    w_id
    }
    }`;

  • Create folder model and then create file workspace.ts:

    • Create type then export these:
    export type WorkSpacesInfo = {
    workspace_id: string,
    workspace_name: string,
    }

    export type WorkSpaces = {
    workspaces: [WorkSpacesInfo],
    current_workspace_id: string,
    }

    export type WId = {
    w_id: string,
    }

    export type Name = {
    name: string,
    }

-To do with query/mutation Vue graphql:

  • In template tag:

    <div class="form-body">
    Mutation create workspaces
    <div class="input-field">
    <input type="text" v-model="name" placeholder="enter the name" />
    <button @click="addWorkspace">ADD Workspace</button>
    </div>
    </div>
    <div v-if="loading">
    <h2>LOADING...</h2>
    </div>
    <div v-else-if="error">{{error}}</div>
    <div class="workpaces-list" v-else-if="workspaces">
    <transition-group name="list" tag="ul">
    <h2>Workspaces</h2>
    <li>
    <div class="description">
    <p> <span> current workspace id: </span>{{workspaces.workspaces?.current_workspace_id}}</p>
    </div>
    </li>
    <li v-for="workspace in workspaces.workspaces?.workspaces" :key="workspace.id">
    <div class="description">
    <p>{{workspace}}</p>
    </div>
    </li>
    </transition-group>
    </div>
  • Import package and execute query/mutation:

    import { defineComponent, ref } from 'vue'
    import { useQuery, useResult, useMutation } from "@vue/apollo-composable";
    import {WorkSpaces, WId } from '../model/workspaces'
    import {GET_WORKSPACES, ADD_WORKSPACE} from '../graphql/workspaces'

    export default defineComponent({
    data() {
    return {
    name:''
    }
    },
    methods: {
    addWorkspace: function() {
    this.createWorkspace({ createWorkSpaceInput: {
    name: this.name
    } });
    }
    },
    setup() {
    const { result, loading, error } = useQuery<{workspaces: WorkSpaces}>(GET_WORKSPACES);
    const workspaces = useResult( result, [], data => data );
    const {
    loading: m_loading,
    error: m_error,
    mutate: createWorkspace
    } = useMutation(ADD_WORKSPACE, {
    update: (cache, { data: {createWorkspace} }) => {
    const data: any = cache.readQuery({ query: GET_WORKSPACES });
    }
    });
    return {
    workspaces,
    result,
    loading: loading || m_loading,
    error: error || m_error,
    createWorkspace,
    };
    },
    })
  • Create style for UI:

    .workpaces-list {
    max-width: 960px;
    margin: 40px auto;
    }
    .workpaces-list ul {
    padding: 0
    }
    .workpaces-list li {
    list-style-type: none;
    background: white;
    border-radius: 4px;
    }
    .workpaces-list h2 {
    margin: 0 0 10px;
    text-transform: capitalize;
    }
    .salary {
    display: flex;
    }
    .salary img {
    width: 30px;
    }
    .salary p {
    color: #17bf66;
    font-weight: bold;
    margin: 10px 4px;
    }
    .list-move {
    transition: all 1s;
    }
    .form-body {
    width: 100%;
    max-width: 700px;
    margin: 0 auto;
    text-align: center;
    margin-top: 10px;
    margin-bottom: 5px;
    }
    .input-field {
    width: 700 px;
    margin: 0 auto;
    }
    .input-field input {
    height: 29px;
    }

-Run project:

  yarn serve

Example: Hexabase Vue Graphql