/gomarvin

Generate Go REST servers with custom endpoints & typescript fetch clients

Primary LanguageGoMIT LicenseMIT

Generate boilerplate for Gin / Fiber / Echo / Chi REST servers.

AKA Why spend 5 minutes doing it when I can spend 3 months automating it?

preview.mp4

Generate:

  • Init server + controllers for endpoints
  • Typescript fetch functions with type-checked payloads for generated endpoints
  • SQL files with tables and queries for controllers ( Postgres )

from one config file.

Disclaimer!

I'm still figuring out how to do stuff better, so if there's a new release where the y in x.y.z the version ( tag ) is incremented, that means that there are breaking changes. The current versions work, but there's a lot of improvements that can be done to make stuff better.

Install

  1. Either create a custom config file with the frontend editor or copy one of the config file from examples dir

  2. Install gomarvin

# install the binary
go install github.com/tompston/gomarvin@latest
# or clone the repo and run go run main.go
git clone https://github.com/tompston/gomarvin.git
  1. run gomarvin
# run this in the same dir as the config file, if the name of the config is "gomarvin.json"
gomarvin generate

# run this if custom config file name or path
gomarvin -config="PATH_TO_CONFIG" generate

# optionally generate the golang struct -> typescript interface converters
gomarvin -gut=true generate
  1. run lower commands
cd GENERATED_SERVER
go mod tidy
go mod download
go run cmd/api/main.go

CLI

Flags:
  -config		Specify path to the gomarvin config file (default "gomarvin.json")
  -dangerous-regen	Regenerate everything. If set to true, init server will be regenerated and all previous changes will be lost (default "false")
  -gut            generate additional file in the modules dir which concats all of the functions that convert possible response structs to typescript interfaces

Generated Typescript fetch functions usage example

// import the generated file
import * as gomarvin from "../../../chi_with_modules/public/gomarvin";
// or just import a single fetch function
import { GetUserById } from "../../../chi_with_modules/public/gomarvin";

// either use the default client created from
// the settings of the config file, or create a new one
// (useful when switching environments)
const defaultClient = gomarvin.defaultClient;

// api client when deployed
const productionClient: gomarvin.Client = {
  host_url: "http://example.com",
  api_prefix: "/api/v1",
  headers: {
    "Content-type": "application/json;charset=UTF-8",
  },
};

const DEV_MODE = true;

// switch to productionClient if DEV_MODE is false
const client = DEV_MODE ? defaultClient : productionClient;

// fetch GetUserById endpoint
async function FetchGetUsersById() {
  const res = await gomarvin.GetUserById(client, 10);
  console.log(res);
}

// append optional string to the existing endpoint url
async function FetchEndpointWithAppendedUrl() {
  const res = await gomarvin.GetUserById(client, 10, {
    append_url: "?name=jim",
  });
  console.log(res);
}

// define custom options for the fetch request
async function FetchEndpointWithCustomOptions() {
  const res = await gomarvin.GetUserById(client, 10, {
    options: { method: "POST" },
  });
  console.log(res);
}

// Use both optional values
// - append a string to the fetch url
// - define a new options object used in the fetch request
async function FetchWithAppendedUrlAndCustomOptions() {
  const res = await gomarvin.GetUserById(client, 10, {
    options: { method: "DELETE" },
    append_url: "?name=jim",
  });
  console.log(res);
}

Generated Python fetch functions usage example

import gomarvin as gomarvin

# use the default localhost client
client = gomarvin.defaultClient

# fetch get users by id endpoint
def get_users_by_id():
  res = gomarvin.UserEndpoints(client).GetUserById(1)
  print(res.json())

# make a post request to the register user endpoint with a body
def register_user():
  body = gomarvin.CreateUserBody(
        username="jim", password="very-long-password", email="jim@email.com")
  res = gomarvin.UserEndpoints(client).CreateUser(body=body)
  print(res.json())

# append a string to the url
def get_users_with_params():
  data = gomarvin.UserEndpoints(client).GetUsers(append_url="?name=jim") 
  print(res.json())

Notes

  • Gin crashes by default. This is due to the way the framework handles routing.

  • bugs caused by url params and routing should be fixed manually.

  • Seeding the db

    • As the generated fetch functions are mapped to the endpoints, you can use them to seed the database pretty easily. Using deno with the faker package can make the process trivial.
  • If formatting does not work for some reason, run this

    gofmt -s -w .
    
  • Using the tool to generate fetch functions for pre-existing REST APIs

    • If you want to generate a client for an already existing REST API in a fast way, you can use the editor to document the needed values to codegen the fetch functions in a fast way
  • If there are errors after creating a new config file, submit an issue. There might be some edge cases that have not been tested yet.

Credits to used packages

Not installed locally to avoid any dependencies.