From 77cc488d89609c7a28dce6f76c5080ad45847b00 Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 16 Aug 2020 01:21:27 +0800 Subject: [PATCH] [feat] add pkgs, dockerfile, makefile --- Dockerfile | 12 +++++ Makefile | 31 ++++++++++++ database/database.go | 33 ++++++++++++ go.mod | 7 ++- go.sum | 44 +++++++++++++++- main.go | 28 ++++++++++- pkg/args/args.go | 8 +++ pkg/config/config.go | 8 +++ pkg/context/context.go | 75 +++++++++++++++++++++++++++ pkg/errors/errors.go | 39 ++++++++++++++ pkg/redis/redis.go | 39 ++++++++++++++ pkg/response/code.go | 44 ++++++++++++++++ pkg/response/response.go | 81 ++++++++++++++++++++++++++++++ pkg/swagger/swagger.go | 18 +++++++ pkg/version/version.go | 20 ++++++++ {route => router}/routes/routes.go | 0 16 files changed, 482 insertions(+), 5 deletions(-) create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 database/database.go create mode 100644 pkg/context/context.go create mode 100644 pkg/errors/errors.go create mode 100644 pkg/redis/redis.go create mode 100644 pkg/response/code.go create mode 100644 pkg/response/response.go create mode 100644 pkg/swagger/swagger.go create mode 100644 pkg/version/version.go rename {route => router}/routes/routes.go (100%) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..927c55b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM otakukaze/golang-base-image:1-alpine as builder +WORKDIR /data +COPY . . +RUN apk add --no-cache make gcc musl-dev \ + && make + +FROM alpine:latest +WORKDIR /data +COPY --from=builder /data/api /usr/bin +COPY ./config/config.yml /data/config.yml +EXPOSE 10230 +CMD ["/usr/bin/api"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..09bb12c --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +.PHONY: all + +BIN_NAME := api +BUILD_DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") + +ifneq ($(DRONE_TAG),) + VERSION ?= $(subst v,,$(DRONE_TAG)) +else + VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//') +endif + +LDFLAGS ?= -X go-api/pkg/version.Version=$(VERSION) -X go-api/pkg/version.BuildDate=$(BUILD_DATE) + +all: clean generate-spec bundle-static build +dev: clean generate-spec bundle-static + +build: + go build -o $(BIN_NAME) -ldflags "-s -w $(LDFLAGS)" . + +clean: + rm -rf $(BIN_NAME) + go clean + +generate-spec: + swagger generate spec -m --compact -o spec.json + +build-static: + go-bindata -fs -pkg static -ignore .git -o static/bundle.go public/ schema/ spec.json + +test: + go test ./... diff --git a/database/database.go b/database/database.go new file mode 100644 index 0000000..059cb39 --- /dev/null +++ b/database/database.go @@ -0,0 +1,33 @@ +package database + +import ( + "go-api/pkg/config" + + "github.com/jmoiron/sqlx" +) + +var x *sqlx.DB + +func Init(conf *config.Config) error { + var err error + x, err = sqlx.Connect("postgres", conf.Database.DSN) + if err != nil { + return err + } + + x.SetMaxIdleConns(int(conf.Database.IdleConn)) + x.SetMaxOpenConns(int(conf.Database.MaxConn)) + + if err := x.Ping(); err != nil { + return err + } + + return nil +} + +func Get() *sqlx.DB { + if x == nil { + panic("database not init") + } + return x +} diff --git a/go.mod b/go.mod index 8618e28..ec141c3 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,13 @@ require ( git.trj.tw/golang/config-loader v1.0.1 github.com/gin-gonic/gin v1.6.3 github.com/go-playground/validator/v10 v10.3.0 // indirect - github.com/golang/protobuf v1.4.2 // indirect + github.com/go-redis/redis v6.15.9+incompatible + github.com/jmoiron/sqlx v1.2.0 + github.com/joho/godotenv v1.3.0 github.com/json-iterator/go v1.1.10 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect - golang.org/x/sys v0.0.0-20200802091954-4b90ce9b60b3 // indirect + github.com/onsi/ginkgo v1.14.0 // indirect + golang.org/x/sys v0.0.0-20200805065543-0cf7623e9dbd // indirect google.golang.org/protobuf v1.25.0 // indirect ) diff --git a/go.sum b/go.sum index fd9dd82..0d0f5f3 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,9 @@ 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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= @@ -28,6 +31,10 @@ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o= github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -49,14 +56,23 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +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/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 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 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -65,6 +81,15 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/otakukaze/envconfig v1.0.4 h1:/rZ8xq1vFpgWzqsqUkk61doDGNv9pIXqrog/mCvSx8Y= github.com/otakukaze/envconfig v1.0.4/go.mod h1:v2dNv5NX1Lakw3FTAkbxYURyaiOy68M8QpMTZz+ogfs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -85,19 +110,29 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200802091954-4b90ce9b60b3 h1:qDJKu1y/1SjhWac4BQZjLljqvqiWUhjmDMnonmVGDAU= -golang.org/x/sys v0.0.0-20200802091954-4b90ce9b60b3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200805065543-0cf7623e9dbd h1:wefLe/3g5tC0FcXw3NneLA5tHgbyouyZlfcSjNfOdgk= +golang.org/x/sys v0.0.0-20200805065543-0cf7623e9dbd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -107,6 +142,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= @@ -127,7 +163,11 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go index 1597fcb..c92a368 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,33 @@ package main -import "fmt" +import ( + "fmt" + "go-api/pkg/args" + "go-api/pkg/config" + "log" + + "github.com/joho/godotenv" +) func main() { fmt.Println("go-api") + + godotenv.Load() + + if err := args.Parse(); err != nil { + log.Fatal(err) + } + + cliArg := args.Get() + + if err := config.Load(cliArg.ConfigPath); err != nil { + log.Fatal(err) + } + + switch cliArg.Run { + case "server": + break + case "dbtool": + break + } } diff --git a/pkg/args/args.go b/pkg/args/args.go index 2b9109a..bb526cb 100644 --- a/pkg/args/args.go +++ b/pkg/args/args.go @@ -1,6 +1,7 @@ package args import ( + "errors" "os" "git.trj.tw/golang/argparse" @@ -26,3 +27,10 @@ func Parse() error { return parser.Parse(os.Args) } + +func Get() *Args { + if a == nil { + panic(errors.New("arguments not init")) + } + return a +} diff --git a/pkg/config/config.go b/pkg/config/config.go index f10068c..fa9aec7 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -17,9 +17,17 @@ type Database struct { IdleConn uint `yaml:"idle_conn" env:"DB_IDLE_CONN" default:"2"` } +// Redis connect setting +type Redis struct { + Host string `yaml:"host" env:"REDIS_HOST" default:"localhost"` + Port int `yaml:"port" env:"REDIS_PORT" default:"6379"` + Prefix string `yaml:"prefix" env:"REDIS_PREFIX"` +} + type Config struct { Server Server `yaml:"server"` Database Database `yaml:"database"` + Redis Redis `yaml:"redis"` } var c *Config diff --git a/pkg/context/context.go b/pkg/context/context.go new file mode 100644 index 0000000..6f7db9b --- /dev/null +++ b/pkg/context/context.go @@ -0,0 +1,75 @@ +package context + +import ( + "context" + "go-api/pkg/response" + + "github.com/gin-gonic/gin" +) + +type C struct { + *gin.Context +} + +type CustomHandler func(c *C) + +func PatchContext(handler CustomHandler) gin.HandlerFunc { + return func(ctx *gin.Context) { + c := &C{ + Context: ctx, + } + handler(c) + } +} + +func (c *C) getContext() context.Context { + return c.Request.Context() +} + +// Success +// send success body to client +func (c *C) Success(i ...interface{}) { + r := response.Get(response.RespSuccess) + + var resp interface{} = r.Body + if len(i) > 0 { + resp = i[0] + } + + c.AbortWithStatusJSON(r.Status, resp) +} + +func (c *C) DataFormat(code ...response.MessageCode) { + r := response.Get(response.RespDataFormat, code...) + c.AbortWithStatusJSON(r.Status, r.Body) +} + +func (c *C) NotFound(code ...response.MessageCode) { + r := response.Get(response.RespNotFound, code...) + c.AbortWithStatusJSON(r.Status, r.Body) +} + +func (c *C) Forbidden(code ...response.MessageCode) { + r := response.Get(response.RespNotFound, code...) + c.AbortWithStatusJSON(r.Status, r.Body) +} + +func (c *C) ServerError(code ...response.MessageCode) { + r := response.Get(response.RespInternalError, code...) + c.AbortWithStatusJSON(r.Status, r.Body) +} + +func (c *C) CustomResp(rt response.RespType, code response.MessageCode, data ...interface{}) { + r := response.Get(rt) + + if code != r.Body.MessageCode { + r.Body.MessageCode, r.Body.Message = response.GetCodeMessage(code) + } + + var resp interface{} = r.Body + if len(data) > 0 { + resp = data[0] + } + + c.AbortWithStatusJSON(r.Status, resp) +} diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go new file mode 100644 index 0000000..91c3c40 --- /dev/null +++ b/pkg/errors/errors.go @@ -0,0 +1,39 @@ +package errors + +import ( + "fmt" + "go-api/pkg/response" +) + +var ( + ErrDataFormat = New(response.RespDataFormat) + ErrUnauthorized = New(response.RespUnauthorized) + ErrNotFound = New(response.RespNotFound) + ErrInternalError = New(response.RespInternalError) +) + +type APIError struct { + code *response.MessageCode + status response.RespType + message string +} + +func (e *APIError) Error() string { + s := fmt.Sprintf("Status: %s, Message: %s", e.status, e.message) + if e.code != nil { + c, m := response.GetCodeMessage(*e.code) + s = fmt.Sprintf("%s, Code: %d, CodeMessage: %s", s, c, m) + } + return s +} + +func New(status response.RespType, code ...response.MessageCode) *APIError { + e := &APIError{ + status: status, + } + + if len(code) > 0 { + e.code = &code[0] + } + return e +} diff --git a/pkg/redis/redis.go b/pkg/redis/redis.go new file mode 100644 index 0000000..54e4d76 --- /dev/null +++ b/pkg/redis/redis.go @@ -0,0 +1,39 @@ +package redis + +import ( + "fmt" + + "github.com/go-redis/redis" +) + +const ( + KeyToken = "91-token:%s" +) + +type Redis struct { + *redis.Client + prefix string +} + +var r *Redis + +// Init redis client +func Init(port int, host, prefix string) error { + r = &Redis{prefix: prefix} + r.Client = redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%s:%d", host, port), + }) + + if _, err := r.Ping().Result(); err != nil { + return err + } + return nil +} + +// Key combine prefix to key +func (x *Redis) Key(key string) string { + if len(x.prefix) > 0 { + return fmt.Sprintf("%s:%s", x.prefix, key) + } + return key +} diff --git a/pkg/response/code.go b/pkg/response/code.go new file mode 100644 index 0000000..f088c68 --- /dev/null +++ b/pkg/response/code.go @@ -0,0 +1,44 @@ +package response + +type MessageCode int + +const ( + // HTTP Default Message + CodeSuccess MessageCode = 1000 + CodeCreated MessageCode = 1001 + CodeAccepted MessageCode = 1002 + CodeNoContent MessageCode = 1003 + CodeRedirect MessageCode = 1004 + CodeDataFormat MessageCode = 1005 + CodeUnauthorized MessageCode = 1006 + CodeForbidden MessageCode = 1007 + CodeNotFound MessageCode = 1008 + CodeInternalError MessageCode = 1009 + + // Custom Message +) + +var code map[MessageCode]string + +func init() { + code = map[MessageCode]string{ + CodeSuccess: "Success", + CodeCreated: "Created", + CodeAccepted: "Accepted", + CodeNoContent: "No Content", + CodeRedirect: "Moved Permanently", + CodeDataFormat: "Data Format Error", + CodeUnauthorized: "Unauhorized", + CodeForbidden: "Forbidden", + CodeNotFound: "Not Found", + CodeInternalError: "Internal Error", + } +} + +func GetCodeMessage(c MessageCode) (MessageCode, string) { + if r, ok := code[c]; ok { + return c, r + } + + return c, "" +} diff --git a/pkg/response/response.go b/pkg/response/response.go new file mode 100644 index 0000000..64fde23 --- /dev/null +++ b/pkg/response/response.go @@ -0,0 +1,81 @@ +package response + +type RespType string + +const ( + RespSuccess RespType = "success" + RespCreated RespType = "created" + RespAccepted RespType = "accepted" + RespNoContent RespType = "noContent" + RespRedirect RespType = "redirect" + RespDataFormat RespType = "dataFormat" + RespUnauthorized RespType = "unauthorized" + RespForbidden RespType = "forbidden" + RespNotFound RespType = "notFound" + RespInternalError RespType = "internalError" +) + +// swagger:model defResponse +type RespBody struct { + MessageCode MessageCode `json:"messageCode"` + Message string `json:"message"` +} + +// swagger:response genericResponse +type Resp struct { + // in: body + Body RespBody + Status int +} + +func Get(key RespType, c ...MessageCode) Resp { + r := Resp{Body: RespBody{}} + + switch key { + case RespSuccess: + r.Status = 200 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeSuccess) + break + case RespCreated: + r.Status = 201 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeCreated) + break + case RespAccepted: + r.Status = 202 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeAccepted) + break + case RespNoContent: + r.Status = 204 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeNoContent) + break + case RespRedirect: + r.Status = 301 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeRedirect) + break + case RespDataFormat: + r.Status = 400 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeDataFormat) + break + case RespUnauthorized: + r.Status = 401 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeUnauthorized) + break + case RespForbidden: + r.Status = 403 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeForbidden) + break + case RespNotFound: + r.Status = 404 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeNotFound) + break + default: + r.Status = 500 + r.Body.MessageCode, r.Body.Message = GetCodeMessage(CodeInternalError) + } + + if len(c) > 0 { + r.Body.MessageCode, r.Body.Message = GetCodeMessage(c[0]) + } + + return r +} diff --git a/pkg/swagger/swagger.go b/pkg/swagger/swagger.go new file mode 100644 index 0000000..9a021ac --- /dev/null +++ b/pkg/swagger/swagger.go @@ -0,0 +1,18 @@ +// Package swagger api document +// +// Terms Of Services: +// +// there are no TOS +// +// Schemes: http, https +// Host localhost +// BasePath: / +// Version: 0.0.0 +// +// Consumes: +// - application/json +// Produces: +// - application/json +// +// swagger:meta +package swagger diff --git a/pkg/version/version.go b/pkg/version/version.go new file mode 100644 index 0000000..12e5979 --- /dev/null +++ b/pkg/version/version.go @@ -0,0 +1,20 @@ +package version + +import ( + "fmt" + "runtime" +) + +var ( + Version string + BuildDate string +) + +func PrintCliVersion() string { + return fmt.Sprintf( + "version: %s, built on %s, %s", + Version, + BuildDate, + runtime.Version(), + ) +} diff --git a/route/routes/routes.go b/router/routes/routes.go similarity index 100% rename from route/routes/routes.go rename to router/routes/routes.go