<?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: Marat</title>
    <description>The latest articles on DEV Community by Marat (@_marat_).</description>
    <link>https://dev.to/_marat_</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%2F4013169%2F678a518e-7798-46b9-a537-d961c98b226c.jpeg</url>
      <title>DEV Community: Marat</title>
      <link>https://dev.to/_marat_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_marat_"/>
    <language>en</language>
    <item>
      <title>Query-First Generator for Go REST APIs</title>
      <dc:creator>Marat</dc:creator>
      <pubDate>Fri, 03 Jul 2026 16:26:29 +0000</pubDate>
      <link>https://dev.to/_marat_/query-first-generator-for-go-rest-apis-3pc1</link>
      <guid>https://dev.to/_marat_/query-first-generator-for-go-rest-apis-3pc1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnbhnct6hdqgtxj5fz5pf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnbhnct6hdqgtxj5fz5pf.png" alt="Query-First cover" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Write queries. Get an application. Add business logic.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have been thinking about a small but annoying backend problem for a long time:&lt;/p&gt;

&lt;p&gt;we often already know the data operations our application needs, but we still spend a lot of time manually building the same layers around them.&lt;/p&gt;

&lt;p&gt;For every new domain model, the ritual is familiar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write repository methods;&lt;/li&gt;
&lt;li&gt;add a service layer;&lt;/li&gt;
&lt;li&gt;create HTTP handlers;&lt;/li&gt;
&lt;li&gt;define request and response shapes;&lt;/li&gt;
&lt;li&gt;update OpenAPI;&lt;/li&gt;
&lt;li&gt;add curl examples;&lt;/li&gt;
&lt;li&gt;write tests;&lt;/li&gt;
&lt;li&gt;wire logging, Docker, health checks, auth, and middleware.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That work is not useless, but a lot of it is repetitive. Worse, the same operation gets described in several places, and those places slowly drift apart.&lt;/p&gt;

&lt;p&gt;So I wanted to try a different starting point.&lt;/p&gt;

&lt;p&gt;Not spec-first.&lt;br&gt;
Not code-first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query-first.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What I mean by query-first
&lt;/h2&gt;

&lt;p&gt;The idea is simple:&lt;/p&gt;

&lt;p&gt;if the database operation already describes what the application can do, use that operation as the beginning of the REST application.&lt;/p&gt;

&lt;p&gt;For SQL projects, that means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PostgreSQL schema + SQLC queries
        ↓
Generated endpoint inventory
        ↓
Repository → Service → HTTP handlers
        ↓
OpenAPI + auth policies + tests + runtime scaffolding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For MongoDB projects, the same idea starts from explicit YAML contracts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MongoDB collection contracts
        ↓
Generated endpoint inventory
        ↓
Repository → Service → HTTP handlers
        ↓
OpenAPI + auth policies + tests + runtime scaffolding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is the middle step: an endpoint inventory.&lt;/p&gt;

&lt;p&gt;It is a normalized internal model that knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP method and path;&lt;/li&gt;
&lt;li&gt;source query or Mongo method;&lt;/li&gt;
&lt;li&gt;path/query/body parameters;&lt;/li&gt;
&lt;li&gt;result shape;&lt;/li&gt;
&lt;li&gt;auth policy;&lt;/li&gt;
&lt;li&gt;roles;&lt;/li&gt;
&lt;li&gt;system routes such as health, readiness, Swagger, and metrics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once that model exists, the generator can render several parts of the application from the same source of truth.&lt;/p&gt;

&lt;p&gt;That is the real trick. The generated handler, OpenAPI operation, curl example, test case, and auth policy should not all guess what the endpoint is. They should all come from the same inventory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The project I built
&lt;/h2&gt;

&lt;p&gt;I implemented this idea in an open-source Go CLI called &lt;strong&gt;rest&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/repomz/rest" rel="noopener noreferrer"&gt;github.com/repomz/rest&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is inspired by &lt;a href="https://github.com/sqlc-dev/sqlc" rel="noopener noreferrer"&gt;sqlc&lt;/a&gt;. SQLC turns SQL into type-safe Go code. &lt;code&gt;rest&lt;/code&gt; takes the next step and turns SQLC output or MongoDB contracts into a runnable layered REST application.&lt;/p&gt;

&lt;p&gt;The goal is not to generate your final product.&lt;/p&gt;

&lt;p&gt;The goal is to remove the boring, error-prone scaffolding so the developer can start from a strong application skeleton and then add the actual business logic.&lt;/p&gt;

&lt;p&gt;In many simple projects, that may get you very close to a working application. In more complex projects, it should still save the first 80–90% of repetitive setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  A SQL example
&lt;/h2&gt;

&lt;p&gt;Imagine a table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;studies&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;              &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;gen_random_uuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;      &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;patient&lt;/span&gt;         &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;study_type&lt;/span&gt;      &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;time_beginning&lt;/span&gt;  &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;surgeon&lt;/span&gt;         &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;deleted&lt;/span&gt;         &lt;span class="nb"&gt;BOOLEAN&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;FALSE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a named SQLC query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- name: GetStudies :many&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;studies&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;deleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sqlc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;narg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;study_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;narg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sqlc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;narg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'surgeon'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;surgeon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;narg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'surgeon'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;time_beginning&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SQLC gives typed Go code for the query. &lt;code&gt;rest&lt;/code&gt; can then infer an endpoint such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /studies?type=CT&amp;amp;surgeon=Ivanov
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional &lt;code&gt;sqlc.narg(...)&lt;/code&gt; values become optional query parameters. The result type becomes part of the response model and OpenAPI schema.&lt;/p&gt;

&lt;p&gt;There is a small convention layer:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Query prefix&lt;/th&gt;
&lt;th&gt;HTTP method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Get&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Find&lt;/code&gt;, &lt;code&gt;Search&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Delete&lt;/code&gt;, &lt;code&gt;Remove&lt;/code&gt;, &lt;code&gt;SoftDelete&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Update&lt;/code&gt;, &lt;code&gt;Patch&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PATCH&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;everything else&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Conventions are never perfect. But they are useful when the alternative is repeatedly describing the same operation in SQL, Go handlers, DTOs, tests, and OpenAPI by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  MongoDB contracts
&lt;/h2&gt;

&lt;p&gt;For MongoDB, there is no SQLC equivalent, so I used explicit YAML contracts.&lt;/p&gt;

&lt;p&gt;The flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rest init &lt;span class="nt"&gt;--example&lt;/span&gt; mongo
rest gen
go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mongo contracts live in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rest_config/rest_mongo/*.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each entity file can describe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collection name;&lt;/li&gt;
&lt;li&gt;fields;&lt;/li&gt;
&lt;li&gt;indexes;&lt;/li&gt;
&lt;li&gt;CRUD methods;&lt;/li&gt;
&lt;li&gt;custom methods such as &lt;code&gt;find_one&lt;/code&gt;, &lt;code&gt;find_many&lt;/code&gt;, &lt;code&gt;update_one&lt;/code&gt;, &lt;code&gt;delete_one&lt;/code&gt;, and &lt;code&gt;aggregate&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;HTTP path/method mapping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generated Mongo app includes repositories, services, handlers, OpenAPI, handler tests, auth middleware, Docker support, and runtime health/readiness paths.&lt;/p&gt;

&lt;p&gt;The Mongo domain layer is intentionally generic enough for document-shaped data. I did not want to pretend every Mongo collection should behave like a rigid relational table.&lt;/p&gt;

&lt;h2&gt;
  
  
  What gets generated
&lt;/h2&gt;

&lt;p&gt;Depending on configuration, &lt;code&gt;rest gen&lt;/code&gt; can generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cmd/main.go&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;domain models;&lt;/li&gt;
&lt;li&gt;PostgreSQL or MongoDB repositories;&lt;/li&gt;
&lt;li&gt;service layer;&lt;/li&gt;
&lt;li&gt;HTTP handlers;&lt;/li&gt;
&lt;li&gt;request/response models;&lt;/li&gt;
&lt;li&gt;handler tests;&lt;/li&gt;
&lt;li&gt;OpenAPI and Swagger UI;&lt;/li&gt;
&lt;li&gt;JWT or Basic Auth;&lt;/li&gt;
&lt;li&gt;RBAC route wrapping;&lt;/li&gt;
&lt;li&gt;security headers;&lt;/li&gt;
&lt;li&gt;rate limiting;&lt;/li&gt;
&lt;li&gt;production-safer CORS defaults;&lt;/li&gt;
&lt;li&gt;request IDs;&lt;/li&gt;
&lt;li&gt;panic recovery;&lt;/li&gt;
&lt;li&gt;body size limits;&lt;/li&gt;
&lt;li&gt;Zap logging;&lt;/li&gt;
&lt;li&gt;optional Prometheus metrics;&lt;/li&gt;
&lt;li&gt;Dockerfile;&lt;/li&gt;
&lt;li&gt;optional Docker Compose;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env.example&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Makefile;&lt;/li&gt;
&lt;li&gt;CI workflow templates;&lt;/li&gt;
&lt;li&gt;curl examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generated Go code is formatted with goimports, so imports and formatting are normalized immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth generation
&lt;/h2&gt;

&lt;p&gt;Auth was one of the harder parts to design because I did not want it to be hidden magic.&lt;/p&gt;

&lt;p&gt;The flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;auth: enable&lt;/code&gt; in &lt;code&gt;rest.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;rest gen&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The generator discovers endpoints and creates &lt;code&gt;rest_config/auth_rest.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The developer marks which endpoints are public, protected, and role-restricted.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;rest gen&lt;/code&gt; again.&lt;/li&gt;
&lt;li&gt;The generator updates middleware, route wrapping, auth handlers, and OpenAPI security.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;JWT and Basic Auth are both supported.&lt;/p&gt;

&lt;p&gt;For SQL/JWT apps, the generator can create signup/signin handlers, password hashing, token service, claims configuration, and protected routes based on the configured user model.&lt;/p&gt;

&lt;p&gt;For Basic Auth and Mongo apps, it generates the matching middleware and role checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;rest doctor&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;I also added a diagnostic command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rest doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can be run at any stage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;after &lt;code&gt;rest init&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;after editing YAML files;&lt;/li&gt;
&lt;li&gt;after &lt;code&gt;rest gen&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;before trying to run the generated app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It checks config consistency, missing tools, YAML mistakes, Docker readiness, OpenAPI/auth configuration, generated files, and runtime prerequisites.&lt;/p&gt;

&lt;p&gt;This is something I personally wanted when learning programming years ago: a command that tells me what is missing and what to do next.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not try to solve
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;rest&lt;/code&gt; does not know your business.&lt;/p&gt;

&lt;p&gt;It will not generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;complex domain validation;&lt;/li&gt;
&lt;li&gt;custom workflows;&lt;/li&gt;
&lt;li&gt;billing logic;&lt;/li&gt;
&lt;li&gt;external integrations;&lt;/li&gt;
&lt;li&gt;complicated transaction boundaries;&lt;/li&gt;
&lt;li&gt;product-specific authorization rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those belong in application code.&lt;/p&gt;

&lt;p&gt;The generator is meant to create a strong, coherent starting point. After that, the developer can continue normally — and may only return to the generator when new domain models or queries need another layer of scaffolding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/repomz/rest/cmd/rest@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SQL example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rest init &lt;span class="nt"&gt;--example&lt;/span&gt; sql
rest gen
go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MongoDB example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rest init &lt;span class="nt"&gt;--example&lt;/span&gt; mongo
rest gen
go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rest list endpoints
rest doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/repomz/rest" rel="noopener noreferrer"&gt;github.com/repomz/rest&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I am sharing it
&lt;/h2&gt;

&lt;p&gt;I am not claiming query-first is the only right way to build APIs.&lt;/p&gt;

&lt;p&gt;Spec-first is still great when OpenAPI is the central contract. Code-first is still convenient for many teams. Manual code is still the right answer when the business logic is the hard part.&lt;/p&gt;

&lt;p&gt;But I think there is a useful space between SQLC and a full application framework:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;if the query already describes the operation, let it generate the boring layers around that operation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the space I wanted to explore with &lt;code&gt;rest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the idea sounds interesting, try one of the examples and bring an inconvenient real-world query or Mongo contract to the issue tracker. Inconvenient examples are how generators become honest.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Write queries. Get an application. Add business logic.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>go</category>
      <category>postgres</category>
      <category>backend</category>
      <category>restapi</category>
    </item>
  </channel>
</rss>
