Skip to content

Instantly share code, notes, and snippets.

@AlexanderHott
Last active January 30, 2023 06:03
Show Gist options
  • Save AlexanderHott/09923a94a2e9fefa5c96d2bf3940a27c to your computer and use it in GitHub Desktop.
Save AlexanderHott/09923a94a2e9fefa5c96d2bf3940a27c to your computer and use it in GitHub Desktop.

Hikari for beginners

A beginners guide to using hikari.

⚠️ NOTE

Before this goes public

  • replace all the images/examples with hikari specific ones
  • review by hikari developers

Prerequisites

Some prerequisites for writing a Discord bot in python.

Required:

  • Primitive data types
  • Operators
  • Control flow
  • Function definitions
  • String formatting
  • Variables, namespace and scope
  • Importing
  • Classes, objects, attributes and methods
  • OOP
  • Data structures
  • Exception handling
  • Console usage, interpreters and environments
  • Decorators

Useful to know:

  • Databases
  • asyncio basics
  • What is "blocking?"
  • Logging
  • Reading documentation properly

Vocab

You should be familiar with Discord's features and naming conventions when writing your bot.

User

A discord user.

user

Member

A user in the context of a guild. Discord introduced server-specific customization for users recently (server profiles).

member

Message

A container for content that a user or bot sends in a channel. This can be text, media, stickers, etc.

message

Ephemeral Message

A message that only you can see. They can be easily dismissed.

ephemeral message

Channel

Text Channel

A channel that members can send messages in.

channel

Voice Channel

A channel that members connect to and can transmit and receive audio and video.

voice channel

News Channel

A channel where a server (server owner or admin) can publish announcements and other servers can "follow" that channel.

new channel

Category

An ordered collection of channels in a drop down.

category

Guild

A server. More specifically, a collection of channels that members of the guild can interact with.

guild icon guild channels

Component

Buttons and select menus.

buttons select menu

Application Command

Slash Command

Commands registered with Discord that appear when you type / in a text channel.

slash command

💡 Slash commands are discord's attempt at a better user experience when interacting bots. Previously, each bot had it's own prefix, and needed to read each incoming message to check if it started with the prefix. Remembering the prefix, viewing all the available commands, and validating user input was not a simple task, and you better hope that the bot developer lets you change the prefix so multiple bots don't respond to ?help. Slash commands solve this by requiring your bot to register the commands with discord.

Menu Command

Commands regisered with Discord that appear under the "apps" context menu of messages and users.

user menu commands message menu command

Embed

A bot specific content type that looks better than plain text.

image

Thread

A text channel within a text channel

thread

Modal

A modal that a user can input content into. Currently, they only accept text

modal

Intro

Hikari is a wrapper for the Discord API, meaning that it abstracts some of the API usage by providing convince classes and methods, and an includes an event manager to handle incoming events. Before we cover what separates Hikari from other libraries, let's cover the basics of the Discord API.

The Discord API is a collection of three smaller APIs: the REST API, the API Gatway, and interaction webhooks.

REST API

The REST API is for performing CRUD (create, read, update, delete) operations. For example, you could create a role or update a channel.

API Gateway

Discord API Gateway docs

The API Gateway is for sending and receiving events.

An event is a notification that something happened. For example, when a channel is updated, your bot will receive a channel update event. Full list of events.

The Gateway is also used for receiving and responding to interactions.

An interaction is a notification that a user interacted with your bot through a slash command or message component. [TODO link]

The difference between events and interactions is that interactions are specific to bots. Interactions are created when a user interacts with a bot, but events are created when a user interacts with Discord in general.

Your bot also sends events to connect to the Gateway, but hikari handles that for us.

Interaction Webhooks

Discord docs

Interaction webhooks are for receiving responding to interactions without a bot.

However, a bot is required for interacting with the API Gateway and REST API, so we won't be covering interaction webhooks in this guide.

What Sets Hikari Appart from Other Libraries

Hikari has a few amazing features that discord.py and it's forks don't have.

Programming Patterns

Python classes have quite a bit of runtime overhead regarding memory because they have a lot of extra methods and attributes that are required for python to function. Even when adding __slots__, not using a class results in a ~90% memory reduction.

Hikari allows you to skip creating intermediary objects. For example, if you wanted to edit a channel, discord.py code might look like

guild = ctx.get_guild()
channel = guild.get_channel(123)
await channel.edit(name="new name")

while the hikari code looks like

await ctx.bot.rest.edit_channel(123, name="new name")

Cache Control

Hikari's cache stores objects so you don't have to fetch them from the REST API. Unlike other caches, hikari's cache always up to date. On startup, it pre-populates the cache in a process called chunking, and on every event your bot receives, it will update accordingly. For example, when a user changes their nickname in a server, your bot will receive a member update event, and hikari will update it's cache to reflect the new changes.

Hikari's cache can be enabled and disabled on an object-by-object basis. For example, you can remove the presence cache because it takes up a lot of memory and gets updated frequently.

Methods that get items from the cache start with a get_ and return either a CacheView (which can be treated like a dict) or T | None. Because you can disable parts or all of cache, you are not guarenteed to get anything, so a common pattern is to use the fetch_ alternative to fetch the resource from the REST API in a short circiut or using the := operator.

member = (
  bot.cache.get_member(123) or
  await bot.rest.fetch_member(123)
)

Note: fetch_member will run only if bot.cache.get_member(123) returns None.

if (member := bot.cache.get_member(123)) is not None:
    # Do something with the member
    await ctx.respond(member.mention)

A Strong Type System

Hikari is statically typed which makes it easy to work with. It's type system is very powerful, following similar patterns to traits in Rust's. For example, if you want to send a message in a channel, that channel class needs to subclass TextableChannel which has the send method. This is very powerful in isinstance checks because we don't care what type of channel it is, we just need to know we can send messages in it.

channel = (
    bot.cache.get_guild_channel(123)
    or await bot.rest.fetch_channel(123)
)

if isinstance(channel, hikari.TextableChannel):
    await channel.send("Hello")

Read more about Rust's traits in the Rust Book.

Hikari has it's own undefined type to explicitly denote an omitted value. We need a way to signify an empty value to Discord and using None might bring unexpected behavior to the developer.

Low Level

Hikair exposes a lower level API, compared to discord.py, where you can manually create, update, and defer interaction responses. Reasons why you need this fine grained control are: TODO

Command Handlers

Because Hikari doesn't come with a built-in command handler (like discord.ext.commands), because hikari was developed to be extendable and reusable, rather than an obstacle for future development. You either need use another library or write one yourself.

Command handlers help with creating and registering commands with Discord and creating event listeners to handle incoming events from the Gateway.

Command handlers can also help with code organization by grouping commands and event listeners into plugins. A plugin is just a collection of commands and event listeners.

There are currenly three command handlers that each have their own pros and cons, so check them all out before sticking to one.

Moving Forward

Some other useful libraries to be aware of

  • Miru: A component handler. This is a must have if you are working with components (e.g. buttons).
  • Uvloop: A faster version of the asyncio event loop (only available on linux)

Examples

Example slash commands with lightbulb https://gist.github.com/AlexanderHOtt/7805843a7120f755938a3b75d680d2e7

Scaling Guide

TOOD. In the mean time, join the discord and check out the #clusters channel

  • intents
  • ratelimiting
  • sharding
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment