GithubHelp home page GithubHelp logo

ddn_demo's Introduction

Hasura DDN Project from scratch (CLI + VS CODE)

Prerequisites

  1. Hasura CLI v3 and Login to Hasura cloud with CLI
  2. VS Code
  3. Hasura VS Code extension
  4. Postgres DB instance
  5. Deno

Getting Started

Step 1 : Create a Hasura DDN Project with local files

Open terminal on a new working directory and execute the following command to start a new DDN project

hasura init

choose Create New Project Alt text

This will create a DDN project on Hasura cloud, and scaffold a local project on your working directory.

Step 2 : Setup the Database

If you have a PostgresDB running locally, execute the SQL to initialise the tables needed for this demo.

-- Create 'users' table
CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

-- Create 'todos' table with a foreign key reference to 'users'
CREATE TABLE IF NOT EXISTS todos (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES users(id),
    todo TEXT NOT NULL,
    description TEXT,
    status TEXT
);

Step 3 : Local Tunnel Setup: Get your local database accessible from Hasura Cloud

If you have your local postgres database running on localhost:5432, run the following commands to start a tunnel deamon that helps Hasura to connect to your locally running database- Idea is to make local dev experience seamless.

hasura deamon start
# and on a different terminal execute the follwing
hasura tunnel create localhost:5432
# if everything goes right, you will see an output similar to the following
#  Creating tunnel... ok
#   Tunnel active on URL asia-south1-x-xxx.secure-connect.cloud.internal:2000

You will now get an endpoint which can be used on Hasura to resolve your database queries.

Step 4: Add Postgres Datasource, Models to the metadata.

Open the directory using VS Code and open the `metadata.hml`` file.

We can start writing something similar to the following, the VS Code extension will help you to auto-complete the structure so that you don't have to remember or refer docs during the metadata authoring.

Add the following lines to it,

kind: HasuraHubDataConnector
version: v1
definition:
  name: dbb
  connectorId: hasura/postgres
  connectorConfiguration:
    - region: gcp-asia-south1
      mode: ReadOnly
      configuration:
        version: 1
        connectionUri:
          uri:
            value: postgres://user_sooraj:[email protected]:2028/db

The above is a partial definition of a HasuraHub Data Connector, we will now load the DB schema to this definition by using CTRL/CMD + Shift + P and then start typing Hasura: Refresh Data Connecor then choose dbb as we have named this datasource dbb.

πŸŽ‰ we now have the schema introspected and ready to use in Hasura metadata without any manual authoring.

Now lets Track all collections and relationships by again simply using the extension command. Press CTRL/CMD + Shift + P and then start typing Hasura: Track all collections / functions / procedures / foreign keys from data connector This will add all the metadata objects that you need to get your GraphQL api from all the tables on posgres.

You can also selectively track a few tables based on your requirements.

Step 5: Creating first build

Now execute the command to create your first build.

hasura build create --description "Added database tables"

we can now go to https://console.hasura.io/ and get to the project that we created and try out the new UPI.

Step 6 : Creating and Starting the TS connector.

You can now write business logic on your Hasura project with typescript, we will have mutations on postgres connector soon, but for this demo we will write to postgres using a custom ts function.

This will also power up developers to write custom checks, or logic in a much customised fashion easily.

Create a file functions/index.ts and use the folllowing to define the functions.

functions/index.ts
import { Client } from "https://deno.land/x/[email protected]/mod.ts";

import Filter from "npm:[email protected]";

const dbConfig = {
  user: "user_sooraj",
  hostname: "127.0.0.1",
  port: 35432,
  password: "pass",
  database: "db",
  ssl: true,
  sslmode: "require",
};
const filter = new Filter();

type todoType = {
  id: number;
  user_id: number;
  todo: string;
};

export async function insert_todos(
  user_id: string,
  todo: string
): Promise<{ status: string; errorMessage?: string; data?: todoType }> {
  console.log(">> NEW TODO");
  const client = new Client(dbConfig);

  // Input validations : Check if the todo text is empty or contains bad words
  if (!todo) {
    return { status: "error", errorMessage: "Invalid todo text" };
  } else if (filter.isProfane(todo)) {
    console.error("Todo text contains bad words");
    return { status: "error", errorMessage: "Todo text contains bad words" };
  }

  // Input sanitization :  remove special characters from the todo text
  todo = todo.replace(/[^\w\s]/gi, "");

  try {
    await client.connect();

    // Check if the user exists in the users table

    const userExistsQuery = await client.queryObject({
      text: `SELECT id FROM users where id =${user_id}`,
    });

    if (userExistsQuery.rows.length === 0) {
      return { status: "error", errorMessage: "User not found. Insert Failed" };
    }
    const result = await client.queryObject({
      text: `INSERT INTO todos(user_id,todo) VALUES ('${user_id}','${todo}') RETURNING *`,
    });

    if (result && result.rows.length > 0 && result.rows[0]) {
      // Notify slack about the new todo
      const notifySlack = await fetch(
        "https://hooks.slack.com/services/XX",
        {
          method: "POST",
          headers: {
            "Content-type": "application/json",
          },
          body: JSON.stringify({
            text: "New Todo Added: \n" + todo,
          }),
        }
      );
      return { status: "SUCCESS", data: result.rows[0] as any };
    } else {
      return { status: "ERROR", errorMessage: "Insert Failed" };
    }
  } catch (error) {
    console.error("Error:", error);
    return { status: "ERROR", errorMessage: error.message };
  } finally {
    await client.end();
  }
}

export async function update_todo(todo_id: string, status: string) {
  const client = new Client(dbConfig);
  try {
    await client.connect();
    const text = `UPDATE todos SET status = '${status}' WHERE id =${todo_id} RETURNING *`;

    const result = await client.queryObject({ text });
    if (result && result.rows.length > 0 && result.rows[0]) {
      return { returning: result.rows[0], status: "SUCCESS" };
    } else {
      throw new Error("Delete Failed: Todo not found");
    }
  } catch (error) {
    throw new Error("Error : " + error.message);
  } finally {
    client.end();
  }
}

Lets also create a file called config.json with the following contents

config.json
{
  "functions": "./functions/index.ts",
  "vendor": "./vendor",
  "preVendor": true,
  "schemaMode": "INFER"
}

Now lets try to start the TS connector by running the followng command

deno run -A --watch --check https://deno.land/x/hasura_typescript_connβ”‚
ector/mod.ts serve --configuration ./config.json

This will start a TS connector locally on localhost:8100 that can be connected to Hasura now.

Now you can add/ modify the functions and the deno will restart the server in realtime to give you a searmless development experience for your business logic.

Step 7: Add TS Connector, functions & Procedures to DDN.

Lets use add the following lines to the metadata to add the TS connector.

---
kind: DataConnector
version: v1
definition:
  name: functions
  url:
    singleUrl: http://127.0.0.1:8101

The above is a partial definition of a DataConnector, we will now load the DB schema to this definition by using CTRL/CMD + Shift + P and then start typing Hasura: Refresh Data Connecor then choose functions as we have named this datasource functions.

πŸŽ‰ we now have the schema introspected and ready to use in Hasura metadata without any manual authoring.

Now lets Track all functions and procedures by again simply using the extension command. Press CTRL/CMD + Shift + P and then start typing Hasura: Track all collections / functions / procedures / foreign keys from data connector This will add all the metadata objects that you need to get your GraphQL api from all the tables on posgres.

Note: Just like database we can use local tunnel to bring this data connector accessible to Hsaura, for that let's run hasura tunnel create localhost:8100 and replace the singelUrl with the tunnel URL (add http:// to the hostname)

We can now save the metadata file and create another build to test the functions

hasura build create --description "Added database tables"

πŸŽ‰ Whoola, we have a TODO app backend up and running across the globe on Hasura DDN.

Code snippets used

  1. Input validations: Add bad words check
if (!todo) {
  return { status: "error", errorMessage: "Invalid todo text" };
} else if (filter.isProfane(todo)) {
  console.error("Todo text contains bad words");
  return { status: "error", errorMessage: "Todo text contains bad words" };
}
  1. Input sanitization : remove special characters from the todo text todo = todo.replace(/[^\w\s]/gi, "");
// remove special characters from the todo text
todo = todo.replace(/[^\w\s]/gi, "");
  1. API Integrations
const notifySlack = await fetch("https://hooks.slack.com/services/XXXXX", {
  method: "POST",
  headers: {
    "Content-type": "application/json",
  },
  body: JSON.stringify({
    text: "New Todo Added: \n" + todo,
  }),
});

ddn_demo's People

Contributors

soorajshankar avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.