Skip to main content

Command Palette

Search for a command to run...

How to Query Records by Protocol Path

Web5 Discovery Guides

Updated
5 min read
How to Query Records by Protocol Path
R

Developer Advocate @ GitHub

Starting a new job is thrilling because I get to learn new things. At my new job, I'm learning about Web5 and decentralization. So, I'm writing this blog post to share my insights about protocols and querying records.

When I built my first Web5 application in July, I explored how to store data in a Decentralized Web Node (DWN)—a personal data store in the Web5 ecosystem. I can write, edit, delete, and read data, also known as records, to my DWN.

To interact with data in my DWN, I need a Decentralized Identifier (DID). DIDs are unique IDs in the digital world. DIDs also act as keys to accessing and manipulating data in a DWN. I think of it like a password to access a database.

Although these were fairly new concepts, I drew parallels to help me understand. In my mind, I compared a DWN to a database and a DID to credentials that help users access a database.

However, there were some technical guidelines that initially confused me. For example – by default, I cannot write data to someone else's DWN unless I have been granted permission to do so. I wasn't sure how to grant permission for a user to write to my DWN. Similarly, I wasn't sure how another user could give me permission to write or read data on their DWN.

Apparently, the solution is to use a protocol! A protocol, structured as a JSON document, outlines the data structure, defines data types, and establishes rules for data access and interaction within a DWN. In other words, protocols enable users to control who can read or write specific types of data to your DWN.

Defining a protocol

I wrote a protocol definition for a chat application:

 const chatProtocolDefinition = {
      protocol: "https://blackgirlbytes.dev/ChatProtocol",
      published: true,
      types: {
        message: {
          schema: "https://schema.org/Message",
          dataFormats: ["application/json"],
        },
        audio: {
          schema: "https://schema.org/AudioObject",
          dataFormats: ["audio/mp3"],
        },
        video: {
          schema: "https://schema.org/VideoObject",
          dataFormats: ["video/mp4"],
        },
        image: {
          schema: "https://schema.org/ImageObject",
          dataFormats: ["image/png"],
        },
        gif: {
          schema: "https://schema.org/ImageObject",
          dataFormats: ["image/gif"],
        },
      },
      structure: {
        message: {
          $actions: [
            { who: "anyone", can: "write" },    
            { who: "author", of: "message", can: "read" },    
            { who: "recipient", of: "message", can: "read" },
          ],
          audio: {
            $actions: [
              { who: "anyone", can: "write" },    
              { who: "author", of: "video", can: "read" },    
              { who: "recipient", of: "video", can: "read" },
            ],
          },
          video: {
            $actions: [
              { who: "anyone", can: "write" },    
              { who: "author", of: "video", can: "read" },    
              { who: "recipient", of: "video", can: "read" },
            ],
          },
          image: {
            $actions: [
              { who: "anyone", can: "write" },    
              { who: "author", of: "video", can: "read" },    
              { who: "recipient", of: "video", can: "read" },
            ],
          },
          gif: {
            $actions: [
              { who: "anyone", can: "write" },    
              { who: "author", of: "video", can: "read" },    
              { who: "recipient", of: "video", can: "read" },
            ],
          },
        },
      },
    };

This protocol definition supports various message types: text, audio, gif, video, or image. It also grants permissions to different groups of users. In this particular example, anyone can create a message, but the author and recipient also have permission to read messages. For clarity, this means anyone can write a message to the DWN, but only the recipients and senders can read the messages that they sent and received.

Sidenote: This method is an amazing way to intentionally architect applications.

Here's a brief explanation of some of the properties listed in the protocol definition:

  • types - Defines all the elements used in a protocol

  • structure - Outlines the relationship and interaction rules between different types

  • $actions - Specifies a set of permissions outlining who is allowed to perform specific actions like reading or writing on a given type

Installing a protocol

After I defined my protocol, I installed the protocol to my DWN. Installing the protocol enables my DWN to recognize and adhere to the rules and structures I've established. Here's how to install the protocol for the chat application:

const { protocolStatus } = await web5.dwn.protocols.configure({
  message: {
    definition: chatProtocolDefinition,
  },
});

Problem: I want to filter for specific records

My protocol is defined and installed, so I can use it now! But there's a problem. I only want to return GIFs for a new feature in my chat application.

This new feature will display a gallery of users' most frequently used GIFs to help users conveniently retrieve the GIFs they want to use during conversation. I could fetch all the records on my DWN and then filter using an Array method on the cl. But, that could be inefficient.

Solution: Query by protocol path

One way I can address this is to query by protocolPath. I can pass the name of my structure as a value for my protocolPath property. In the protocol definition, gif is nested inside a message structure. Therefore, the protocol path for a gif is message/gif.

The query below will only fetch the GIF records:

const { records } = await web5.dwn.records.query({
  message: {
    filter: {
      protocol: "https://blackgirlbytes.dev/ChatProtocol",
      protocolPath: "message/gif",
    },
  },
});

Other ways to query records

There are other ways to query records using the Web5 JS SDK. You can find a list of filterable record properties in the documentation. I’ve listed a couple of examples for your convenience:

Query Records by Record ID

The snippet below will return a record with the record ID: bfw35evr6e54c4cqa4c589h4cq3v7w4nc534c9w7h5

const { record } = await web5.dwn.records.query({
  message: {
    recordId: "bfw35evr6e54c4cqa4c589h4cq3v7w4nc534c9w7h5",
  },
});

Query Records by Data Format

The snippet below will return all records that have an application/json data format.

const response = await web5.dwn.records.query({
  message: {
    filter: {
      dataFormat: 'application/json'
    }
  }
});

Read the documentation

Remember that this technology is evolving rapidly! Web5 is in active development and technical preview. For the most current information and guidance on querying records in Web5, always refer to the official Query DWN Records guide.

Knowledge check

Excited to continue learning

Every Friday, the Developer Relations team has been spending time learning in public about Web5. Join us on Twitch.tv/tbdevs. Check out a preview below

You can watch the full episode here

Like this content?

For more content like this, follow TBDevs and me!

C

Hello, I just wanted to say thanks for your post; it was a fascinating read. It mentioned the following protocol URL when I was reading it: https://blackgirlbytes.dev/ChatProtocol. Upon attempting to access it, I found that the hyperlink does not seem to lead to an active webpage.

Given how often non-functional URLs are included with protocol specs, I'm curious as to if this is really a placeholder URL used for illustration. Could you please confirm if the URL to be used when defining a protocol is meant to be a working example or a valid one?

Thank you again for this post.

1
R

Hi! Your protocol doesn't have to be hosted anywhere. Your protocol will still work if you use a uri that's not resolvable aka it returns a 404. But the point of it is for it to be unique and descriptive. That way you can identify it between other protocols..and you know what it's being used for.

My strategy for now is I usually use a domain I already own..which is blackgirlbytes.dev and then I add on something that describes the protocol like https://blackgirlbytes.dev/chat-protocol or https://blackgirlbytes.dev/contacts-protocol

These addresses will lead you to a 404, but they help me know what the protocol is supposed to do.

1
C

@blackgirlbytes

Thank you for the reply. I get it now. I got confused at first when all the protocol URLs I saw were leading to non-existent pages.

Thank you very much 😊

More from this blog

B

Black Girl Bytes

58 posts

I'm a Developer Advocate at GitHub. I'm passionate about community, code, and education! Reach out to me on Twitter ❤️