I've been working with the Discord API for many years now, starting out with JDA, a popular library in the Java ecosystem. While I think JDA is a great library, I don't think it has the same "magic" developer experience similar to something like Svelte. So in November 2022, I decided that I'd build my own library for the Discord API—and if it didn't work out? I'd still have learned a lot along the way. Those were my two main goals.
Since this was my first API library, I kept it simple originally by experimenting with basic endpoint calling and response handling. But, I soon realized that I wanted to build a library that was easy to use and had a great developer experience. I wanted to create a library that felt like it was built for developers, something that could actually be used in production.
Over the last 2 years building discord.jar, various things propped up that caused quite significant roadblocks or challenges. Some of these were:
Gateway is Discord's name for their two-way WebSocket API. This is how the real-time aspect of Discord works. Gateway is a monster to implement for a few reasons:
I originally began with Spring's WebSocket API. This did work for quite a while, but it was fairly buggy and didn't support the complexities of implementing Gateway, so eventually the entire Gateway implementation was rewritten using OkHttp instead. This was a huge improvement and allowed for a much more stable and performant library. It just wasn't production ready before OkHttp.
The WebSocket
class handles most of the low-level WebSocket stuff,
and the Gateway
class handles the high-level stuff. The two classes work together to provide a seamless experience for the dev.
I still haven't finished implementing all the Gateway events (or the HTTP endpoints for that matter!) but it's stable enough now, just missing features.
Rate-limiting is also a fairly complex thing to handle in this sort of library. discord.jar supports both asynchronous and synchronous requests to the API which does make it fairly difficult when you run into rate-limits. We handle them in various ways:
This logic is available in the Bucket
class.
Most Discord bots don't need to implement voice, but I wanted to ensure that discord.jar could support it nontheless. This was quite a messy one...
Discord's protocol for connecting to their voice servers is roughly this:
This is a very simplified version of the process, but it does give you an idea of how complex it is. My favourite story to tell
is that when implementing voice, because of a missing this.
, I ended up sending the UDP packets to the bot (the host computer) instead of Discord. That one took a few months... 😂
Overall, building discord.jar has been a great experience. I've learned a lot about building libraries, working with APIs, and the complexities of real-time communication. There are certainly things I would change if I was to create a new library, but I'm still very proud of what I've built as it's, as we speak, being used in production by many bots. There's still more work to be done! More endpoints to implement, more events to handle, but I'm excited to see where discord.jar goes in the future.