<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dhaval_Rasputala</title>
    <description>The latest articles on DEV Community by Dhaval_Rasputala (@dhavalrasputala).</description>
    <link>https://dev.to/dhavalrasputala</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4035969%2Feb24207d-edff-42d7-9908-2f6d4d2a2287.png</url>
      <title>DEV Community: Dhaval_Rasputala</title>
      <link>https://dev.to/dhavalrasputala</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dhavalrasputala"/>
    <language>en</language>
    <item>
      <title>Building GateKeeper: Designing a Role-Based Access Control Library in Pure Go</title>
      <dc:creator>Dhaval_Rasputala</dc:creator>
      <pubDate>Sun, 19 Jul 2026 03:20:56 +0000</pubDate>
      <link>https://dev.to/dhavalrasputala/building-gatekeeper-designing-a-role-based-access-control-library-in-pure-go-5a7e</link>
      <guid>https://dev.to/dhavalrasputala/building-gatekeeper-designing-a-role-based-access-control-library-in-pure-go-5a7e</guid>
      <description>&lt;p&gt;As developers, we use authorization libraries almost every day. Whether it's a web application, an API, or an internal tool, we often rely on packages that decide who can do what.&lt;/p&gt;

&lt;p&gt;But I realized I had never actually built one.&lt;/p&gt;

&lt;p&gt;So instead of using an existing library, I decided to build my own Role-Based Access Control (RBAC) library in Go using only the standard library.&lt;/p&gt;

&lt;p&gt;This project eventually became GateKeeper v1.0.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Built One
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;As a beginner in backend development, I wanted to get exposure on how to make public APIs and how to make them work under the hood.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It also made me fight my old syntax habits. Go has strict error handling, which I also learned.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I built it because I wanted to understand the engineering decisions behind public libraries. Instead of watching another tutorial, I built it myself.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Goals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Before writing any code, I brainstorm the architecture in my mind.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No external library used, only the standard Go library.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keeping the public APIs simple and easy to read for developers to use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write tests for each and every function, no matter how small.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These constraints forced me to think more carefully about the design instead of depending on external packages.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Engine
├── Users
├── Roles
└── Permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Relationships are straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Users
  |
  V
Roles
  |
  V
Permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;A user can have multiple roles, and roles can have multiple permissions.&lt;/li&gt;
&lt;li&gt;Permissions describe access to a resource and an action.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Designing The API
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One thing I learned the hard way is that API design matters more than the implementation itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I wanted to keep the library easy to read even without documentation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The public API ended up looking something like this:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateUser()
CreateRole()
CreatePermission()

AssignRole()
AssignPermission()

Can()

DeleteUser()
DeleteRole()
DeletePermission()

RenameUser()
RenameRole()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I had to redesign the API many times before eventually coming up with the final one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The time spent fighting the design was worth it. It taught me API design and how to think about architecture rather than just implementation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bugs I Found Along The Way
&lt;/h2&gt;

&lt;p&gt;One of the most interesting bugs appeared when deleting roles.&lt;/p&gt;

&lt;p&gt;Initially, my implementation simply deleted the role.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Delete Role
    |
    V
Role disappears
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That looked correct.&lt;/p&gt;

&lt;p&gt;Until I realized users still stored that role ID. But the role no longer existed. The system had entered an invalid state.&lt;/p&gt;

&lt;p&gt;The correct solution wasn't just deleting the role. It was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Delete Role
    |
    V
Remove role from every user
    |
    V
Delete Role
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same issue existed when deleting permissions.&lt;/p&gt;

&lt;p&gt;That experience introduced me to the idea of maintaining referential integrity, something I had previously only encountered in databases.&lt;/p&gt;

&lt;p&gt;Another bug that surprised me, and almost went unseen, was about slices.&lt;/p&gt;

&lt;p&gt;Slices in Go point to their backing array, which means if we send a user a copy of &lt;code&gt;User&lt;/code&gt;, that user can modify the internal state of the engine, which can cause problems.&lt;/p&gt;

&lt;p&gt;The fix was to make defensive copies of the slices before returning them.&lt;/p&gt;

&lt;p&gt;That bug taught me more about Go's memory model than several hours of reading documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons I Learned
&lt;/h2&gt;

&lt;p&gt;As a beginner, you are always fighting two battles while learning: one with the programming language, and the other with the architecture you want to create.&lt;/p&gt;

&lt;p&gt;By making this project, I not only had to think about correct, production-ready architecture, but also had to learn about Go's underlying structure.&lt;/p&gt;

&lt;p&gt;This project made me learn many topics that are important for a beginner, like encapsulation, API design, maintaining invariants, and designing software that remains consistent after every operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building software from scratch is a very different experience from using libraries.&lt;/p&gt;

&lt;p&gt;You begin to appreciate the small design decisions that make software reliable.&lt;/p&gt;

&lt;p&gt;GateKeeper started as an exercise in learning authorization. It ended up teaching me much more about software engineering than I expected.&lt;/p&gt;

&lt;p&gt;If you have any suggestions or feedback, I'd be happy to hear them.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/dhavalrasputala/gatekeeper" rel="noopener noreferrer"&gt;GateKeeper&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>go</category>
      <category>backend</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
