<?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>Forem: Sebastian Pavel</title>
    <description>The latest articles on Forem by Sebastian Pavel (@zerk4).</description>
    <link>https://forem.com/zerk4</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F826813%2Fd0ce3117-fc1c-43ca-9138-41a5f94f8976.jpeg</url>
      <title>Forem: Sebastian Pavel</title>
      <link>https://forem.com/zerk4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zerk4"/>
    <language>en</language>
    <item>
      <title>I was tired of arcane query syntax and tab switching, so I built Loguro</title>
      <dc:creator>Sebastian Pavel</dc:creator>
      <pubDate>Sat, 28 Mar 2026 21:46:00 +0000</pubDate>
      <link>https://forem.com/zerk4/i-was-tired-of-arcane-query-syntax-and-tab-switching-so-i-built-loguro-i6j</link>
      <guid>https://forem.com/zerk4/i-was-tired-of-arcane-query-syntax-and-tab-switching-so-i-built-loguro-i6j</guid>
      <description>&lt;p&gt;I personally had a pain point with logs. I never understood the complicated UIs, all the charts, all the metrics, everything the premium tools throw at you.&lt;/p&gt;

&lt;p&gt;I still had to install an SDK. I still needed to learn some arcane query syntax just to filter logs. Debugging should be easy, we already break our heads writing code, making it understandable by others, dealing with deadlines. The last thing I want is to read docs when something breaks on my production, or worse, on a client's production.&lt;/p&gt;

&lt;p&gt;That's why I built Loguro. My debugging partner should understand English — almost as if I was talking to myself.&lt;/p&gt;

&lt;p&gt;level:error|critical message:"database timeout" &lt;a class="mentioned-user" href="https://dev.to/today"&gt;@today&lt;/a&gt;&lt;br&gt;
Simple, on point. No docs needed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I don't like noise. I might have 1k logs from a single error — a lot of rows to scroll through. Loguro transforms repeated patterns into groups, so I see 1000x and can expand them directly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I need to see how it happened. There are tools that replay UI interactions, but what about the backend? Server started hiccuping, then something else happened, then dead. Normally I end up hunting traces and timestamps across 10 tabs.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;from:"1 hour ago" to:"5 minutes ago" --replay&lt;br&gt;
Renders a widget, I watch my logs come back in sequence like a time machine. No tabs, no traces, just the story.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I have the error. I know how it happened. Now I need to create a task. Normally I open Jira or Linear, navigate to the right project, create the issue, switch tab, copy the log message, paste it as the title, go back for context, go back again, submit, copy the URL, open Slack, post to the team channel... you see where this is going.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;--task:jira --send:slack#team&lt;br&gt;
I add the relevant logs to context, hit the command or type it in the same query bar, press cmd+enter. That's it. Task created, Slack notified with the link and details. I can go to sleep.&lt;/p&gt;

&lt;p&gt;And that log? It lives forever, even if the retention is 24 hours, a log that becomes a task never gets deleted.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Months have passed. I consider myself a decent developer, but that goddamn error is back, and it brought friends. Normally I go hunting. Search through thousands of issues, hope it sounds familiar, spend minutes or hours finding the first occurrence. Then switch back to the logging tool, compare, check if it's the same pattern, check if the old fix still applies...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Loguro, when a log was tasked, it remembers. New logs matching the same pattern are automatically marked as "seen before." I click it, see the original task, the comments, the context, the smart dude who "fixed" it last time — and decide what to do next. No hunting, no tab switching, no déjà vu.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One more thing — as a good dev, I sometimes send logs with stringified JSON inside the message field. Perfectly normal, yea? Loguro handles it with --separate::message, pulls that JSON out of the message and puts it where it belongs, in the context. Clean log, no noise.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything is managed from a command palette — my account, billing, usage, API keys, notification channels and integrations. All of it, without touching the mouse.&lt;/p&gt;

&lt;p&gt;Loguro is packed with a handful of features which I hope make it stand out and provide value on the already saturated market.&lt;/p&gt;

&lt;p&gt;I would love some feedback — on the product, the landing page, and the docs. On the footer there's a link to the Discord server, I'm there if you need anything. And once inside the app, --feedback sends feedback directly from anywhere.&lt;/p&gt;

&lt;p&gt;You can have a look too at &lt;a href="https://logu.ro" rel="noopener noreferrer"&gt;loguro&lt;/a&gt;&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>How I Turned a Logging Dashboard into a Keyboard-First CLI-ish ⚡️</title>
      <dc:creator>Sebastian Pavel</dc:creator>
      <pubDate>Tue, 10 Mar 2026 22:33:00 +0000</pubDate>
      <link>https://forem.com/zerk4/how-i-turned-a-logging-dashboard-into-a-keyboard-first-cli-ish-1mcb</link>
      <guid>https://forem.com/zerk4/how-i-turned-a-logging-dashboard-into-a-keyboard-first-cli-ish-1mcb</guid>
      <description>&lt;p&gt;When building Loguro, I had a realization: developers don't want to click through 15 pages to find a log, configure an alert, or create a Jira ticket. We live in our terminals and IDEs, where we just hit &lt;code&gt;Cmd/Ctrl + K&lt;/code&gt; and type what we want.&lt;/p&gt;

&lt;p&gt;I decided to bring that exact experience to observability. Instead of building a complex "flight-simulator" dashboard with endless toggle switches and dropdown menus, I built Loguro around two core ideas that changed everything about how I interact with logs.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;"The Loguro Way."&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The "Smart" Input Bar
&lt;/h3&gt;

&lt;p&gt;Most logging tools force you to build queries visually or force you to learn a proprietary syntax just to filter out the noise. In Loguro, the entire experience is anchored by a single input field that feels alive.&lt;/p&gt;

&lt;p&gt;It's not just a search bar; it's a context-aware engine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Natural Macros:&lt;/strong&gt; Found a query that catches failed checkout attempts? You don't need to bookmark a URL. Just hit &lt;code&gt;Cmd + S&lt;/code&gt; or &lt;code&gt;--save:failed-checkouts&lt;/code&gt; to save it as &lt;code&gt;failed-checkouts&lt;/code&gt;. The next time you type &lt;code&gt;#fail...&lt;/code&gt;, inline ghost-text autocompletes the entire complex query for you, &lt;code&gt;TAB&lt;/code&gt; and &lt;code&gt;CMD ENTER&lt;/code&gt; it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Syntax Hints:&lt;/strong&gt; As you type, the input animates placeholder queries and uses reactive state to show you context-aware syntax hints right below the bar. You never have to leave the page to read documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. A True Command Palette (The Global CLI)
&lt;/h3&gt;

&lt;p&gt;The real magic is the command palette. By hitting &lt;code&gt;Cmd + K&lt;/code&gt;, you don't just get a simple page jumping navigation tool. &lt;/p&gt;

&lt;p&gt;If you type &lt;code&gt;--&lt;/code&gt;, the palette transforms into a fully-functional CLI. It’s perfectly rigged with fast Tab-completion. It feels exactly like using a local terminal, allowing you to instantly jump between your Logs, Alerts, or API Keys pages, and execute deep commands on the fly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Power of a Command-Driven Plugin Ecosystem 🧩
&lt;/h3&gt;

&lt;p&gt;How do you keep the core UI completely minimalistic while offering enterprise features? &lt;strong&gt;You don't hardcode them.&lt;/strong&gt; You build an isolated plugin architecture.&lt;/p&gt;

&lt;p&gt;Every major action in Loguro is powered by isolated plugins that listen to your commands within the CLI. This means the UI only shows you the tools you need &lt;em&gt;exactly&lt;/em&gt; when you ask for them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Visibility (Timeline &amp;amp; Downloads):&lt;/strong&gt; Need a visual representation of your filtered logs? Just type &lt;code&gt;--timeline&lt;/code&gt; and a temporal graph instantly appears in your results panel. Need those logs for offline analysis? Type &lt;code&gt;--download:csv&lt;/code&gt; or &lt;code&gt;--download:parquet&lt;/code&gt;, provide an optional expiration time (e.g., &lt;code&gt;24h&lt;/code&gt;), and Loguro generates an optimized archive on the spot. You can even type &lt;code&gt;--download:list&lt;/code&gt; to manage your previous exports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant Security (API Keys):&lt;/strong&gt; Rotating or generating keys shouldn't involve hunting through a deep settings page. Type &lt;code&gt;--keys&lt;/code&gt; to view your active tokens, or simply type &lt;code&gt;--keys:my-new-token&lt;/code&gt; to instantly create one without leaving the page. To revoke it, just type &lt;code&gt;--keys:my-new-token:delete&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant Issue Tracking (Jira, Linear, GitHub):&lt;/strong&gt; See a critical exception? Don't copy-paste the stack trace into a new browser tab. Just type &lt;code&gt;--task:linear:LOG_ID&lt;/code&gt; directly in the command palette. Loguro will instantly parse the command, generate a task preview with the exact log context attached, and create the ticket the moment you hit &lt;code&gt;Enter&lt;/code&gt;, include --send:slack to automatically send the ticket and details to the configured channel. Or type &lt;code&gt;--tasks:list:jira&lt;/code&gt; to show all created Jira issues globally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frictionless Messaging (Slack, Discord):&lt;/strong&gt; Need to notify the team about a spike in errors? Type &lt;code&gt;--send:slack:"Hey team, seeing a lot of 500s here."&lt;/code&gt; Loguro will bundle the current context and push an alert straight to your configured channel. For setup, simply typing &lt;code&gt;--config:slack&lt;/code&gt; brings up the zero-click configuration panel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By treating operations like analyzing timelines, generating encrypted archives, and managing access tokens as isolated "commands," the dashboard stays completely out of your way until you summon it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Vision
&lt;/h3&gt;

&lt;p&gt;The Loguro way is about treating your logging platform like your favorite code editor. It should be fast, keyboard-driven, and infinitely extensible through plugins, rather than bogged down by UI clutter.&lt;/p&gt;

&lt;p&gt;While user-created custom plugins aren't available &lt;em&gt;yet&lt;/em&gt; (you can't write your own in the dashboard), this foundation ensures that adding new integrations or custom commands natively in the future is just plugging them into the command registry.&lt;/p&gt;

&lt;p&gt;If you're tired of reaching for your mouse every time an alert fires or you need to download a CSV, you might enjoy this approach.&lt;/p&gt;

&lt;p&gt;You can give it a spin at &lt;a href="https://logu.ro" rel="noopener noreferrer"&gt;loguro&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>devops</category>
      <category>productivity</category>
      <category>logging</category>
    </item>
    <item>
      <title>Logging shouldn't feel like flying a spaceship 🚀</title>
      <dc:creator>Sebastian Pavel</dc:creator>
      <pubDate>Wed, 04 Mar 2026 22:26:00 +0000</pubDate>
      <link>https://forem.com/zerk4/logging-shouldnt-feel-like-flying-a-spaceship-3feh</link>
      <guid>https://forem.com/zerk4/logging-shouldnt-feel-like-flying-a-spaceship-3feh</guid>
      <description>&lt;h2&gt;
  
  
  Why I Built Loguro: Logging Shouldn't Feel Like Flying a Spaceship 🚀
&lt;/h2&gt;

&lt;p&gt;When I started building &lt;strong&gt;Loguro&lt;/strong&gt;, I had one simple mission: &lt;strong&gt;Keep logging simple.&lt;/strong&gt; That’s it.&lt;/p&gt;

&lt;p&gt;Whenever I show it to people, the first thing I hear is: &lt;em&gt;"But we already have Axiom, Datadog, and all these massive solutions."&lt;/em&gt; True. But those tools are built for a scale that often brings unnecessary friction. You end up paying for features you don't use, navigating "flight-simulator" dashboards, and learning proprietary query languages just to find a single error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loguro is the "no-noise" SaaS alternative.&lt;/strong&gt; I wanted a tool where the tech stays out of the way so you can focus on the code.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠 The Philosophy: Focus on the Code, Not the Tool
&lt;/h2&gt;

&lt;p&gt;The goal for Loguro is to stay out of your way. It is a tool where you don't need to hunt for buttons or navigate complex pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Human-First Querying
&lt;/h3&gt;

&lt;p&gt;Write filters the way you'd explain them to a colleague. No syntax manuals needed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;level:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter by severity&lt;/td&gt;
&lt;td&gt;&lt;code&gt;level:error&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Natural time&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@today&lt;/code&gt; or &lt;code&gt;@10minutesago&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;from: and to:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Still natural time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;from:"10 days ago" to:"yesterday"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;!message:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exclude the noise&lt;/td&gt;
&lt;td&gt;&lt;code&gt;!message:"cache miss"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;context.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deep-dive fields&lt;/td&gt;
&lt;td&gt;&lt;code&gt;context.user_id:42&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trace.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Follow a trace send with &lt;code&gt;X-Request-ID&lt;/code&gt; header&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trace."uuid"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2. The "Mouse-Free" Workflow ⌨️
&lt;/h3&gt;

&lt;p&gt;I’m obsessed with keeping you on the keyboard. If you have to reach for your mouse, I’ve failed as a designer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Autocompletion:&lt;/strong&gt; It’s smart and it’s fast. Hit &lt;code&gt;Tab&lt;/code&gt; and it’s there for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saved Views:&lt;/strong&gt; &lt;code&gt;Cmd/Ctrl + S&lt;/code&gt; to save a complex query, &lt;code&gt;Cmd/Ctrl + B&lt;/code&gt; to browse them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command Palette:&lt;/strong&gt; &lt;code&gt;Cmd/Ctrl + K&lt;/code&gt; to jump between Logs, API Keys, and Alerts instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focused and don't know a query?:&lt;/strong&gt; &lt;code&gt;Cmd/Ctrl + /&lt;/code&gt; opens the help from the advanced search.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡️ Performance that Bites
&lt;/h2&gt;

&lt;p&gt;Don't let the "simple" UI fool you. Under the hood, the engine is a beast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sub-500ms query times&lt;/strong&gt; on 50M+ logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;45k+ req/s&lt;/strong&gt; ingestion on single requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;500k+ logs/s&lt;/strong&gt; in batch mode.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Key Features at a Glance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Signal Monitors (Alerts):&lt;/strong&gt; Set up a per-project alert in 5 clicks from the UI, or &lt;strong&gt;2 clicks&lt;/strong&gt; directly from a log line you’re currently investigating.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace Discovery:&lt;/strong&gt; Traces are first-class citizens. Click a trace ID to instantly follow the entire request lifecycle. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log Detail View:&lt;/strong&gt; One-click copy for Trace IDs, IDs, or the full JSON context. Visual styling changes based on log severity so you can spot errors in a sea of info. Find anything inside the context with the advanced search and jump between entries with just &lt;code&gt;Enter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Vision
&lt;/h2&gt;

&lt;p&gt;Loguro is for the developer who wants to &lt;strong&gt;Find the bug. Fix it. Move on.&lt;/strong&gt; ☕️&lt;/p&gt;

&lt;p&gt;I’m constantly adding features to keep the experience as simple and mouse-free as possible. If you've ever felt overwhelmed by the complexity of modern observability, Loguro might be the breath of fresh air you need.&lt;/p&gt;

&lt;p&gt;There are a lot of ideas i have in my head waiting for me to put them on Loguro, like:&lt;/p&gt;

&lt;h3&gt;
  
  
  Secure, "No-Login" Sharing
&lt;/h3&gt;

&lt;p&gt;We've all been there: a Product Owner asks why payments are failing. Instead of taking a sketchy screenshot, Loguro will let you generate a &lt;strong&gt;secure, shareable link&lt;/strong&gt; to a specific log entry or view. They get the context they need; you don't have to manage a new user account for them. Just to let the PO know why the revenue stopped—just saying.&lt;/p&gt;

&lt;h3&gt;
  
  
  BYOS
&lt;/h3&gt;

&lt;p&gt;There are companies which do not want to store the logs on my servers, or they just want to avoid paying the storage(which BTW is cheap because of the &lt;code&gt;parquet&lt;/code&gt; compression i am using), so i shall be able to provide them a way to add credentials for whatever storage provider they want, S3, R2, whatever, and just push the logs there while the queries will still happen on my own dashboard but without me having a single piece of log from them on my server.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What’s the one thing that drives you crazy about your current logging setup? Let’s chat in the comments.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While i still work on it, even if it's fully working at production level, there is only one plan, *&lt;em&gt;FREE&lt;/em&gt; with generous limits. Something will change on the future, maybe the retention, but we'll see.&lt;/p&gt;

&lt;p&gt;PS. It doesn't need to be used on web only, it can be used in any setup that provides a secure way for you to use an &lt;strong&gt;api key&lt;/strong&gt;, even a plain server on which you need to have some logs and alerts.&lt;/p&gt;

&lt;p&gt;You can give it a spin here: &lt;a href="https://logu.ro" rel="noopener noreferrer"&gt;loguro&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>devops</category>
      <category>webdev</category>
      <category>logging</category>
    </item>
    <item>
      <title>HookTunnel: A Modern Alternative to Ngrok for Webhook Development</title>
      <dc:creator>Sebastian Pavel</dc:creator>
      <pubDate>Sun, 30 Nov 2025 21:12:00 +0000</pubDate>
      <link>https://forem.com/zerk4/hooktunnel-a-modern-alternative-to-ngrok-for-webhook-development-3ja2</link>
      <guid>https://forem.com/zerk4/hooktunnel-a-modern-alternative-to-ngrok-for-webhook-development-3ja2</guid>
      <description>&lt;p&gt;HookTunnel: A Modern Alternative to Ngrok for Webhook Development&lt;/p&gt;

&lt;p&gt;If you've ever struggled with webhook development, you know the pain: setting up tunnels that disappear on restart, losing webhook payloads when your local server is down, and the endless cycle of debugging in production.&lt;br&gt;
I built HookTunnel ('tsuu') to solve these problems and make webhook testing as seamless as local development.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem with Current Webhook Tools
&lt;/h3&gt;

&lt;p&gt;Traditional tools like ngrok are fantastic for quick HTTP tunneling, but they fall short for serious webhook development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ephemeral URLs: Every restart gives you a new endpoint&lt;/li&gt;
&lt;li&gt;No offline handling: Webhooks are lost if your local server is down&lt;/li&gt;
&lt;li&gt;Limited inspection: Basic request logging without replay capabilities&lt;/li&gt;
&lt;li&gt;No persistence: Hard to debug historical webhook payloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;HookTunnel addresses these pain points with a complete webhook development platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  What HookTunnel Does
&lt;/h3&gt;

&lt;p&gt;HookTunnel provides everything you need for modern webhook development:&lt;/p&gt;

&lt;p&gt;🔗 Persistent Relay URLs&lt;br&gt;
Create endpoints that stay the same across sessions. No more updating webhook URLs in external services.&lt;/p&gt;

&lt;p&gt;📡 Offline Queueing&lt;br&gt;
Webhooks are automatically queued when your local server is offline. When you reconnect, they stream in real-time.&lt;/p&gt;

&lt;p&gt;⚡ Real-time Forwarding&lt;br&gt;
WebSocket tunnels forward webhooks instantly to your localhost development environment.&lt;/p&gt;

&lt;p&gt;🔍 Inspection &amp;amp; Replay&lt;br&gt;
Full webhook inspection with headers, body, query parameters, and metadata. Replay any webhook for testing.&lt;/p&gt;

&lt;p&gt;📊 Modern Dashboard&lt;br&gt;
A clean web interface to manage endpoints, view webhook history, and monitor activity.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create Your Endpoint&lt;br&gt;
Get a persistent URL like &lt;a href="https://hooktunnel.dev/api/r/your-user-id/your-slug" rel="noopener noreferrer"&gt;https://hooktunnel.dev/api/r/your-user-id/your-slug&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect Locally&lt;br&gt;
Use WebSocket tunnels to establish a secure connection to your development server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Receive Webhooks&lt;br&gt;
External APIs send webhooks to your HookTunnel URL, which forwards them to your local environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inspect &amp;amp; Debug&lt;br&gt;
View all incoming webhooks in the dashboard with full request details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replay for Testing&lt;br&gt;
Resend webhooks to test different scenarios or debug edge cases.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;p&gt;HookTunnel is built with modern web technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend: Next.js 16 (App Router) + React 19&lt;/li&gt;
&lt;li&gt;Backend API: Hono framework for high-performance routing&lt;/li&gt;
&lt;li&gt;Database: Turso (SQLite) + Drizzle ORM&lt;/li&gt;
&lt;li&gt;Authentication: Better Auth with OAuth support&lt;/li&gt;
&lt;li&gt;Payments: Stripe integration for premium features&lt;/li&gt;
&lt;li&gt;Real-time: WebSocket tunnels for instant forwarding&lt;/li&gt;
&lt;li&gt;UI: TailwindCSS 4 + shadcn/ui components&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;HookTunnel is currently in alpha, so things might be a bit rough around the edges while I iterate. But if you're ready to try it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit hooktunnel.dev (&lt;a href="https://hooktunnel.dev" rel="noopener noreferrer"&gt;https://hooktunnel.dev&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Sign up for an account&lt;/li&gt;
&lt;li&gt;Create your first endpoint&lt;/li&gt;
&lt;li&gt;Start receiving webhooks locally&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why I Built HookTunnel
&lt;/h3&gt;

&lt;p&gt;As a developer working with webhooks daily, I got tired of the friction in the development workflow. HookTunnel started as a personal tool to scratch my own itch, but I believe it has broader value for the developer community.&lt;/p&gt;

&lt;p&gt;The goal is to make webhook development feel native to your local environment - no more context switching, no more lost payloads, no more production debugging nightmares.&lt;/p&gt;

&lt;h3&gt;
  
  
  Current Status
&lt;/h3&gt;

&lt;p&gt;HookTunnel is a work-in-progress personal project. I'm actively building features, fixing bugs, and iterating based on feedback. &lt;/p&gt;

&lt;p&gt;What webhook development pain points do you face? I'd love to hear your thoughts and feedback!&lt;/p&gt;




&lt;p&gt;HookTunnel is my latest indie project - a modern webhook development platform built with Next.js, Hono, and WebSocket magic. Currently in alpha, but already making webhook testing much more enjoyable.&lt;/p&gt;

</description>
      <category>webhooks</category>
      <category>typescript</category>
      <category>nextjs</category>
      <category>websockets</category>
    </item>
    <item>
      <title>efri, the_framework</title>
      <dc:creator>Sebastian Pavel</dc:creator>
      <pubDate>Thu, 13 Feb 2025 09:07:30 +0000</pubDate>
      <link>https://forem.com/zerk4/efri-theframework-3358</link>
      <guid>https://forem.com/zerk4/efri-theframework-3358</guid>
      <description>&lt;h2&gt;
  
  
  Hey codeholics! 👋
&lt;/h2&gt;

&lt;p&gt;I'm a huge fan of &lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt;, but let's be real - PHP can be a pain sometimes, right? That's why I built &lt;a href="https://efri.sepavl.com" rel="noopener noreferrer"&gt;Efri&lt;/a&gt;, my take on bringing Laravel's awesomeness to TypeScript.&lt;/p&gt;

&lt;p&gt;The framework is coming along nicely - it's built on &lt;a href="https://bun.sh/" rel="noopener noreferrer"&gt;Bun&lt;/a&gt; with lots of TypeScript goodness baked in. I've been running some speed tests against other JS/TS frameworks, and trust me, &lt;strong&gt;this thing flies&lt;/strong&gt;! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the Box?
&lt;/h2&gt;

&lt;p&gt;Got all the good stuff you'd expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plugin system to extend everything&lt;/li&gt;
&lt;li&gt;Config management&lt;/li&gt;
&lt;li&gt;Middleware support&lt;/li&gt;
&lt;li&gt;Its own logger (because why not?)&lt;/li&gt;
&lt;li&gt;Gates, validators, models, controllers&lt;/li&gt;
&lt;li&gt;CLI commands&lt;/li&gt;
&lt;li&gt;And more goodies!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the thing that always bugged me - writing database code over and over for different DBs. Like, why can't everything be as smooth as Laravel's Eloquent? That's where &lt;a href="https://knexjs.org/" rel="noopener noreferrer"&gt;Knex&lt;/a&gt; comes in - write once, run anywhere (with a bit of config magic)!&lt;/p&gt;

&lt;p&gt;Want to take it for a spin? Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bunx create-efri@latest
bun dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need to see what commands are available? Just hit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun efri
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the docs at &lt;a href="https://efri.sepavl.com" rel="noopener noreferrer"&gt;efri.sepavl.com&lt;/a&gt; if you want to dive deeper!&lt;/p&gt;

&lt;p&gt;Did you encountered any issue? Here is the &lt;a href="https://github.com/zerK4/efri" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, feel free to drop me an email or contact me on my socials too if needed.&lt;/p&gt;

</description>
      <category>bunjs</category>
      <category>typescript</category>
      <category>efri</category>
      <category>framework</category>
    </item>
    <item>
      <title>Shared form with config files in NextJs</title>
      <dc:creator>Sebastian Pavel</dc:creator>
      <pubDate>Thu, 09 Jan 2025 22:32:41 +0000</pubDate>
      <link>https://forem.com/zerk4/shared-form-with-config-files-in-nextjs-5ehc</link>
      <guid>https://forem.com/zerk4/shared-form-with-config-files-in-nextjs-5ehc</guid>
      <description>&lt;p&gt;Working with forms has always been one of the most challenging aspects of development—not because creating a form is inherently difficult, but because of the sheer amount of code required to make a truly good one.&lt;/p&gt;

&lt;p&gt;Recently, I became a father! The play time has shortened, but I found myself with a bit still to tackle this challenge head-on. So, I decided to build a way to assemble forms faster in React (Next.js, of course). Let's dive in and explore the solution.&lt;/p&gt;




&lt;p&gt;I will act like you already have everything prepared and you are ready to build a shared form solution for your future projects.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Build a &lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;zod&lt;/a&gt; schema.
&lt;/h3&gt;

&lt;p&gt;It can be whatever you want, i will go with something simple, a user schema.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;userSchema.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// we don't want it to complain about adding an id in the frontend i assume&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can add lots of fields here but it will remain on you to add more based on your needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Add the schema configuration
&lt;/h3&gt;

&lt;p&gt;Have a look at &lt;a href="https://gist.github.com/zerK4/7c3ef04fa200a230a472808f05ac7d96#file-schemaconfigs-ts" rel="noopener noreferrer"&gt;this gist&lt;/a&gt; to add the schema configuration that handles some of the magic.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Add the configuration specific to your zod schema.
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productFieldConfigs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;createFieldConfigs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Johnny Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-full&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inputClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-sm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This field is required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some label whatever you want&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-full&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inputClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-sm text-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nf"&gt;onImageLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;previewClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-full h-48 border rounded-xl overflow-hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;uploadAreaClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-md mx-auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-full&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inputClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-sm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This field is required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This seemed pretty simple, let's go further and see how do we render this form on the screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Add the shared form component.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/zerK4/7c3ef04fa200a230a472808f05ac7d96#file-sharedform-tsx" rel="noopener noreferrer"&gt;Here&lt;/a&gt; we have the shared form component, it is not perfect, but it did the job for me and i think it will for others too. On the same gist, you can see all the other components I made to cover my needs. &lt;/p&gt;

&lt;p&gt;You can combine those fields as you wish, here a small example:&lt;/p&gt;

&lt;p&gt;Assume the user has to chose between 3 subscriptions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productFieldConfigs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;createFieldConfigs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;select&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Subscription 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sub-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Subscription 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sub-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Subscription 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sub-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This field is required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;It does not have a documentation yet, but, i am preparing for something, i have limited time, as i am father now, but i still managed to find time to buy a cheap a* domain to push on it a documentation for this and for a badass multi-step form, stay close and you'll see it.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>forms</category>
      <category>zod</category>
    </item>
    <item>
      <title>Laravel Debugbar for Next.js</title>
      <dc:creator>Sebastian Pavel</dc:creator>
      <pubDate>Sat, 04 Jan 2025 19:52:33 +0000</pubDate>
      <link>https://forem.com/zerk4/laravel-debugbar-for-nextjs-326m</link>
      <guid>https://forem.com/zerk4/laravel-debugbar-for-nextjs-326m</guid>
      <description>&lt;h2&gt;
  
  
  Laravel Debugbar for Next.js
&lt;/h2&gt;

&lt;p&gt;Working with Next.js as the frontend and Laravel as the backend, I wanted to optimize my queries or at least better understand what is happening with the speed after creating and implementing &lt;a href="https://queryfi.link/" rel="noopener noreferrer"&gt;Queryfi&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Without further ado, here we have it: a Debugbar integration built on top of &lt;a href="https://github.com/barryvdh/laravel-debugbar" rel="noopener noreferrer"&gt;Laravel Debugbar&lt;/a&gt; for Next.js. While there is still a long way to go for it to be perfect, it works for me and the project I am currently working on.  &lt;/p&gt;

&lt;p&gt;There is no package yet, but if I will have time, I will create a package in the future.  &lt;/p&gt;

&lt;p&gt;I’ll try not to paste a lot of code here since the files are pretty big. Instead, there are links to GitHub Gists for the code (follow the &lt;code&gt;this&lt;/code&gt; keywords). 😁  &lt;/p&gt;




&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Laravel Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install Debugbar in your Laravel project:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   composer require barryvdh/laravel-debugbar &lt;span class="nt"&gt;--dev&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a middleware called &lt;code&gt;InjectDebugBarData&lt;/code&gt; and add the following code to inject Debugbar data into your Laravel API responses:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;   &lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;  

   &lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

   &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Barryvdh\Debugbar\Facades\Debugbar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
   &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Closure&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

   &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InjectDebugBarData&lt;/span&gt;  
   &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
       &lt;span class="p"&gt;{&lt;/span&gt;  
           &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  

           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Debugbar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
               &lt;span class="nv"&gt;$debugbarData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Debugbar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  

               &lt;span class="c1"&gt;// Decode the existing JSON response  &lt;/span&gt;
               &lt;span class="nv"&gt;$originalData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  

               &lt;span class="c1"&gt;// Update accordingly as for me `data` is a default  &lt;/span&gt;
               &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$originalData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
                   &lt;span class="c1"&gt;// Inject debugbar into the existing 'data' key  &lt;/span&gt;
                   &lt;span class="nv"&gt;$originalData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'debugbar'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$debugbarData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
               &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
                   &lt;span class="c1"&gt;// Fallback: Add debugbar separately if 'data' key doesn't exist  &lt;/span&gt;
                   &lt;span class="nv"&gt;$originalData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'debugbar'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$debugbarData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
               &lt;span class="p"&gt;}&lt;/span&gt;  

               &lt;span class="c1"&gt;// Set the modified response content  &lt;/span&gt;
               &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;json_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$originalData&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  
           &lt;span class="p"&gt;}&lt;/span&gt;  

           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
       &lt;span class="p"&gt;}&lt;/span&gt;  
   &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply this middleware to your routes.  &lt;/p&gt;




&lt;h3&gt;
  
  
  Next.js Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a file named &lt;code&gt;debugBar.ts&lt;/code&gt; in your utilities folder and add the code to handle Debugbar responses.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure you have &lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;shadcn&lt;/a&gt; as the component is built with it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a service provider to manage Debugbar data and add &lt;a href="https://gist.github.com/zerK4/ff877be2cd84fda6f6b4cc8c21b91e70#file-debugbarprovider-tsx" rel="noopener noreferrer"&gt;this&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a component for the Debugbar to display and add &lt;a href="https://gist.github.com/zerK4/ff877be2cd84fda6f6b4cc8c21b91e70#file-debugbar-tsx" rel="noopener noreferrer"&gt;this&lt;/a&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Using the Debugbar
&lt;/h3&gt;

&lt;p&gt;Wrap your app layout with the service provider to include the Debugbar component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DebugBarProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DebugBar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;  
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DebugBarProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your API responses, use the hook from the DebugBar provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDebugBar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
&lt;span class="nf"&gt;addResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debugbar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Final Notes
&lt;/h3&gt;

&lt;p&gt;Following these steps, if you log something in your Laravel app, you will see the logs in the browser console. The component will be similar but simpler compared to the one provided by the official Laravel Debugbar package.  &lt;/p&gt;




</description>
      <category>laravel</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>php</category>
    </item>
    <item>
      <title>Designing a Scalable Repository Structure in Laravel with queryFi</title>
      <dc:creator>Sebastian Pavel</dc:creator>
      <pubDate>Mon, 16 Dec 2024 23:02:35 +0000</pubDate>
      <link>https://forem.com/zerk4/designing-a-scalable-repository-structure-in-laravel-with-queryfi-oa6</link>
      <guid>https://forem.com/zerk4/designing-a-scalable-repository-structure-in-laravel-with-queryfi-oa6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When I was starting a new Laravel project, I often wondered what structure I should use. &lt;br&gt;
Laravel is very well-structured, don't get me wrong, making it hard to mess things up. &lt;br&gt;
However, there is a catch, how do we avoid putting all the logic we need into a controller, such as &lt;code&gt;UserController.php&lt;/code&gt;?&lt;br&gt;
In this article, we'll focus on this issue. I'll share my preferred structure to cover my use cases, along with some best practices, and explain how to integrate queryFi.&lt;/p&gt;


&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Since you’re here, I’ll assume you already have a &lt;strong&gt;Laravel&lt;/strong&gt; project or know how to create one, so we can skip that step. Just make sure the API is set up.&lt;/p&gt;

&lt;p&gt;We’ll be using the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app
├── Repositories
|   ├── Interfaces
|   |   ├── EloquentRepositoryInterface.php
|   └── Eloquent
|       ├── BaseRepository.php
|       └── UserRepository.php
├── Resources
    ├── BaseResource.php
    └── ExtendedJsonResource.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find the &lt;strong&gt;Resources&lt;/strong&gt; folder &lt;a href="https://gist.github.com/zerK4/321e37c39da4fcf823364bc4510aa181#file-baseresource-php" rel="noopener noreferrer"&gt;here&lt;/a&gt;, plus a custom logger.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Install queryFi
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Backend&lt;/span&gt;
composer require z3rka/queryfi

&lt;span class="c"&gt;# Frontend&lt;/span&gt;
npm i queryfi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Add repository Interfaces
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Repositories\Interfaces&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Resources\Json\JsonResource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;EloquentRepositoryInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$successMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$successMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$successMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Add the base repository class
&lt;/h3&gt;

&lt;p&gt;I’ll add only three methods here to keep things clean and avoid cluttering the space with repetitive code. &lt;br&gt;
You can find the rest &lt;a href="https://gist.github.com/zerK4/321e37c39da4fcf823364bc4510aa181#file-baserepository-php" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Repositories\Eloquent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Z3rka\Queryfi\HasRelations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseRepository&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;EloquentRepositoryInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;HasRelations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$successMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;BaseResource&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BaseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;$successMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BaseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="s1"&gt;'error'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;BaseResource&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BaseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
              &lt;span class="s1"&gt;'Success'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
              &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;processModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;spitError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BaseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="s2"&gt;"error"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$errorMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;BaseResource&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BaseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
              &lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
              &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;processModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;spitError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BaseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="s2"&gt;"error"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally, to return something from a model you have to &lt;code&gt;-&amp;gt;get()&lt;/code&gt; or to find and &lt;code&gt;-&amp;gt;first()&lt;/code&gt;, that’s not the case here as we are using the queryFi package and we can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$this-&amp;gt;processModel($request, $this-&amp;gt;model)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This automatically covers &lt;code&gt;-&amp;gt;get()&lt;/code&gt; by default if no getter(check the getters here) is configured in the query.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. User repository
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Repositories\Eloquent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Z3rka\Queryfi\HasRelations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;HasRelations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. User controller
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Repositories\Eloquent\UserRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;UserRepository&lt;/span&gt; &lt;span class="nv"&gt;$userRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userRepository&lt;/span&gt;
                  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Ooops, there was an error fetching all the users."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"Ooops, there was an error fetching the user."&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. The api route
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;only&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'show'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Once we have everything set up, we can make requests from the browser by passing query parameters directly, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;url?where[name]=john&amp;amp;select=name&amp;amp;getter=first
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, we can use the &lt;code&gt;queryFi&lt;/code&gt; TypeScript package on the frontend for a cleaner approach.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;queryfi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:8000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// will return an object with the user if it exists.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated query will look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8000/api/users?where[id]=1&amp;amp;getter=first
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This piece of code will return the user with &lt;code&gt;id = 1&lt;/code&gt;.&lt;br&gt;
When you use &lt;code&gt;.find()&lt;/code&gt;, the response will automatically be an object.&lt;br&gt;
If you use &lt;code&gt;.get()&lt;/code&gt;, it will return an array.&lt;/p&gt;

&lt;p&gt;You can try it out in the &lt;a href="https://queryfi.link" rel="noopener noreferrer"&gt;playground&lt;/a&gt; to see how the response looks.&lt;/p&gt;

&lt;p&gt;Since we’re using the HasRelations trait, we can chain frontend queries to transform the data directly on the backend before it’s returned, as shown here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;queryfi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:8000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// will return an array with one entry if it exists.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more methods you can use, check out the the &lt;a href="https://www.queryfi.link/docs/methods/path" rel="noopener noreferrer"&gt;queryFi documentation&lt;/a&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  END
&lt;/h4&gt;

&lt;p&gt;And that’s it! 🎉 Now you’ve got a solid and powerful starting point to build your APIs like a pro. &lt;br&gt;
Go ahead, flex those coding muscles, and make something awesome! 🚀💻&lt;/p&gt;

&lt;p&gt;Get in touch &lt;a href="https://github.com/zerK4" rel="noopener noreferrer"&gt;github&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/s-pavel/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://queryfi.link" rel="noopener noreferrer"&gt;queryFi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>typescript</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
