CRUD operations with Hypi’s low code APIs

CRUD operations are the backbone of any relational database application. At the user interface level, CRUD operations are relevant as well. Hypi’s low code APIs help you implement CRUD operations in the data-driven application.

Let’s take a look at CRUD operations using Hypi’s low code APIs through this tutorial.

We shall start with a simple question. What does CRUD stand for?

CRUD is an acronym for Create, Read, Update, Delete (CRUD) referring to operations necessary for the persistent storage and retrieval of data.

Hypi is a serverless low code backend platform that provides CRUD APIs (among many others). In Hypi you don’t write CRUD methods, they’re built in i.e., lowcode.

In Hypi you perform Query operations to get data from the database, you perform Mutations to create or update data in the database. Create, Update and Delete are mutations. Read is the Query.

CRUD operations using Hypi’s low code APIs

Consider we are building a social media application platform and we are going to perform CRUD operations on the social media post.

Let’s build schema for the social media post and perform CRUD operations using Hypi’s low code APIs.

Here’s the schema.

type Post {
  postedby: Account @computed(query: "hypi.id = '${self.hypi.createdBy}'")
  date: DateTime
  text: String
  likecount: Int @computedCount(field: "likedby") 
  likedby: [Account!]
  comments: [Post!]
}

Consider Post (GraphQL data type) as a table and the fields like the columns of the table.

Let’s understand the fields in Post. postedby is the account of the person creating the Post on the social media platform. Notice the @computed directive? This works out the Account object by using the built in hypi.id field available on all objects in Hypi. A likecount is the number of likes and likedby is the list of people who liked the post. comment is the list of comments on the post. A comment is considered just like any other post. Different users can post a comment on a particular post which may be further liked/commented on by other users.

When you save the above data type, the hypi field of type Hypi gets created automatically. Hypi is the magic object that holds the unique identifier. It is associated with every object created for a data type. (Here data type is Post). You may set a unique id for an object or Hypi will generate it automatically for you.

Check here how to add schema using GraphQL Editor. Once the schema is saved and the release is published, you can create an instance of the schema. Then you are ready to perform CRUD operations on the instance.

Create Data with low code Hypi API (upsert)

In the CRUD operations, Create is a mutation that inserts data in the table.

Just one API is used to create and update the data in an instance when using Hypi’s CRUD APIs: upsert

Go to GraphQL playground selecting an instance and use upsert to add data in the table as follows.

mutation {
  upsert(
    values: {
      Post: [
        {
          date: "2021-05-07"
          text: "The future is low code!"
        }
      ]
    }
  ) {
    id
  }
}

In the above CRUD operation, we have created a Post object and added the text of the post. The person who posted will be automatically updated in the postedby field. postedby runs the query to extract the username from the account that created the post. Please refer Account table from the set of Core tables provided by Hypi.

You pass the object that you want to create as a ‘values’ parameter to the upsert mutation and specify what fields of the Magic Hypi object you want in the response. Do check the fields in the Magic Hypi Object from the schema. Here only object id is selected and so that’s all that is returned.

{
  "data": {
    "upsert": [
      {
        "id": "01F52TZ03J426MHJYKYRB9Q8PT"
      }
    ]
  }
}

Thus we have successfully created a social media post using the CRUD API of Hypi.

Let’s see now how we can update the post using the same CRUD API, i.e. upsert.

Update Data with low code Hypi API (upsert)

In the CRUD Operations, Update is also the mutation that works similarly like Create.

To update an existing object, we should provide the hypi.id for the object along with the data that we want to save for that object.

Let’s say the created post was liked by two people (Hypi and CRUD). So, update this data in the object created previously.

mutation {
  upsert(
    values: {
      Post: [
        {
          hypi:{
            id: "01F52TZ03J426MHJYKYRB9Q8PT"
          }
          date: "2021-05-07"
          text: "The future is low code!",
          likedby:[
            {
              hypi:{
                id:"01F52T1ZB6FRY7G2293W2MCS52"
              }
            },
            {
              hypi:{
                id:"01F52T57V50CG3MBQE2HNX0SB7"
              }
            }            
          ]
        }
      ]
    }
  ) {
    id
  }
}

In the above CRUD operation, we have passed the same hypi. id that we received while creating the object. And we received the same id as a response.

{
  "data": {
    "upsert": [
      {
        "id": "01F52TZ03J426MHJYKYRB9Q8PT"
      }
    ]
  }
}

For updating the list of accounts who liked the post, we have passed the hypi.id of those accounts (Hypi and CRUD).

Now, we want someone to comment on the field. So, another user should have permission to comment on the post. To do this we will provide all users in our instance with permission to comment on the Post object that we created. Learn more about Permissions here.

mutation {
  upsert(
    values: {
      Permission: [
        {
          name: "Give all users permission to comment"
          decisionStrategy: Unanimous
          type: "Post"
          resource: "01F52TZ03J426MHJYKYRB9Q8PT"
          scopes: ["comments"]
          operationType: Mutation
          operations: ["upsert"]
          includeAllAccounts: true 

        }
      ]
    }
  ) {
    id
  }
}

Here we’ve created a Permission which gives all users in the social network permission to add comments. Specifically, we’ve given all users permision to call the Mutation.upsert function but notice the scopes is set to [comments] this array has a single field, this means any user can call the Mutation.upsert function on the comments field only. If they try to modify any other field they will be given a permission denied error.

Another user (e.g. I created one called CRUD) should log in to the Hypi account using the login function. A session token will get generated. Use this token on the Authorization header in the GraphQL Playground to update the comment on the post.

mutation {
  upsert(
    values: {
      Post: [
        {
          hypi: { id: "01F52TZ03J426MHJYKYRB9Q8PT" }
          comments: [
            { 
              text: "next generation application using low code" 
            }
          ]
        }
      ]
    }
  ) {
    id
  }
}

The response will be the same.

{
  "data": {
    "upsert": [
      {
        "id": "01F52TZ03J426MHJYKYRB9Q8PT"
      }
    ]
  }
}

This way you may perform an Update CRUD operation to modify any object.

Let’s check now how to read the data that we have added with Hypi CRUD APIs.

Read Data with low code Hypi APIs (get, find)

In the CRUD operations, Read works as a query to retrieve data from the table.

Two CRUD APIs are used to read the data from an instance: get and find

Let’s say you want to share the post, so you need to retrieve all the data from the post object. So, you may use the get function from Hypi’s CRUD API. get query provides a single object using the id of the object hypi.id.

The get CRUD operation accepts type and id as parameters and it returns whatever fields you specify for the type that you are using it for.

{
  get(type: Post, id: "01F52TZ03J426MHJYKYRB9Q8PT") {
    ... on Post {
      hypi {
        id
        created
      }
      postedby {
        username
      }
      text
      likedby {
        username
      }
      likecount
      comments {
        text
        hypi {
          createdBy
        }
        postedby {
          username
        }
      }
    }
  }
}

The response will be like this.

{
  "data": {
    "get": {
      "hypi": {
        "id": "01F52TZ03J426MHJYKYRB9Q8PT",
        "created": "2021-05-07T07:16:40Z"
      },
      "postedby": "low code",
      "text": "The future is low code!",
      "likedby": [
        {
          "username": "Hypi"
        },
        {
          "username": "CRUD"
        }
      ],
      "likecount": 2,
      "comments": [
        {
          "text": "next generation application using low code",
          "hypi": {
            "createdBy": "01F52T68AEYJRH74TZJ7F8FBBP"
          },
          "postedby": {
            "username": "CRUD"
          }
        }
      ]
    }
  }
}

Let’s say you want to show the posts by a user on his timeline, you may retrieve all the posts by the find CRUD operation. It scans all the objects of a specific type and returns the data as needed.

{
  find(type: Post, arcql: "*") {
    edges {
      node {
        ... on Post {
          hypi {
            id
            created
          }         
          postedby {
           username
          }
          text
          likedby {
            username
          }
          likecount
          comments {
            text
            postedby {
              username
            }
            hypi {
              createdBy
            }
          }
        }
      }
      cursor
    }
  }
}

Result follows. Please note that it returns comments field as separate ‘Post’ object.

{
  "data": {
    "find": {
      "edges": [
        {
          "node": {
            "hypi": {
              "id": "01F52TZ03J426MHJYKYRB9Q8PT",
              "created": "2021-05-07T07:16:40Z"
            },
            "text": "The future is low code!",
            "likedby": [
              {
                "username": "Hypi"
              },
              {
                "username": "crudapi"
              }
            ],
            "likecount": 2,
            "comments": [
              {
                "text": "next generation application using low code",
                "postedby": {
                  "username": "CRUD"
                },
                "hypi": {
                  "createdBy": "01F52T68AEYJRH74TZJ7F8FBBP"
                }
              }
            ]
          },
          "cursor": "01F52TZ03J426MHJYKYRB9Q8PT"
        },
        {
          "node": {
            "hypi": {
              "id": "01F531WTD1K9PA575F3CRXTNB9",
              "created": "2021-05-07T09:17:48Z"
            },
            "text": "next generation application using low code",
            "likedby": null,
            "likecount": 0,
            "comments": null
          },
          "cursor": "01F531WTD1K9PA575F3CRXTNB9"
        }
      ]
    }
  }
}

You may filter the data with an arcql query and retrieve the results. In the above CRUD operation, we have used wildcard * as the parameter indicating that we want all the Posts.

Delete Data with low code Hypi APIs (trash, delete)

In the CRUD operations, Delete works as a Mutation to remove data from the table.

You can either perform soft delete to temporarily remove data or delete the data altogether.

Soft delete is executed using the trash function. With trash, your data may appear deleted. But you can restore it if required. Let’s trash a post object for now.

mutation {
  trash(type: Post, 
  arcql: "hypi.id = 01F52TZ03J426MHJYKYRB9Q8PT ")
}

If you use the get or find queries now, the result will not display the trashed object by default. You must set the includeTrashed parameter to true to get the object.

The opposite of the trash function is untrash. Use this function to remove the marker from the data that was previously marked as trash.

mutation {
  untrash(type: Post, 
  arcql: "hypi.id = 01F52TZ03J426MHJYKYRB9Q8PT ")
}

Both functions return the number of records that were marked trashed/untrashed.

If you want to delete the post permanently, use the delete function.

mutation {
  delete(type: Post, 
  arcql: "hypi.id = 01F52TZ03J426MHJYKYRB9Q8PT ",
  clearArrayReferences:true)
}

Setting clearArrayReferences to true removes the references between objects and performs delete CRUD operation without an error. Here, original post and comment posts get unlinked and the object gets deleted. If we didn’t set clearArrayReferences to true, you’d get an error because the it would leave orphaned objects (data that used to link to something that has been deleted). Here we forced the post to be deleted but the comments still exist, this is normally not what a user would expect. This is where cascading deletes should be used – when cascading delete is used, the Post will be deleted and any child objects it links to e.g. the comments and anything they link to and so on.

Concluding Note

In this tutorial, we’ve shown you the basic CRUD operations available in Hypi. You should have a fair idea by now how to use Hypi’s low code APIs to execute CRUD Operations. This is the basics, but is pretty powerful. A large portion of many applications can be built with these APIs only. For custom features written in your favourite language, take a look at user defined functions or serverless functions among many other features.

1 Like