Full Code of StarpTech/go-web for AI

master 80bf6b777a6b cached
56 files
57.6 KB
22.0k tokens
85 symbols
1 requests
Download .txt
Repository: StarpTech/go-web
Branch: master
Commit: 80bf6b777a6b
Files: 56
Total size: 57.6 KB

Directory structure:
gitextract_pi_oupt8/

├── .editorconfig
├── .github/
│   └── workflows/
│       ├── go.yml
│       └── goreleaser.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── app.json
├── config/
│   └── config.go
├── docker-compose.yml
├── go.mod
├── go.sum
├── internal/
│   ├── cache/
│   │   └── cache.go
│   ├── context/
│   │   └── app_context.go
│   ├── controller/
│   │   ├── healthcheck.go
│   │   ├── healthcheck_test.go
│   │   ├── init_test.go
│   │   ├── metric_test.go
│   │   ├── user-list.go
│   │   ├── user.go
│   │   └── user_test.go
│   ├── core/
│   │   ├── cache_store.go
│   │   ├── error_handler.go
│   │   ├── errors/
│   │   │   └── boom.go
│   │   ├── middleware/
│   │   │   └── app_context.go
│   │   ├── router.go
│   │   ├── server.go
│   │   ├── template.go
│   │   ├── user_store.go
│   │   └── validator.go
│   ├── i18n/
│   │   └── i18n.go
│   ├── models/
│   │   ├── models.go
│   │   └── user.go
│   └── store/
│       ├── cache.go
│       └── user.go
├── locales/
│   └── en/
│       └── default.po
├── main.go
├── scripts/
│   └── create.db.sql
└── web/
    ├── .babelrc
    ├── .eslintrc.json
    ├── .gitignore
    ├── README.md
    ├── package.json
    ├── src/
    │   ├── app/
    │   │   ├── app.js
    │   │   ├── components/
    │   │   │   ├── header.js
    │   │   │   └── like-button.js
    │   │   ├── index.js
    │   │   └── styles.scss
    │   └── global/
    │       ├── app.js
    │       ├── global.html
    │       ├── index.js
    │       └── styles.scss
    └── templates/
        ├── layouts/
        │   └── base.html
        └── pages/
            ├── user-list.html
            └── user.html

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
; http://editorconfig.org/

root = true

[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 2

[{Makefile,go.mod,go.sum,*.go}]
indent_style = tab
indent_size = 8


================================================
FILE: .github/workflows/go.yml
================================================
name: CI

on:
  pull_request:
    paths-ignore:
      - "**.md"
      - "docs/**"

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Set up Go 1.14
        uses: actions/setup-go@v1
        with:
          go-version: 1.14
        id: go

      - name: Check out code into the Go module directory
        uses: actions/checkout@v2

      - name: Install tools
        run: make setup

      - name: Test
        run: make ci


================================================
FILE: .github/workflows/goreleaser.yml
================================================
name: Release with goreleaser
on:
  push:
    branches:
      - "!*"
    tags:
      - "v*.*.*"

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Unshallow
        run: git fetch --prune --unshallow
      - name: Set up Go
        uses: actions/setup-go@v1
        with:
          go-version: 1.13.x
      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v1
        with:
          version: latest
          args: release --rm-dist
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

vendor
.netrc
.vscode
.vs
.tern-project
.DS_Store
.idea
.cgo_ldflags
tmp

.eslintcache

# dependencies
web/node_modules
web/.pnp
web/.pnp.js

# testing
web/coverage

# misc
.DS_Store
.env*
/.sass-cache
/connect.lock
/coverage/*
/test-results/*
/libpeerconnection.log
npm-debug.log
testem.log
/typings
/vendor

# dist
dist

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# make artifacts
/bin

# vendored files
/vendor

# test outputs
/test-results.xml
junit-results
cypress/screenshots
cypress/videos
coverage.txt

# gcloud utils
cloud_sql_proxy
.now

# tools
air
air.log

# test data
cockroach-data
bin


================================================
FILE: CONTRIBUTING.md
================================================
## Setup your machine

`go-web` is written in [Go](https://golang.org/).

Prerequisites:

- `make`
- [Go 1.14+](https://golang.org/doc/install)
- [Docker](https://www.docker.com/)
- `gpg` (probably already installed on your system)

Clone `goweb` anywhere:

```sh
$ git clone git@github.com:StarpTech/go-web.git
```

Install the build and lint dependencies:

```sh
$ make setup
```

A good way of making sure everything is all right is running the test suite:

```sh
$ make test
```

## Test your change

You can create a branch for your changes and try to build from the source as you go:

```sh
$ make
```

When you are satisfied with the changes, we suggest you run:

```sh
$ make ci
```

Which runs all the linters and tests.

## Create a commit

Commit messages should be well formatted, and to make that "standardized", we
are using Conventional Commits.

You can follow the documentation on
[their website](https://www.conventionalcommits.org).

## Submit a pull request

Push your branch to your `go-web` fork and open a pull request against the
master branch.

## Deployment

Tag a new release and push it to origin. This will trigger the Github CI to deploy the commit.
```
git tag v1.0.0
git push origin v1.0.0
```


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 Dustin Deus

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
MODULE   = $(shell env GO111MODULE=on $(GO) list -m)
DATE    ?= $(shell date +%FT%T%z)
VERSION ?= $(shell git describe --tags --always --dirty --match=v* 2> /dev/null || \
			cat $(CURDIR)/.version 2> /dev/null || echo v0)
PKGS     = $(or $(PKG),$(shell env GO111MODULE=on $(GO) list ./...))
TESTPKGS = $(shell env GO111MODULE=on $(GO) list -f \
			'{{ if or .TestGoFiles .XTestGoFiles }}{{ .ImportPath }}{{ end }}' \
			$(PKGS))
BIN      = $(CURDIR)/bin

GO      = go
TIMEOUT = 15
V = 0
Q = $(if $(filter 1,$V),,@)
M = $(shell printf "\033[34;1m▶\033[0m")

export GO111MODULE=on
export GOPROXY=https://proxy.golang.org,direct

.PHONY: all
all: fmt lint | $(BIN) ; $(info $(M) building executable…) @ ## Build program binary
	$Q $(GO) build \
		-tags release \
		-ldflags '-X $(MODULE)/cmd.Version=$(VERSION) -X $(MODULE)/cmd.BuildDate=$(DATE)' \
		-o $(BIN)/$(basename $(MODULE)) main.go

# Tools

# Install all the build and lint dependencies
setup:
	# Install by default to .bin
	curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- v1.24.0
	go mod tidy
.PHONY: setup

$(BIN):
	@mkdir -p $@
$(BIN)/%: | $(BIN) ; $(info $(M) building $(PACKAGE)…)
	$Q tmp=$$(mktemp -d); \
	   env GO111MODULE=off GOPATH=$$tmp GOBIN=$(BIN) $(GO) get $(PACKAGE) \
		|| ret=$$?; \
	   rm -rf $$tmp ; exit $$ret

# Tests

# Run all the tests
test:
	LC_ALL=C go test $(TEST_OPTIONS) -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.txt $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=2m
.PHONY: test

.PHONY: cover
cover: ; $(info $(M) running coverage…) @  # Run all the tests and opens the coverage report
	go tool cover -html=coverage.txt
.PHONY: cover

.PHONY: fmt
fmt: ; $(info $(M) running gofmt…) @ ## Run gofmt on all source files
	$Q $(GO) fmt $(PKGS)

.PHONY: lint
lint: ; $(info $(M) running lint…) @ ## Run gofmt on all source files
	./bin/golangci-lint run ./...

.PHONY: ci
ci: all test; $(info $(M) running all the tests and code checks…) @ ## Run all the tests and code checks

# UI

.PHONY: ui
ui: ; @ ## Run frontend development server
	cd ui && yarn run dev

.PHONY: build-ui
build-ui: ; @ ## Build frontend production build
	cd ui && yarn run build

# API

.PHONY: start
start-api: ; @ ## Start api
	go run main.go

# Misc

.PHONY: clean
clean: ; $(info $(M) cleaning…)	@ ## Cleanup everything
	@rm -rf $(BIN)
	@rm -rf test/tests.* test/coverage.*

.PHONY: help
help:
	@grep -E '^[ a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'

.PHONY: version
version:
	@echo $(VERSION)


================================================
FILE: README.md
================================================
![big-gopher](big-gopher.png)

[![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT)
[![Build Status](https://github.com/StarpTech/go-web/workflows/Go/badge.svg)](https://github.com/StarpTech/go-web/actions)
[![Go Report Card](https://goreportcard.com/badge/github.com/StarpTech/go-web)](https://goreportcard.com/report/github.com/StarpTech/go-web)

# Go-Web

Modern Web Application with Golang "Keep it simple, stupid"

# Stack

## Backend

- HTTP Middleware [Echo](https://echo.labstack.com/)
- ORM library [gorm](https://github.com/jinzhu/gorm)
- Configuration [env](https://github.com/caarlos0/env)
- Load ENV variables from .env file [godotenv](https://github.com/joho/godotenv)
- Payload validation [validator](https://github.com/go-playground/validator)
- Cache [Redis](https://github.com/go-redis/redis)
- Localization [gotext](https://github.com/leonelquinteros/gotext)
- Database [CockroachDB](https://github.com/cockroachdb/cockroach)
- Releasing [goreleaser](https://github.com/goreleaser/goreleaser)

## Frontend

- Server side templating [Go Templates](https://golang.org/pkg/text/template/)
- Module Bundler [Parcel bundler](https://github.com/parcel-bundler/parcel)
- Javascript UI library [React](https://github.com/facebook/react)

# Getting Started

## Project structure

Follows https://github.com/golang-standards/project-layout

## Building From Source

This project requires Go +1.13 and Go module support.

To build the project run:

```
make
```

## Bootstrap infrastructure and run application

This project requires docker and docker compose to run the required services.

1. To run the services:

```
docker-compose up
```

2. To create database

```
docker run --network="host" -it cockroachdb/cockroach:v19.2.1 sql --insecure -e "$(cat ./scripts/create.db.sql)"
```

3. Build [web application](ui/README.md)

4. Start server

```
go run main.go
```

5. Navigate to users list [page](http://127.0.0.1/users)

## CI and Static Analysis

### CI

All pull requests will run through CI, which is currently hosted by Github-CI.
Community contributors should be able to see the outcome of this process by looking at the checks on their PR.
Please fix any issues to ensure a prompt review from members of the team.

### Static Analysis

This project uses the following static analysis tools.
Failure during the running of any of these tools results in a failed build.
Generally, code must be adjusted to satisfy these tools, though there are exceptions.

- [go vet](https://golang.org/cmd/vet/) checks for Go code that should be considered incorrect.
- [go fmt](https://golang.org/cmd/gofmt/) checks that Go code is correctly formatted.
- [golangci-lint](https://github.com/golangci/golangci-lintt) checks for things like: unused code, code that can be simplified, code that is incorrect and code that will have performance issues.
- [go mod tidy](https://tip.golang.org/cmd/go/#hdr-Add_missing_and_remove_unused_modules) ensures that the source code and go.mod agree.

# Releasing

When a new tag is pushed, the version is released with [goreleaser](https://github.com/goreleaser/goreleaser).

```
$ git tag -a v0.1.0 -m "First release"
$ git push origin v0.1.0 # => want to release v0.1.0
```

# Tooling

- IDE plugin [vscode-go](https://github.com/Microsoft/vscode-go)
- Administration of cockroachdb [DBeaver](https://dbeaver.io/)
- REST client [Postman](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en)
- Go testing in the browser [go-convey](https://github.com/smartystreets/goconvey)
- Benchmarking [bombardier](http://github.com/codesenberg/bombardier)

# Documentation

```
$ godoc github.com/starptech/go-web/pkg/controller
$ godoc -http=:6060
```

Visit localhost:6060 and search for `go-web`

# Benchmarking

```
$ bombardier -c 10 -n 10000 http://localhost:8080/users
```

# Cockroachdb Cluster overview

http://localhost:8111/

## Deploy on Heroku

[![Heroku Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/StarpTech/go-web)

# Further reading

- http://www.alexedwards.net/blog/organising-database-access
- https://12factor.net/
- https://dev.otto.de/2015/09/30/on-monoliths-and-microservices/


================================================
FILE: app.json
================================================
{
  "name": "go-web",
  "description": "Modern Web Application with Golang",
  "website": "https://github.com/StarpTech/go-web",
  "repository": "https://github.com/StarpTech/go-web",
  "logo": "https://github.com/StarpTech/go-web/raw/master/big-gopher.png",
  "success_url": "/",
  "keywords": [
    "starter-kit",
    "golang",
    "frontend",
    "api"
  ],
  "addons": [
    "heroku-postgresql",
    "heroku-redis"
  ],
  "env": {}
}

================================================
FILE: config/config.go
================================================
package config

import (
	"log"

	"github.com/caarlos0/env"
	"github.com/joho/godotenv"
)

type Configuration struct {
	Address          string `env:"ADDRESS" envDefault:":8080"`
	Dialect          string `env:"DIALECT,required" envDefault:"postgres"`
	AssetsBuildDir   string `env:"ASSETS_BUILD_DIR"`
	TemplateDir      string `env:"TPL_DIR"`
	LayoutDir        string `env:"LAYOUT_DIR"`
	RedisAddr        string `env:"REDIS_ADDR" envDefault:":6379"`
	RedisPwd         string `env:"REDIS_PWD"`
	ConnectionString string `env:"CONNECTION_STRING,required"`
	IsProduction     bool   `env:"PRODUCTION"`
	GrayLogAddr      string `env:"GRAYLOG_ADDR"`
	RequestLogger    bool   `env:"REQUEST_LOGGER"`
	LocaleDir        string `env:"LOCALE_DIR" envDefault:"locales"`
	Lang             string `env:"LANG" envDefault:"en_US"`
	LangDomain       string `env:"LANG_DOMAIN" envDefault:"default"`
	JwtSecret        string `env:"JWT_SECRET,required"`
}

func NewConfig(files ...string) (*Configuration, error) {
	err := godotenv.Load(files...)

	if err != nil {
		log.Printf("No .env file could be found %q\n", files)
	}

	cfg := Configuration{}
	err = env.Parse(&cfg)
	if err != nil {
		return nil, err
	}

	return &cfg, nil
}


================================================
FILE: docker-compose.yml
================================================
version: "3"
services:
  roach1:
    container_name: roach1
    image: cockroachdb/cockroach:v19.2.1
    command: start --insecure
    ports:
      - "26257:26257"
      - "8111:8080"
    volumes:
      - ./cockroach-data/roach1:/cockroach/cockroach-data
    networks:
      roachnet:
        aliases:
          - roach1

  roach2:
    container_name: roach2
    image: cockroachdb/cockroach:v19.2.1
    command: start --insecure --join=roach1
    volumes:
      - ./cockroach-data/roach2:/cockroach/cockroach-data
    depends_on:
      - roach1
    networks:
      roachnet:
        aliases:
          - roach2

  roach3:
    container_name: roach3
    image: cockroachdb/cockroach:v19.2.1
    command: start --insecure --join=roach1
    volumes:
      - ./cockroach-data/roach3:/cockroach/cockroach-data
    depends_on:
      - roach1
    networks:
      roachnet:
        aliases:
          - roach3

  redis:
    ports:
      - "6379:6379"
    image: "redis:alpine"

networks:
  roachnet:
    driver: bridge


================================================
FILE: go.mod
================================================
module github.com/starptech/go-web

go 1.13

require (
	github.com/caarlos0/env v3.5.0+incompatible
	github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73 // indirect
	github.com/go-playground/locales v0.12.1 // indirect
	github.com/go-playground/universal-translator v0.16.0 // indirect
	github.com/go-redis/redis v6.15.5+incompatible
	github.com/go-sql-driver/mysql v1.5.0 // indirect
	github.com/golang/protobuf v1.3.1 // indirect
	github.com/jinzhu/gorm v1.9.12
	github.com/jinzhu/now v1.1.1 // indirect
	github.com/joho/godotenv v1.3.0
	github.com/labstack/echo/v4 v4.1.14
	github.com/labstack/gommon v0.3.0
	github.com/leodido/go-urn v1.1.0 // indirect
	github.com/mattn/go-isatty v0.0.12 // indirect
	github.com/mattn/go-sqlite3 v2.0.2+incompatible // indirect
	github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect
	github.com/onsi/ginkgo v1.11.0 // indirect
	github.com/onsi/gomega v1.8.1 // indirect
	github.com/prometheus/client_golang v0.9.1
	github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 // indirect
	github.com/prometheus/common v0.2.0 // indirect
	github.com/prometheus/procfs v0.0.0-20190322151404-55ae3d9d5573 // indirect
	github.com/stretchr/testify v1.4.0
	golang.org/x/crypto v0.0.0-20200117160349-530e935923ad // indirect
	golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
	golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
	gopkg.in/go-playground/validator.v9 v9.31.0
	gopkg.in/leonelquinteros/gotext.v1 v1.3.1
)


================================================
FILE: go.sum
================================================
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs=
github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73 h1:OGNva6WhsKst5OZf7eZOklDztV3hwtTHovdrLHV+MsA=
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-redis/redis v6.15.5+incompatible h1:pLky8I0rgiblWfa8C1EV7fPEUv0aH6vKRaYHc/YRHVk=
github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/labstack/echo/v4 v4.1.14 h1:h8XP66UfB3tUm+L3QPw7tmwAu3pJaA/nyfHPCcz46ic=
github.com/labstack/echo/v4 v4.1.14/go.mod h1:Q5KZ1vD3V5FEzjM79hjwVrC3ABr7F5IdM23bXQMRDGg=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.2+incompatible h1:qzw9c2GNT8UFrgWNDhCTqRqYUSmu/Dav/9Z58LGpk7U=
github.com/mattn/go-sqlite3 v2.0.2+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1 h1:K47Rk0v/fkEfwfQet2KWhscE0cJzjgCCDBG2KHZoVno=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190322151404-55ae3d9d5573 h1:gAuD3LIrjkoOOPLlhGlZWZXztrQII9a9kT6HS5jFtSY=
github.com/prometheus/procfs v0.0.0-20190322151404-55ae3d9d5573/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 h1:8d9/fdTG0kn/B7NNGV1BsEyvektXFAbkMsTZS2sFSCc=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1/go.mod h1:X1WlGDeAFIYsW6GjgMm4VwUwZ2XjI7Zan2InxSUQWrU=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=


================================================
FILE: internal/cache/cache.go
================================================
package cache

import (
	"log"

	"github.com/go-redis/redis"
	"github.com/starptech/go-web/config"
)

func NewCache(config *config.Configuration) *redis.Client {
	client := redis.NewClient(&redis.Options{
		Addr:     config.RedisAddr,
		Password: config.RedisPwd,
		DB:       0, // use default DB
	})

	pong, err := client.Ping().Result()

	if err != nil || pong == "" {
		log.Fatalf("redis cache: got no PONG back %q", err)
	}

	return client
}


================================================
FILE: internal/context/app_context.go
================================================
package context

import (
	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/config"
	"github.com/starptech/go-web/internal/i18n"
	"github.com/starptech/go-web/internal/store"
)

// AppContext is the new context in the request / response cycle
// We can use the db store, cache and central configuration
type AppContext struct {
	echo.Context
	UserStore store.User
	Cache     store.Cache
	Config    *config.Configuration
	Loc       i18n.I18ner
}


================================================
FILE: internal/controller/healthcheck.go
================================================
package controller

import (
	"net/http"

	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/internal/context"
)

type Healthcheck struct{}

type healthcheckReport struct {
	Health  string          `json:"health"`
	Details map[string]bool `json:"details"`
}

// GetHealthcheck returns the current functional state of the application
func (ctrl Healthcheck) GetHealthcheck(c echo.Context) error {
	cc := c.(*context.AppContext)
	m := healthcheckReport{Health: "OK"}

	dbCheck := cc.UserStore.Ping()
	cacheCheck := cc.Cache.Ping()

	if dbCheck != nil {
		m.Health = "NOT"
		m.Details["db"] = false
	}

	if cacheCheck != nil {
		m.Health = "NOT"
		m.Details["cache"] = false
	}

	return c.JSON(http.StatusOK, m)
}


================================================
FILE: internal/controller/healthcheck_test.go
================================================
package controller

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/labstack/echo/v4"
	"github.com/stretchr/testify/assert"
)

func TestHealthcheck(t *testing.T) {
	req := httptest.NewRequest(echo.GET, "/.well-known/health-check", nil)
	rec := httptest.NewRecorder()
	e.server.Echo.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code)
}


================================================
FILE: internal/controller/init_test.go
================================================
package controller

import (
	"os"
	"testing"

	"github.com/labstack/echo/v4"
	"github.com/labstack/gommon/log"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/starptech/go-web/config"
	"github.com/starptech/go-web/internal/core"
	"github.com/starptech/go-web/internal/models"
)

var e struct {
	config   *config.Configuration
	logger   *log.Logger
	server   *core.Server
	testUser *models.User
}

func TestMain(m *testing.M) {
	e.config = &config.Configuration{
		ConnectionString: "host=localhost user=gorm dbname=gorm sslmode=disable password=mypassword",
		TemplateDir:      "../templates/*.html",
		LayoutDir:        "../templates/layouts/*.html",
		Dialect:          "postgres",
		RedisAddr:        ":6379",
	}

	e.server = core.NewServer(e.config)

	setup()
	code := m.Run()
	tearDown()

	os.Exit(code)
}

func setup() {
	userCtrl := &User{}
	healthCtrl := &Healthcheck{}

	g := e.server.Echo.Group("/api")
	g.GET("/users/:id", userCtrl.GetUserJSON)

	u := e.server.Echo.Group("/users")
	u.GET("/:id", userCtrl.GetUser)

	e.server.Echo.GET("/.well-known/health-check", healthCtrl.GetHealthcheck)
	e.server.Echo.GET("/.well-known/metrics", echo.WrapHandler(promhttp.Handler()))

	// test data
	user := models.User{Name: "Peter"}
	mr := e.server.GetModelRegistry()
	err := mr.Register(user)

	if err != nil {
		e.server.Echo.Logger.Fatal(err)
	}

	mr.AutoMigrateAll()
	mr.Save(&user)

	e.testUser = &user
}

func tearDown() {
	e.server.GetModelRegistry().AutoDropAll()
}


================================================
FILE: internal/controller/metric_test.go
================================================
package controller

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/labstack/echo/v4"
	"github.com/stretchr/testify/assert"
)

func TestMetric(t *testing.T) {
	req := httptest.NewRequest(echo.GET, "/.well-known/metrics", nil)
	rec := httptest.NewRecorder()
	e.server.Echo.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code)
}


================================================
FILE: internal/controller/user-list.go
================================================
package controller

import (
	"net/http"

	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/internal/context"
	"github.com/starptech/go-web/internal/core/errors"
	"github.com/starptech/go-web/internal/models"
)

type (
	UserList          struct{}
	UserListViewModel struct {
		Users []UserViewModel
	}
)

func (ctrl UserList) GetUsers(c echo.Context) error {
	cc := c.(*context.AppContext)

	users := []models.User{}

	err := cc.UserStore.Find(&users)

	if err != nil {
		b := errors.NewBoom(errors.UserNotFound, errors.ErrorText(errors.UserNotFound), err)
		c.Logger().Error(err)
		return c.JSON(http.StatusNotFound, b)
	}

	viewModel := UserListViewModel{
		Users: make([]UserViewModel, len(users)),
	}

	for index, user := range users {
		viewModel.Users[index] = UserViewModel{
			Name: user.Name,
			ID:   user.ID,
		}
	}

	return c.Render(http.StatusOK, "user-list.html", viewModel)

}


================================================
FILE: internal/controller/user.go
================================================
package controller

import (
	"net/http"

	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/internal/context"
	"github.com/starptech/go-web/internal/core/errors"
	"github.com/starptech/go-web/internal/models"
)

type (
	User          struct{}
	UserViewModel struct {
		Name string
		ID   string
	}
)

func (ctrl User) GetUser(c echo.Context) error {
	cc := c.(*context.AppContext)
	userID := c.Param("id")

	user := models.User{ID: userID}

	err := cc.UserStore.First(&user)

	if err != nil {
		b := errors.NewBoom(errors.UserNotFound, errors.ErrorText(errors.UserNotFound), err)
		c.Logger().Error(err)
		return c.JSON(http.StatusNotFound, b)
	}

	vm := UserViewModel{
		Name: user.Name,
		ID:   user.ID,
	}

	return c.Render(http.StatusOK, "user.html", vm)

}

func (ctrl User) GetUserJSON(c echo.Context) error {
	cc := c.(*context.AppContext)
	userID := c.Param("id")

	user := models.User{ID: userID}

	err := cc.UserStore.First(&user)

	if err != nil {
		b := errors.NewBoom(errors.UserNotFound, errors.ErrorText(errors.UserNotFound), err)
		c.Logger().Error(err)
		return c.JSON(http.StatusNotFound, b)
	}

	vm := UserViewModel{
		Name: user.Name,
		ID:   user.ID,
	}

	return c.JSON(http.StatusOK, vm)
}


================================================
FILE: internal/controller/user_test.go
================================================
package controller

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/internal/context"
	"github.com/starptech/go-web/internal/core/middleware"
	"github.com/starptech/go-web/internal/models"
	"github.com/stretchr/testify/assert"
)

type UserFakeStore struct{}

func (s *UserFakeStore) First(m *models.User) error {
	return nil
}
func (s *UserFakeStore) Find(m *[]models.User) error {
	return nil
}
func (s *UserFakeStore) Create(m *models.User) error {
	return nil
}
func (s *UserFakeStore) Ping() error {
	return nil
}

func TestUserPage(t *testing.T) {
	req := httptest.NewRequest(echo.GET, "/users/"+e.testUser.ID, nil)
	rec := httptest.NewRecorder()
	e.server.Echo.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code)
}

func TestUnitGetUserJson(t *testing.T) {
	s := echo.New()
	g := s.Group("/api")

	req := httptest.NewRequest(echo.GET, "/api/users/"+e.testUser.ID, nil)
	rec := httptest.NewRecorder()

	userCtrl := &User{}

	cc := &context.AppContext{
		Config:    e.config,
		UserStore: &UserFakeStore{},
	}

	s.Use(middleware.AppContext(cc))

	g.GET("/users/:id", userCtrl.GetUserJSON)
	s.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code)
}


================================================
FILE: internal/core/cache_store.go
================================================
package core

import (
	"time"

	"github.com/go-redis/redis"
)

// CacheStore simple redis implementation
type CacheStore struct {
	Cache *redis.Client
}

func (s *CacheStore) Ping() error {
	return s.Cache.Ping().Err()
}

func (s *CacheStore) Get(key string) (string, error) {
	return s.Cache.Get(key).Result()
}

func (s *CacheStore) Set(key string, value interface{}, exp time.Duration) (string, error) {
	return s.Cache.Set(key, value, exp).Result()
}


================================================
FILE: internal/core/error_handler.go
================================================
package core

import (
	"net/http"

	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/internal/core/errors"
)

func HTTPErrorHandler(err error, c echo.Context) {
	c.Logger().Error(err)
	code := http.StatusInternalServerError

	switch v := err.(type) {
	case *echo.HTTPError:
		err := c.JSON(v.Code, v)
		if err != nil {
			c.Logger().Error("error handler: json encoding", err)
		}
	default:
		e := errors.NewBoom(errors.InternalError, "Bad implementation", nil)
		err := c.JSON(code, e)
		if err != nil {
			c.Logger().Error("error handler: json encoding", err)
		}
	}
}


================================================
FILE: internal/core/errors/boom.go
================================================
package errors

const (
	InternalError       = "internalError"
	UserNotFound        = "userNotFound"
	InvalidBindingModel = "invalidBindingModel"
	EntityCreationError = "entityCreationError"
)

var errorMessage = map[string]string{
	"internalError":       "an internal error occured",
	"userNotFound":        "user could not be found",
	"invalidBindingModel": "model could not be bound",
	"EntityCreationError": "could not create entity",
}

// Booms can contain multiple boom errors
type Booms struct {
	Errors []Boom `json:"errors"`
}

func (b *Booms) Add(e Boom) {
	b.Errors = append(b.Errors, e)
}

func NewBooms() Booms {
	return Booms{}
}

// boom represent the basic structure of an json error
type Boom struct {
	Code    string      `json:"code"`
	Message string      `json:"message"`
	Details interface{} `json:"details"`
}

func NewBoom(code, msg string, details interface{}) Boom {
	return Boom{Code: code, Message: msg, Details: details}
}

func ErrorText(code string) string {
	return errorMessage[code]
}


================================================
FILE: internal/core/middleware/app_context.go
================================================
package middleware

import (
	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/internal/context"
)

func AppContext(cc *context.AppContext) echo.MiddlewareFunc {
	return func(h echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			cc.Context = c
			return h(cc)
		}
	}
}


================================================
FILE: internal/core/router.go
================================================
package core

import (
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/starptech/go-web/internal/context"
	mid "github.com/starptech/go-web/internal/core/middleware"
	"github.com/starptech/go-web/internal/i18n"

	v "gopkg.in/go-playground/validator.v9"
)

func NewRouter(server *Server) *echo.Echo {
	config := server.config
	e := echo.New()
	e.Validator = &Validator{validator: v.New()}

	cc := context.AppContext{
		Cache:     &CacheStore{Cache: server.cache},
		Config:    config,
		UserStore: &UserStore{DB: server.db},
		Loc:       i18n.New(),
	}

	e.Use(mid.AppContext(&cc))

	if config.RequestLogger {
		e.Use(middleware.Logger()) // request logger
	}

	e.Use(middleware.Recover())       // panic errors are thrown
	e.Use(middleware.BodyLimit("5M")) // limit body payload to 5MB
	e.Use(middleware.Secure())        // provide protection against injection attacks
	e.Use(middleware.RequestID())     // generate unique requestId

	e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
		AllowOrigins: []string{"*"},
		AllowMethods: []string{echo.GET, echo.HEAD, echo.PUT, echo.PATCH, echo.POST, echo.DELETE},
	}))

	// add custom error formating
	e.HTTPErrorHandler = HTTPErrorHandler

	// Add html templates with go template syntax
	renderer := newTemplateRenderer(config.LayoutDir, config.TemplateDir)
	e.Renderer = renderer

	return e
}


================================================
FILE: internal/core/server.go
================================================
package core

import (
	"context"
	"log"
	"os"
	"os/signal"
	"time"

	"github.com/go-redis/redis"
	"github.com/jinzhu/gorm"
	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/config"
	"github.com/starptech/go-web/internal/cache"
	"github.com/starptech/go-web/internal/i18n"
	"github.com/starptech/go-web/internal/models"
)

type Server struct {
	Echo          *echo.Echo            // HTTP middleware
	config        *config.Configuration // Configuration
	db            *gorm.DB              // Database connection
	cache         *redis.Client         // Redis cache connection
	modelRegistry *models.Model         // Model registry for migration
}

// NewServer will create a new instance of the application
func NewServer(config *config.Configuration) *Server {
	server := &Server{}
	server.config = config
	i18n.Configure(config.LocaleDir, config.Lang, config.LangDomain)
	server.modelRegistry = models.NewModel()
	err := server.modelRegistry.OpenWithConfig(config)

	if err != nil {
		log.Fatalf("gorm: could not connect to db %q", err)
	}

	server.cache = cache.NewCache(config)
	server.db = server.modelRegistry.DB
	server.Echo = NewRouter(server)

	return server
}

// GetDB returns gorm (ORM)
func (s *Server) GetDB() *gorm.DB {
	return s.db
}

// GetCache returns the current redis client
func (s *Server) GetCache() *redis.Client {
	return s.cache
}

// GetConfig return the current app configuration
func (s *Server) GetConfig() *config.Configuration {
	return s.config
}

// GetModelRegistry returns the model registry
func (s *Server) GetModelRegistry() *models.Model {
	return s.modelRegistry
}

// Start the http server
func (s *Server) Start(addr string) error {
	return s.Echo.Start(addr)
}

// ServeStaticFiles serve static files for development purpose
func (s *Server) ServeStaticFiles() {
	s.Echo.Static("/assets", s.config.AssetsBuildDir)
}

// GracefulShutdown Wait for interrupt signal
// to gracefully shutdown the server with a timeout of 5 seconds.
func (s *Server) GracefulShutdown() {
	quit := make(chan os.Signal, 1)

	signal.Notify(quit, os.Interrupt)
	<-quit
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// close cache
	if s.cache != nil {
		cErr := s.cache.Close()
		if cErr != nil {
			s.Echo.Logger.Fatal(cErr)
		}
	}

	// close database connection
	if s.db != nil {
		dErr := s.db.Close()
		if dErr != nil {
			s.Echo.Logger.Fatal(dErr)
		}
	}

	// shutdown http server
	if err := s.Echo.Shutdown(ctx); err != nil {
		s.Echo.Logger.Fatal(err)
	}
}


================================================
FILE: internal/core/template.go
================================================
package core

import (
	"fmt"
	"html/template"
	"io"
	"log"
	"path/filepath"

	"github.com/labstack/echo/v4"
	"github.com/starptech/go-web/internal/i18n"
)

var mainTmpl = `{{define "main" }} {{ template "base" . }} {{ end }}`

type templateRenderer struct {
	templates map[string]*template.Template
}

// NewTemplateRenderer creates a new setup to render layout based go templates
func newTemplateRenderer(layoutsDir, templatesDir string) *templateRenderer {
	r := &templateRenderer{}
	r.templates = make(map[string]*template.Template)
	r.Load(layoutsDir, templatesDir)
	return r
}

func (t *templateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
	tmpl, ok := t.templates[name]
	if !ok {
		c.Logger().Fatalf("the template %s does not exist", name)
		return fmt.Errorf("the template %s does not exist", name)
	}

	return tmpl.ExecuteTemplate(w, "base", data)
}

func (t *templateRenderer) Load(layoutsDir, templatesDir string) {
	layouts, err := filepath.Glob(layoutsDir)
	if err != nil {
		log.Fatal(err)
	}

	includes, err := filepath.Glob(templatesDir)

	if err != nil {
		log.Fatal(err)
	}

	funcMap := template.FuncMap{
		"Loc": i18n.Get,
	}

	mainTemplate := template.New("main")
	mainTemplate.Funcs(funcMap)

	mainTemplate, err = mainTemplate.Parse(mainTmpl)
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range includes {
		fileName := filepath.Base(file)
		files := append(layouts, file)
		t.templates[fileName], err = mainTemplate.Clone()

		if err != nil {
			log.Fatal(err)
		}

		t.templates[fileName] = template.Must(t.templates[fileName].ParseFiles(files...))
	}
}


================================================
FILE: internal/core/user_store.go
================================================
package core

import (
	"github.com/jinzhu/gorm"
	"github.com/starptech/go-web/internal/models"
)

// UserStore implements the UserStore interface
type UserStore struct {
	DB *gorm.DB
}

func (s *UserStore) First(m *models.User) error {
	return s.DB.First(m).Error
}

func (s *UserStore) Create(m *models.User) error {
	return s.DB.Create(m).Error
}

func (s *UserStore) Find(m *[]models.User) error {
	return s.DB.Find(m).Error
}

func (s *UserStore) Ping() error {
	return s.DB.DB().Ping()
}


================================================
FILE: internal/core/validator.go
================================================
package core

import (
	validator "gopkg.in/go-playground/validator.v9"
)

type Validator struct {
	validator *validator.Validate
}

func (v *Validator) Validate(i interface{}) error {
	return v.validator.Struct(i)
}


================================================
FILE: internal/i18n/i18n.go
================================================
package i18n

import gotext "gopkg.in/leonelquinteros/gotext.v1"

type I18ner interface {
	Get(string, ...interface{}) string
}

type I18n struct{}

func New() *I18n {
	return &I18n{}
}

func Configure(lib, lang, dom string) {
	gotext.Configure(lib, lang, dom)
}

func (i *I18n) Get(str string, vars ...interface{}) string {
	return gotext.Get(str, vars...)
}

func Get(str string, vars ...interface{}) string {
	return gotext.Get(str, vars...)
}


================================================
FILE: internal/models/models.go
================================================
package models

import (
	"errors"
	"reflect"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	"github.com/starptech/go-web/config"
)

// Model facilitate database interactions
type Model struct {
	models map[string]reflect.Value
	isOpen bool
	*gorm.DB
}

// NewModel returns a new Model without opening database connection
func NewModel() *Model {
	return &Model{
		models: make(map[string]reflect.Value),
	}
}

// IsOpen returns true if the Model has already established connection
// to the database
func (m *Model) IsOpen() bool {
	return m.isOpen
}

// OpenWithConfig opens database connection with the settings found in cfg
func (m *Model) OpenWithConfig(cfg *config.Configuration) error {
	db, err := gorm.Open(cfg.Dialect, cfg.ConnectionString)
	if err != nil {
		return err
	}

	// https://github.com/go-sql-driver/mysql/issues/461
	db.DB().SetConnMaxLifetime(time.Minute * 5)
	db.DB().SetMaxIdleConns(0)
	db.DB().SetMaxOpenConns(20)

	m.DB = db
	m.isOpen = true
	return nil
}

// Register adds the values to the models registry
func (m *Model) Register(values ...interface{}) error {

	// do not work on them.models first, this is like an insurance policy
	// whenever we encounter any error in the values nothing goes into the registry
	models := make(map[string]reflect.Value)
	if len(values) > 0 {
		for _, val := range values {
			rVal := reflect.ValueOf(val)
			if rVal.Kind() == reflect.Ptr {
				rVal = rVal.Elem()
			}
			switch rVal.Kind() {
			case reflect.Struct:
				models[getTypeName(rVal.Type())] = reflect.New(rVal.Type())
			default:
				return errors.New("models must be structs")
			}
		}
	}
	for k, v := range models {
		m.models[k] = v
	}
	return nil
}

// AutoMigrateAll runs migrations for all the registered models
func (m *Model) AutoMigrateAll() {
	for _, v := range m.models {
		m.AutoMigrate(v.Interface())
	}
}

// AutoDropAll drops all tables of all registered models
func (m *Model) AutoDropAll() {
	for _, v := range m.models {
		m.DropTableIfExists(v.Interface())
	}
}

func getTypeName(typ reflect.Type) string {
	if typ.Name() != "" {
		return typ.Name()
	}
	split := strings.Split(typ.String(), ".")
	return split[len(split)-1]
}


================================================
FILE: internal/models/user.go
================================================
package models

import "time"

type User struct {
	ID        string `gorm:"type:uuid;primary_key;default:gen_random_uuid()"`
	Name      string `sql:"type:varchar(30)"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time
}


================================================
FILE: internal/store/cache.go
================================================
package store

import "time"

type Cache interface {
	Ping() error
	Get(string) (string, error)
	Set(string, interface{}, time.Duration) (string, error)
}


================================================
FILE: internal/store/user.go
================================================
package store

import "github.com/starptech/go-web/internal/models"

type User interface {
	First(m *models.User) error
	Find(m *[]models.User) error
	Create(m *models.User) error
	Ping() error
}


================================================
FILE: locales/en/default.po
================================================
# msgid ""
# msgstr ""
# Initial comment
# Headers below
"Language: en\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
# Some comment
msgid "My text"
msgstr "Translated text"
# More comments
msgid "Another string"
msgstr ""

================================================
FILE: main.go
================================================
package main

import (
	"log"

	"github.com/labstack/echo/v4"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/starptech/go-web/config"
	"github.com/starptech/go-web/internal/controller"
	"github.com/starptech/go-web/internal/core"
	"github.com/starptech/go-web/internal/models"
)

func main() {
	config, err := config.NewConfig()
	if err != nil {
		log.Fatalf("%+v\n", err)
	}
	// create server
	server := core.NewServer(config)
	// serve files for dev
	server.ServeStaticFiles()

	userCtrl := &controller.User{}
	userListCtrl := &controller.UserList{}
	healthCtrl := &controller.Healthcheck{}

	// api endpoints
	g := server.Echo.Group("/api")
	g.GET("/users/:id", userCtrl.GetUserJSON)

	// pages
	u := server.Echo.Group("/users")
	u.GET("", userListCtrl.GetUsers)
	u.GET("/:id", userCtrl.GetUser)

	// metric / health endpoint according to RFC 5785
	server.Echo.GET("/.well-known/health-check", healthCtrl.GetHealthcheck)
	server.Echo.GET("/.well-known/metrics", echo.WrapHandler(promhttp.Handler()))

	// migration for dev
	user := models.User{Name: "Peter"}
	mr := server.GetModelRegistry()
	err = mr.Register(user)

	if err != nil {
		server.Echo.Logger.Fatal(err)
	}

	mr.AutoMigrateAll()
	mr.Create(&user)
	// Start server
	go func() {
		if err := server.Start(config.Address); err != nil {
			server.Echo.Logger.Info("shutting down the server")
		}
	}()

	server.GracefulShutdown()
}


================================================
FILE: scripts/create.db.sql
================================================
CREATE USER IF NOT EXISTS goweb;
CREATE DATABASE goweb;
GRANT ALL ON DATABASE goweb TO goweb;

================================================
FILE: web/.babelrc
================================================
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false
      }
    ],
    "@babel/preset-react"
  ]
}


================================================
FILE: web/.eslintrc.json
================================================
{
  "rules": {},
  "env": {
    "es6": true,
    "browser": true
  },
  "parserOptions": {
    "ecmaVersion": 2018,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "extends": [
    "eslint:recommended",
    "plugin:prettier/recommended"
  ],
  "globals": {
    "Atomics": "readonly",
    "SharedArrayBuffer": "readonly"
  },
  "plugins": [
    "react"
  ]
}

================================================
FILE: web/.gitignore
================================================

.cache/
coverage/
dist/*
!dist/index.html
node_modules/
*.log

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db


================================================
FILE: web/README.md
================================================
# Go Web

Web application for the api

## Building and running on localhost

First install dependencies:

```sh
yarn install
```

To run in hot module reloading mode:

```sh
yarn start
```

To create a production build:

```sh
yarn run build-prod
```

## Development

Run the server and start the bundler in watch mode

```sh
yarn start
go run main.go
```


================================================
FILE: web/package.json
================================================
{
  "name": "empty-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "scripts": {
    "clean": "rm -rf dist",
    "start": "parcel watch src/app/index.js --public-url /assets/dist",
    "build-prod": "yarn clean && parcel build src/app/index.js --public-url /assets/dist"
  },
  "dependencies": {
    "react": "^16.12.0",
    "react-dom": "^16.12.0"
  },
  "devDependencies": {
    "@babel/core": "^7.8.3",
    "@babel/preset-env": "^7.8.3",
    "@babel/preset-react": "^7.8.3",
    "bootstrap": "^4.4.1",
    "eslint": "^6.8.0",
    "eslint-config-prettier": "^6.9.0",
    "eslint-plugin-prettier": "^3.1.2",
    "parcel-bundler": "^1.12.4",
    "prettier": "^1.19.1",
    "sass": "^1.25.1-test.1"
  }
}


================================================
FILE: web/src/app/app.js
================================================
import React from "react";

export default function App({ message }) {
  return (
    <div>
      <h1>{message}</h1>
    </div>
  );
}


================================================
FILE: web/src/app/components/header.js
================================================
import React from "react";

export default function Header({ message }) {
  return (
    <header className="bg-white text-white">
      <div className="container text-center text-dark">
        <img src="http://127.0.0.1:8080/assets/images/go-web.png" />
        <h1>{message}</h1>
        <p className="lead">Welcome to modern web development with Go</p>
      </div>
    </header>
  );
}


================================================
FILE: web/src/app/components/like-button.js
================================================
import React, { useState } from "react";

export default function LikeButton({ id }) {
  const [likes, setLikes] = useState(() => parseInt(id));
  return (
    <button className="btn btn-secondary" onClick={() => setLikes(draft => setLikes(++draft))}>
      Like ({likes})
    </button>
  );
}


================================================
FILE: web/src/app/index.js
================================================
import React from "react";
import ReactDOM from "react-dom";
import App from "./app";
import LikeButton from "./components/like-button";
import Header from "./components/header";
import "./styles.scss";

var mountNode = document.getElementById("app");
ReactDOM.render(<App />, mountNode);

document.querySelectorAll(".like-button-component").forEach(domContainer => {
  ReactDOM.render(<LikeButton {...domContainer.dataset} />, domContainer);
});
document.querySelectorAll(".header-component").forEach(domContainer => {
  ReactDOM.render(<Header {...domContainer.dataset} />, domContainer);
});


================================================
FILE: web/src/app/styles.scss
================================================
@import "~bootstrap/scss/bootstrap";

header {
  padding: 156px 0 100px;
}

section {
  padding: 50px 0;
}

.bd-highlight {
  background-color: rgb(237, 253, 255);
  border: 1px solid rgb(106, 214, 227);
}


================================================
FILE: web/src/global/app.js
================================================
import React from "react";

export default function App({ message }) {
  return (
    <div className="container">
      <ul className="nav">
        <li className="nav-item">
          <a className="nav-link active" href="/">
            Home
          </a>
        </li>
        <li className="nav-item">
          <a className="nav-link" href="/users">
            Users
          </a>
        </li>
      </ul>
      <h1>{message}</h1>
      <img src="http://127.0.0.1:8080/assets/images/go-web.png" />
    </div>
  );
}


================================================
FILE: web/src/global/global.html
================================================
<script src="index.js"></script>


================================================
FILE: web/src/global/index.js
================================================
import React from "react";
import ReactDOM from "react-dom";
import App from "./app";
import "./styles.scss";

var mountNode = document.getElementById("app");
ReactDOM.render(
  <App message="Welcome to modern web development with Go" />,
  mountNode
);


================================================
FILE: web/src/global/styles.scss
================================================
@import "~bootstrap/scss/bootstrap";


================================================
FILE: web/templates/layouts/base.html
================================================
{{ define "base" }}

<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">
  <link href="/assets/dist/index.css" rel="stylesheet">
  <title>{{ block "title" . }} {{end}}</title>
</head>

<body id="page-top">

  <!-- Navigation -->
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" id="mainNav">
    <div class="container">
      <a class="navbar-brand js-scroll-trigger" href="/users">Go Web</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarResponsive">
        <ul class="navbar-nav ml-auto">
          <li class="nav-item">
            <a class="nav-link js-scroll-trigger" href="#about">About</a>
          </li>
          <li class="nav-item">
            <a class="nav-link js-scroll-trigger" href="#services">Services</a>
          </li>
          <li class="nav-item">
            <a class="nav-link js-scroll-trigger" href="#contact">Contact</a>
          </li>
        </ul>
      </div>
    </div>
  </nav>

  {{ template "header" . }}

  <section id="about">
    <div class="container">
      <div class="row">
        <div id="app"></div>
      </div>
      {{ template "content" . }}
    </div>
  </section>

  <!-- Footer -->
  <footer class="py-5 bg-dark">
    <div class="container">
      <p class="m-0 text-center text-white">Copyright &copy; Your Website 2019</p>
    </div>
    <!-- /.container -->
  </footer>

  <script src="/assets/dist/index.js"></script>

</body>

</html>
{{ end }}


================================================
FILE: web/templates/pages/user-list.html
================================================
{{define "title"}}User list{{end}}

{{define "header"}}
<div class="header-component" data-message="User list"></div>
{{end}}

{{define "content"}}

<div class="d-flex flex-column bd-highlight mb-3">
  {{range .Users}}
  <div class="p-2 bd-highlight">{{.Name}}: <a href="/users/{{.ID}}">Details</a></div>
  {{end}}
</div>

{{end}}


================================================
FILE: web/templates/pages/user.html
================================================
{{define "title"}}User {{.Name}}{{end}}

{{define "header"}}
<div class="header-component" data-message="{{.Name}}"></div>
{{end}}

{{define "content"}}

<div class="d-flex flex-column bd-highlight mb-3">
  <div class="p-2 bd-highlight">ID: {{.ID}}</div>
  <div class="p-2 bd-highlight">Name: {{.Name}}</div>
  <div class="p-2 bd-highlight">Translated content: {{ Loc "My text" }}</div>
  <div class="p-2 bd-highlight">
    Mount server rendered html as react component:
    <div class="like-button-component d-inline-block" data-id="101"></div>
  </div>
</div>

{{end}}
Download .txt
gitextract_pi_oupt8/

├── .editorconfig
├── .github/
│   └── workflows/
│       ├── go.yml
│       └── goreleaser.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── app.json
├── config/
│   └── config.go
├── docker-compose.yml
├── go.mod
├── go.sum
├── internal/
│   ├── cache/
│   │   └── cache.go
│   ├── context/
│   │   └── app_context.go
│   ├── controller/
│   │   ├── healthcheck.go
│   │   ├── healthcheck_test.go
│   │   ├── init_test.go
│   │   ├── metric_test.go
│   │   ├── user-list.go
│   │   ├── user.go
│   │   └── user_test.go
│   ├── core/
│   │   ├── cache_store.go
│   │   ├── error_handler.go
│   │   ├── errors/
│   │   │   └── boom.go
│   │   ├── middleware/
│   │   │   └── app_context.go
│   │   ├── router.go
│   │   ├── server.go
│   │   ├── template.go
│   │   ├── user_store.go
│   │   └── validator.go
│   ├── i18n/
│   │   └── i18n.go
│   ├── models/
│   │   ├── models.go
│   │   └── user.go
│   └── store/
│       ├── cache.go
│       └── user.go
├── locales/
│   └── en/
│       └── default.po
├── main.go
├── scripts/
│   └── create.db.sql
└── web/
    ├── .babelrc
    ├── .eslintrc.json
    ├── .gitignore
    ├── README.md
    ├── package.json
    ├── src/
    │   ├── app/
    │   │   ├── app.js
    │   │   ├── components/
    │   │   │   ├── header.js
    │   │   │   └── like-button.js
    │   │   ├── index.js
    │   │   └── styles.scss
    │   └── global/
    │       ├── app.js
    │       ├── global.html
    │       ├── index.js
    │       └── styles.scss
    └── templates/
        ├── layouts/
        │   └── base.html
        └── pages/
            ├── user-list.html
            └── user.html
Download .txt
SYMBOL INDEX (85 symbols across 29 files)

FILE: config/config.go
  type Configuration (line 10) | type Configuration struct
  function NewConfig (line 28) | func NewConfig(files ...string) (*Configuration, error) {

FILE: internal/cache/cache.go
  function NewCache (line 10) | func NewCache(config *config.Configuration) *redis.Client {

FILE: internal/context/app_context.go
  type AppContext (line 12) | type AppContext struct

FILE: internal/controller/healthcheck.go
  type Healthcheck (line 10) | type Healthcheck struct
    method GetHealthcheck (line 18) | func (ctrl Healthcheck) GetHealthcheck(c echo.Context) error {
  type healthcheckReport (line 12) | type healthcheckReport struct

FILE: internal/controller/healthcheck_test.go
  function TestHealthcheck (line 12) | func TestHealthcheck(t *testing.T) {

FILE: internal/controller/init_test.go
  function TestMain (line 22) | func TestMain(m *testing.M) {
  function setup (line 40) | func setup() {
  function tearDown (line 68) | func tearDown() {

FILE: internal/controller/metric_test.go
  function TestMetric (line 12) | func TestMetric(t *testing.T) {

FILE: internal/controller/user-list.go
  type UserList (line 13) | type UserList struct
    method GetUsers (line 19) | func (ctrl UserList) GetUsers(c echo.Context) error {
  type UserListViewModel (line 14) | type UserListViewModel struct

FILE: internal/controller/user.go
  type User (line 13) | type User struct
    method GetUser (line 20) | func (ctrl User) GetUser(c echo.Context) error {
    method GetUserJSON (line 43) | func (ctrl User) GetUserJSON(c echo.Context) error {
  type UserViewModel (line 14) | type UserViewModel struct

FILE: internal/controller/user_test.go
  type UserFakeStore (line 15) | type UserFakeStore struct
    method First (line 17) | func (s *UserFakeStore) First(m *models.User) error {
    method Find (line 20) | func (s *UserFakeStore) Find(m *[]models.User) error {
    method Create (line 23) | func (s *UserFakeStore) Create(m *models.User) error {
    method Ping (line 26) | func (s *UserFakeStore) Ping() error {
  function TestUserPage (line 30) | func TestUserPage(t *testing.T) {
  function TestUnitGetUserJson (line 38) | func TestUnitGetUserJson(t *testing.T) {

FILE: internal/core/cache_store.go
  type CacheStore (line 10) | type CacheStore struct
    method Ping (line 14) | func (s *CacheStore) Ping() error {
    method Get (line 18) | func (s *CacheStore) Get(key string) (string, error) {
    method Set (line 22) | func (s *CacheStore) Set(key string, value interface{}, exp time.Durat...

FILE: internal/core/error_handler.go
  function HTTPErrorHandler (line 10) | func HTTPErrorHandler(err error, c echo.Context) {

FILE: internal/core/errors/boom.go
  constant InternalError (line 4) | InternalError       = "internalError"
  constant UserNotFound (line 5) | UserNotFound        = "userNotFound"
  constant InvalidBindingModel (line 6) | InvalidBindingModel = "invalidBindingModel"
  constant EntityCreationError (line 7) | EntityCreationError = "entityCreationError"
  type Booms (line 18) | type Booms struct
    method Add (line 22) | func (b *Booms) Add(e Boom) {
  function NewBooms (line 26) | func NewBooms() Booms {
  type Boom (line 31) | type Boom struct
  function NewBoom (line 37) | func NewBoom(code, msg string, details interface{}) Boom {
  function ErrorText (line 41) | func ErrorText(code string) string {

FILE: internal/core/middleware/app_context.go
  function AppContext (line 8) | func AppContext(cc *context.AppContext) echo.MiddlewareFunc {

FILE: internal/core/router.go
  function NewRouter (line 13) | func NewRouter(server *Server) *echo.Echo {

FILE: internal/core/server.go
  type Server (line 19) | type Server struct
    method GetDB (line 47) | func (s *Server) GetDB() *gorm.DB {
    method GetCache (line 52) | func (s *Server) GetCache() *redis.Client {
    method GetConfig (line 57) | func (s *Server) GetConfig() *config.Configuration {
    method GetModelRegistry (line 62) | func (s *Server) GetModelRegistry() *models.Model {
    method Start (line 67) | func (s *Server) Start(addr string) error {
    method ServeStaticFiles (line 72) | func (s *Server) ServeStaticFiles() {
    method GracefulShutdown (line 78) | func (s *Server) GracefulShutdown() {
  function NewServer (line 28) | func NewServer(config *config.Configuration) *Server {

FILE: internal/core/template.go
  type templateRenderer (line 16) | type templateRenderer struct
    method Render (line 28) | func (t *templateRenderer) Render(w io.Writer, name string, data inter...
    method Load (line 38) | func (t *templateRenderer) Load(layoutsDir, templatesDir string) {
  function newTemplateRenderer (line 21) | func newTemplateRenderer(layoutsDir, templatesDir string) *templateRende...

FILE: internal/core/user_store.go
  type UserStore (line 9) | type UserStore struct
    method First (line 13) | func (s *UserStore) First(m *models.User) error {
    method Create (line 17) | func (s *UserStore) Create(m *models.User) error {
    method Find (line 21) | func (s *UserStore) Find(m *[]models.User) error {
    method Ping (line 25) | func (s *UserStore) Ping() error {

FILE: internal/core/validator.go
  type Validator (line 7) | type Validator struct
    method Validate (line 11) | func (v *Validator) Validate(i interface{}) error {

FILE: internal/i18n/i18n.go
  type I18ner (line 5) | type I18ner interface
  type I18n (line 9) | type I18n struct
    method Get (line 19) | func (i *I18n) Get(str string, vars ...interface{}) string {
  function New (line 11) | func New() *I18n {
  function Configure (line 15) | func Configure(lib, lang, dom string) {
  function Get (line 23) | func Get(str string, vars ...interface{}) string {

FILE: internal/models/models.go
  type Model (line 15) | type Model struct
    method IsOpen (line 30) | func (m *Model) IsOpen() bool {
    method OpenWithConfig (line 35) | func (m *Model) OpenWithConfig(cfg *config.Configuration) error {
    method Register (line 52) | func (m *Model) Register(values ...interface{}) error {
    method AutoMigrateAll (line 78) | func (m *Model) AutoMigrateAll() {
    method AutoDropAll (line 85) | func (m *Model) AutoDropAll() {
  function NewModel (line 22) | func NewModel() *Model {
  function getTypeName (line 91) | func getTypeName(typ reflect.Type) string {

FILE: internal/models/user.go
  type User (line 5) | type User struct

FILE: internal/store/cache.go
  type Cache (line 5) | type Cache interface

FILE: internal/store/user.go
  type User (line 5) | type User interface

FILE: main.go
  function main (line 14) | func main() {

FILE: web/src/app/app.js
  function App (line 3) | function App({ message }) {

FILE: web/src/app/components/header.js
  function Header (line 3) | function Header({ message }) {

FILE: web/src/app/components/like-button.js
  function LikeButton (line 3) | function LikeButton({ id }) {

FILE: web/src/global/app.js
  function App (line 3) | function App({ message }) {
Condensed preview — 56 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (66K chars).
[
  {
    "path": ".editorconfig",
    "chars": 226,
    "preview": "; http://editorconfig.org/\n\nroot = true\n\n[*]\ninsert_final_newline = true\ncharset = utf-8\ntrim_trailing_whitespace = true"
  },
  {
    "path": ".github/workflows/go.yml",
    "chars": 458,
    "preview": "name: CI\n\non:\n  pull_request:\n    paths-ignore:\n      - \"**.md\"\n      - \"docs/**\"\n\njobs:\n  build:\n    name: Build\n    ru"
  },
  {
    "path": ".github/workflows/goreleaser.yml",
    "chars": 594,
    "preview": "name: Release with goreleaser\non:\n  push:\n    branches:\n      - \"!*\"\n    tags:\n      - \"v*.*.*\"\n\njobs:\n  goreleaser:\n   "
  },
  {
    "path": ".gitignore",
    "chars": 700,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\nvendor\n.netrc\n.vscode\n.vs\n.tern-p"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1226,
    "preview": "## Setup your machine\n\n`go-web` is written in [Go](https://golang.org/).\n\nPrerequisites:\n\n- `make`\n- [Go 1.14+](https://"
  },
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2017 Dustin Deus\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "Makefile",
    "chars": 2607,
    "preview": "MODULE   = $(shell env GO111MODULE=on $(GO) list -m)\nDATE    ?= $(shell date +%FT%T%z)\nVERSION ?= $(shell git describe -"
  },
  {
    "path": "README.md",
    "chars": 4282,
    "preview": "![big-gopher](big-gopher.png)\n\n[![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org"
  },
  {
    "path": "app.json",
    "chars": 437,
    "preview": "{\n  \"name\": \"go-web\",\n  \"description\": \"Modern Web Application with Golang\",\n  \"website\": \"https://github.com/StarpTech/"
  },
  {
    "path": "config/config.go",
    "chars": 1208,
    "preview": "package config\n\nimport (\n\t\"log\"\n\n\t\"github.com/caarlos0/env\"\n\t\"github.com/joho/godotenv\"\n)\n\ntype Configuration struct {\n\t"
  },
  {
    "path": "docker-compose.yml",
    "chars": 1012,
    "preview": "version: \"3\"\nservices:\n  roach1:\n    container_name: roach1\n    image: cockroachdb/cockroach:v19.2.1\n    command: start "
  },
  {
    "path": "go.mod",
    "chars": 1571,
    "preview": "module github.com/starptech/go-web\n\ngo 1.13\n\nrequire (\n\tgithub.com/caarlos0/env v3.5.0+incompatible\n\tgithub.com/denisenk"
  },
  {
    "path": "go.sum",
    "chars": 15644,
    "preview": "github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc="
  },
  {
    "path": "internal/cache/cache.go",
    "chars": 446,
    "preview": "package cache\n\nimport (\n\t\"log\"\n\n\t\"github.com/go-redis/redis\"\n\t\"github.com/starptech/go-web/config\"\n)\n\nfunc NewCache(conf"
  },
  {
    "path": "internal/context/app_context.go",
    "chars": 456,
    "preview": "package context\n\nimport (\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/starptech/go-web/config\"\n\t\"github.com/starptech/go"
  },
  {
    "path": "internal/controller/healthcheck.go",
    "chars": 721,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/starptech/go-web/internal/context\""
  },
  {
    "path": "internal/controller/healthcheck_test.go",
    "chars": 366,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/st"
  },
  {
    "path": "internal/controller/init_test.go",
    "chars": 1500,
    "preview": "package controller\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/labstack/gommon/log\"\n\t\"github"
  },
  {
    "path": "internal/controller/metric_test.go",
    "chars": 356,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/st"
  },
  {
    "path": "internal/controller/user-list.go",
    "chars": 903,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/starptech/go-web/internal/context\""
  },
  {
    "path": "internal/controller/user.go",
    "chars": 1223,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/starptech/go-web/internal/context\""
  },
  {
    "path": "internal/controller/user_test.go",
    "chars": 1239,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/st"
  },
  {
    "path": "internal/core/cache_store.go",
    "chars": 456,
    "preview": "package core\n\nimport (\n\t\"time\"\n\n\t\"github.com/go-redis/redis\"\n)\n\n// CacheStore simple redis implementation\ntype CacheStor"
  },
  {
    "path": "internal/core/error_handler.go",
    "chars": 582,
    "preview": "package core\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/starptech/go-web/internal/core/errors\"\n)"
  },
  {
    "path": "internal/core/errors/boom.go",
    "chars": 1019,
    "preview": "package errors\n\nconst (\n\tInternalError       = \"internalError\"\n\tUserNotFound        = \"userNotFound\"\n\tInvalidBindingMode"
  },
  {
    "path": "internal/core/middleware/app_context.go",
    "chars": 306,
    "preview": "package middleware\n\nimport (\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/starptech/go-web/internal/context\"\n)\n\nfunc AppC"
  },
  {
    "path": "internal/core/router.go",
    "chars": 1383,
    "preview": "package core\n\nimport (\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/labstack/echo/v4/middleware\"\n\t\"github.com/starptech/g"
  },
  {
    "path": "internal/core/server.go",
    "chars": 2540,
    "preview": "package core\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"time\"\n\n\t\"github.com/go-redis/redis\"\n\t\"github.com/jinzhu/go"
  },
  {
    "path": "internal/core/template.go",
    "chars": 1625,
    "preview": "package core\n\nimport (\n\t\"fmt\"\n\t\"html/template\"\n\t\"io\"\n\t\"log\"\n\t\"path/filepath\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.co"
  },
  {
    "path": "internal/core/user_store.go",
    "chars": 494,
    "preview": "package core\n\nimport (\n\t\"github.com/jinzhu/gorm\"\n\t\"github.com/starptech/go-web/internal/models\"\n)\n\n// UserStore implemen"
  },
  {
    "path": "internal/core/validator.go",
    "chars": 217,
    "preview": "package core\n\nimport (\n\tvalidator \"gopkg.in/go-playground/validator.v9\"\n)\n\ntype Validator struct {\n\tvalidator *validator"
  },
  {
    "path": "internal/i18n/i18n.go",
    "chars": 447,
    "preview": "package i18n\n\nimport gotext \"gopkg.in/leonelquinteros/gotext.v1\"\n\ntype I18ner interface {\n\tGet(string, ...interface{}) s"
  },
  {
    "path": "internal/models/models.go",
    "chars": 2220,
    "preview": "package models\n\nimport (\n\t\"errors\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jinzhu/gorm\"\n\t_ \"github.com/jinzhu/gorm/d"
  },
  {
    "path": "internal/models/user.go",
    "chars": 234,
    "preview": "package models\n\nimport \"time\"\n\ntype User struct {\n\tID        string `gorm:\"type:uuid;primary_key;default:gen_random_uuid"
  },
  {
    "path": "internal/store/cache.go",
    "chars": 155,
    "preview": "package store\n\nimport \"time\"\n\ntype Cache interface {\n\tPing() error\n\tGet(string) (string, error)\n\tSet(string, interface{}"
  },
  {
    "path": "internal/store/user.go",
    "chars": 196,
    "preview": "package store\n\nimport \"github.com/starptech/go-web/internal/models\"\n\ntype User interface {\n\tFirst(m *models.User) error\n"
  },
  {
    "path": "locales/en/default.po",
    "chars": 305,
    "preview": "# msgid \"\"\n# msgstr \"\"\n# Initial comment\n# Headers below\n\"Language: en\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"C"
  },
  {
    "path": "main.go",
    "chars": 1417,
    "preview": "package main\n\nimport (\n\t\"log\"\n\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\""
  },
  {
    "path": "scripts/create.db.sql",
    "chars": 93,
    "preview": "CREATE USER IF NOT EXISTS goweb;\nCREATE DATABASE goweb;\nGRANT ALL ON DATABASE goweb TO goweb;"
  },
  {
    "path": "web/.babelrc",
    "chars": 130,
    "preview": "{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"modules\": false\n      }\n    ],\n    \"@babel/preset-rea"
  },
  {
    "path": "web/.eslintrc.json",
    "chars": 390,
    "preview": "{\n  \"rules\": {},\n  \"env\": {\n    \"es6\": true,\n    \"browser\": true\n  },\n  \"parserOptions\": {\n    \"ecmaVersion\": 2018,\n    "
  },
  {
    "path": "web/.gitignore",
    "chars": 157,
    "preview": "\n.cache/\ncoverage/\ndist/*\n!dist/index.html\nnode_modules/\n*.log\n\n# OS generated files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight"
  },
  {
    "path": "web/README.md",
    "chars": 356,
    "preview": "# Go Web\n\nWeb application for the api\n\n## Building and running on localhost\n\nFirst install dependencies:\n\n```sh\nyarn ins"
  },
  {
    "path": "web/package.json",
    "chars": 786,
    "preview": "{\n  \"name\": \"empty-project\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"keywords\": [],\n  \"autho"
  },
  {
    "path": "web/src/app/app.js",
    "chars": 135,
    "preview": "import React from \"react\";\n\nexport default function App({ message }) {\n  return (\n    <div>\n      <h1>{message}</h1>\n   "
  },
  {
    "path": "web/src/app/components/header.js",
    "chars": 390,
    "preview": "import React from \"react\";\n\nexport default function Header({ message }) {\n  return (\n    <header className=\"bg-white tex"
  },
  {
    "path": "web/src/app/components/like-button.js",
    "chars": 294,
    "preview": "import React, { useState } from \"react\";\n\nexport default function LikeButton({ id }) {\n  const [likes, setLikes] = useSt"
  },
  {
    "path": "web/src/app/index.js",
    "chars": 595,
    "preview": "import React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport App from \"./app\";\nimport LikeButton from \"./componen"
  },
  {
    "path": "web/src/app/styles.scss",
    "chars": 206,
    "preview": "@import \"~bootstrap/scss/bootstrap\";\n\nheader {\n  padding: 156px 0 100px;\n}\n\nsection {\n  padding: 50px 0;\n}\n\n.bd-highligh"
  },
  {
    "path": "web/src/global/app.js",
    "chars": 524,
    "preview": "import React from \"react\";\n\nexport default function App({ message }) {\n  return (\n    <div className=\"container\">\n      "
  },
  {
    "path": "web/src/global/global.html",
    "chars": 33,
    "preview": "<script src=\"index.js\"></script>\n"
  },
  {
    "path": "web/src/global/index.js",
    "chars": 254,
    "preview": "import React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport App from \"./app\";\nimport \"./styles.scss\";\n\nvar mount"
  },
  {
    "path": "web/src/global/styles.scss",
    "chars": 37,
    "preview": "@import \"~bootstrap/scss/bootstrap\";\n"
  },
  {
    "path": "web/templates/layouts/base.html",
    "chars": 1870,
    "preview": "{{ define \"base\" }}\n\n<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content="
  },
  {
    "path": "web/templates/pages/user-list.html",
    "chars": 331,
    "preview": "{{define \"title\"}}User list{{end}}\n\n{{define \"header\"}}\n<div class=\"header-component\" data-message=\"User list\"></div>\n{{"
  },
  {
    "path": "web/templates/pages/user.html",
    "chars": 571,
    "preview": "{{define \"title\"}}User {{.Name}}{{end}}\n\n{{define \"header\"}}\n<div class=\"header-component\" data-message=\"{{.Name}}\"></di"
  }
]

About this extraction

This page contains the full source code of the StarpTech/go-web GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 56 files (57.6 KB), approximately 22.0k tokens, and a symbol index with 85 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!