Compare commits
11 Commits
dev-21-04-
...
develop
Author | SHA1 | Date | |
---|---|---|---|
752a058ac3 | |||
90a0f562ea | |||
39ed417398 | |||
316323587d | |||
0fb494f0fd | |||
30ee6e8c39 | |||
bf3f5a0fc0 | |||
41292b25e3 | |||
ceb3c4bba5 | |||
69b4179102 | |||
4dab09e66b |
@ -32,7 +32,6 @@ steps:
|
||||
- name: build_image
|
||||
image: plugins/docker
|
||||
commands:
|
||||
- env
|
||||
- sleep 5
|
||||
- ./deploy/docker/build_image.sh
|
||||
depends_on:
|
||||
|
2
Makefile
2
Makefile
@ -7,7 +7,7 @@ race:
|
||||
go run --race cmd/server/main.go
|
||||
|
||||
build:
|
||||
go build -o build/server cmd/server/main.go
|
||||
GOOS=linux GOARCH=amd64 go build -o build/server cmd/server/main.go
|
||||
|
||||
test:
|
||||
go test -v -run=. test/**/*.go
|
||||
|
@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -17,20 +16,22 @@ import (
|
||||
const (
|
||||
defHttpIp = "127.0.0.1"
|
||||
defHttpPort = "8080"
|
||||
defDbUrl = "postgres://postgres:postgres@127.0.0.1:5432/Api" // FIXME use default container conf in future
|
||||
defDbUrl = "postgres://postgres:postgres@127.0.0.1:5432/Api" // FIXME: use env
|
||||
)
|
||||
|
||||
func main() {
|
||||
if config.ErrLoadingEnvs != nil {
|
||||
log.Fatalln("Error loading .env file")
|
||||
app.Panicf("Error loading .env file")
|
||||
}
|
||||
|
||||
httpAddr := net.JoinHostPort(config.GetEnv("SERVER_IP", defHttpIp), config.GetEnv("SERVER_PORT", defHttpPort))
|
||||
dbConnStr := config.GetEnv("DATABASE_URL", defDbUrl)
|
||||
//fmt.Println(dbConnStr)
|
||||
//os.Exit(1)
|
||||
|
||||
dbc, err := database.Connect(dbConnStr)
|
||||
if err != nil {
|
||||
log.Panicf("Unable to connect to database: %v\n", err)
|
||||
app.Panicf("Unable to connect to database: %v\n", err)
|
||||
}
|
||||
|
||||
env := &handler.Env{httpAddr, dbc}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -x
|
||||
set -evx
|
||||
|
||||
branch=${DRONE_TAG:=$CI_COMMIT_BRANCH}
|
||||
branch=$(echo $branch | grep -v /) || echo $branch ;
|
||||
|
@ -1,6 +1,5 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -x
|
||||
set -evx
|
||||
|
||||
branch=${DRONE_TAG:=$CI_COMMIT_BRANCH}
|
||||
branch=$(echo $branch | grep -v /) || echo $branch ;
|
||||
|
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
||||
module git.pbiernat.dev/golang/rest-api-prototype
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
|
||||
|
21
init/api-server.service
Normal file
21
init/api-server.service
Normal file
@ -0,0 +1,21 @@
|
||||
#FIXME: FIX PATHS
|
||||
|
||||
[Unit]
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
Requires=api-server.socket
|
||||
|
||||
[Service]
|
||||
ExecStart=/home/keedosn/go/src/git.pbiernat.dev/golang/rest-api-prototype/build/server
|
||||
ExecStop=/bin/kill $MAINPID
|
||||
WorkingDirectory=/home/keedosn/go/src/git.pbiernat.dev/golang/rest-api-prototype
|
||||
User=keedosn
|
||||
Group=keedosn
|
||||
NonBlocking=true
|
||||
StandardOutput=append:/home/keedosn/go/src/git.pbiernat.dev/golang/rest-api-prototype/build/api-server.log
|
||||
StandardError=append:/home/keedosn/go/src/git.pbiernat.dev/golang/rest-api-prototype/build/api-server.log
|
||||
SyslogIdentifier=api-server
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
7
init/api-server.socket
Normal file
7
init/api-server.socket
Normal file
@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=API Server socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=10080
|
||||
NoDelay=true
|
||||
|
@ -12,9 +12,6 @@ func init() {
|
||||
ErrLoadingEnvs = godotenv.Load()
|
||||
}
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetEnv(name, defVal string) string {
|
||||
env := os.Getenv(name)
|
||||
if env == "" {
|
||||
|
@ -1,16 +0,0 @@
|
||||
package definition
|
||||
|
||||
import "git.pbiernat.dev/golang/rest-api-prototype/internal/app/entity"
|
||||
|
||||
type CreateArticleRequest struct {
|
||||
CategoryID int `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Intro string `json:"intro"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type CreateArticleResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data *entity.Article `json:"data"`
|
||||
Err string `json:"err,omitempty"`
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package definition
|
||||
|
||||
import (
|
||||
"git.pbiernat.dev/golang/rest-api-prototype/internal/app/entity"
|
||||
validation "github.com/go-ozzo/ozzo-validation"
|
||||
)
|
||||
|
||||
type CreateCategoryRequest struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (c CreateCategoryRequest) Validate() error {
|
||||
return validation.ValidateStruct(&c,
|
||||
validation.Field(&c.Name, validation.Required, validation.Length(3, 255)),
|
||||
)
|
||||
}
|
||||
|
||||
type CreateCategoryResponse struct {
|
||||
Data *entity.Category `json:"data"`
|
||||
Err string `json:"err,omitempty"` // FIXME: omitempty on/off?
|
||||
}
|
||||
|
||||
type DeleteCategoryRequest struct {
|
||||
}
|
||||
|
||||
type DeleteCategoryResponse struct {
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Article struct {
|
||||
ID int `json:"id"`
|
||||
CategoryID int `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Intro string `json:"intro"`
|
||||
Text string `json:"text"`
|
||||
CreateDate time.Time `json:"create_date"`
|
||||
ModifyDate time.Time `json:"modify_date"`
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Category struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CreateDate time.Time `json:"create_date"`
|
||||
ModifyDate time.Time `json:"modify_date"` // FIXME: zero-value issue
|
||||
}
|
||||
|
||||
// func (c Category) Validate() error {
|
||||
// return validation.ValidateStruct(&c,
|
||||
// validation.Field(&c.Name, validation.Required, validation.Length(3, 255)),
|
||||
// )
|
||||
// }
|
@ -1,34 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
def "git.pbiernat.dev/golang/rest-api-prototype/internal/app/definition"
|
||||
"git.pbiernat.dev/golang/rest-api-prototype/internal/app/entity"
|
||||
)
|
||||
|
||||
var CreateArticleHandler *Handler
|
||||
|
||||
func init() {
|
||||
CreateArticleHandler = &Handler{
|
||||
Handle: CreateArticleHandlerFunc,
|
||||
Request: &def.CreateArticleRequest{},
|
||||
Response: &def.CreateArticleResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func CreateArticleHandlerFunc(h *Handler, w http.ResponseWriter) (interface{}, int, error) {
|
||||
var art = h.Request.(*def.CreateArticleRequest)
|
||||
log.Println(art)
|
||||
|
||||
return &entity.Article{
|
||||
ID: 1,
|
||||
CategoryID: 1,
|
||||
Title: "Dummy article",
|
||||
Intro: "Intro",
|
||||
Text: "Text",
|
||||
CreateDate: time.Now(),
|
||||
}, http.StatusCreated, nil
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
def "git.pbiernat.dev/golang/rest-api-prototype/internal/app/definition"
|
||||
"git.pbiernat.dev/golang/rest-api-prototype/internal/app/entity"
|
||||
)
|
||||
|
||||
var CreateCategoryHandler *Handler
|
||||
var DeleteCategoryHandler *Handler
|
||||
|
||||
func init() {
|
||||
CreateCategoryHandler = &Handler{
|
||||
Handle: CreateCategoryHandlerFunc,
|
||||
Request: &def.CreateCategoryRequest{},
|
||||
Response: &def.CreateCategoryResponse{},
|
||||
}
|
||||
|
||||
DeleteCategoryHandler = &Handler{
|
||||
Handle: DeleteCategoryHandlerFunc,
|
||||
Request: &def.DeleteCategoryRequest{},
|
||||
Response: &def.DeleteCategoryResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func CreateCategoryHandlerFunc(h *Handler, w http.ResponseWriter) (interface{}, int, error) {
|
||||
var cat = h.Request.(*def.CreateCategoryRequest)
|
||||
log.Println("Cat input:", cat)
|
||||
|
||||
if err := cat.Validate(); err != nil {
|
||||
log.Println("Create category validation errors:", err)
|
||||
return nil, http.StatusUnprocessableEntity, err
|
||||
}
|
||||
|
||||
return &entity.Category{
|
||||
Name: cat.Name,
|
||||
CreateDate: time.Now(),
|
||||
}, http.StatusCreated, nil
|
||||
}
|
||||
|
||||
func DeleteCategoryHandlerFunc(h *Handler, w http.ResponseWriter) (interface{}, int, error) {
|
||||
var cat = h.Request.(*def.DeleteCategoryRequest)
|
||||
log.Println(cat)
|
||||
|
||||
id, _ := strconv.Atoi(h.Params["id"])
|
||||
log.Println(h.Params)
|
||||
|
||||
if id != 1 {
|
||||
return nil, http.StatusNotFound, nil
|
||||
}
|
||||
|
||||
return nil, http.StatusNoContent, nil
|
||||
}
|
@ -34,8 +34,11 @@ type response struct {
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func New(e *Env, h *Handler) *Handler {
|
||||
return &Handler{e, h.Handle, h.Request, h.Response, Set{}}
|
||||
func Init(e *Env, h *Handler) *Handler {
|
||||
// return &Handler{e, h.Handle, h.Request, h.Response, Set{}}
|
||||
h.Env = e
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
@ -68,7 +71,9 @@ func encodeResponse(w http.ResponseWriter, res *response, err error) {
|
||||
}
|
||||
|
||||
w.WriteHeader(res.Status)
|
||||
json.NewEncoder(w).Encode(res.Data)
|
||||
if res.Data != nil {
|
||||
json.NewEncoder(w).Encode(res.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeError(w http.ResponseWriter, status int, e error) {
|
||||
|
16
internal/app/log.go
Normal file
16
internal/app/log.go
Normal file
@ -0,0 +1,16 @@
|
||||
package app
|
||||
|
||||
import "log"
|
||||
|
||||
func Panic(v ...any) {
|
||||
log.Panicln(Name + ":", v)
|
||||
}
|
||||
|
||||
func Panicf(format string, v ...any) {
|
||||
log.Panicf(Name + ": " + format, v...)
|
||||
}
|
||||
|
||||
func Panicln(v ...any) {
|
||||
v = append([]any{Name + ":"}, v...)
|
||||
log.Panicln(v...)
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"git.pbiernat.dev/golang/rest-api-prototype/internal/app/handler"
|
||||
"git.pbiernat.dev/golang/rest-api-prototype/internal/app/service"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
@ -18,18 +17,10 @@ func SetupRouter(env *handler.Env) *mux.Router {
|
||||
r.Use(LoggingMiddleware)
|
||||
|
||||
hc := r.PathPrefix("/health").Subrouter()
|
||||
hc.Handle("", handler.New(env, handler.HealthCheckHandler)).Methods(http.MethodGet)
|
||||
hc.Handle("", handler.Init(env, handler.HealthCheckHandler)).Methods(http.MethodGet)
|
||||
|
||||
auth := r.PathPrefix("/auth").Subrouter()
|
||||
auth.Handle("/login", handler.New(env, handler.AuthLoginHandler)).Methods(http.MethodPost)
|
||||
|
||||
api := r.PathPrefix("/api").Subrouter()
|
||||
api.Use(service.AuthService.ValidateUserTokenMiddleware) // only /api/** endpoints use this middleware
|
||||
|
||||
api.Handle("/article", handler.New(env, handler.CreateArticleHandler)).Methods(http.MethodPost)
|
||||
|
||||
api.Handle("/category", handler.New(env, handler.CreateCategoryHandler)).Methods(http.MethodPost)
|
||||
api.Handle("/category/{id:[0-9]+}", handler.New(env, handler.DeleteCategoryHandler)).Methods(http.MethodDelete)
|
||||
auth.Handle("/login", handler.Init(env, handler.AuthLoginHandler)).Methods(http.MethodPost)
|
||||
|
||||
return r
|
||||
}
|
||||
|
@ -5,13 +5,18 @@ import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
def "git.pbiernat.dev/golang/rest-api-prototype/internal/app/definition"
|
||||
"git.pbiernat.dev/golang/rest-api-prototype/internal/app/handler"
|
||||
)
|
||||
|
||||
const Name = "REST API Service"
|
||||
|
||||
type Server struct {
|
||||
*http.Server
|
||||
}
|
||||
@ -29,9 +34,20 @@ func NewServer(env *handler.Env) *Server {
|
||||
}
|
||||
|
||||
func (s *Server) Start() {
|
||||
log.Println("Server listening on " + s.Addr)
|
||||
if err := s.ListenAndServe(); err != nil {
|
||||
log.Println(err)
|
||||
if os.Getenv("LISTEN_PID") == strconv.Itoa(os.Getpid()) {
|
||||
// systemd run
|
||||
f := os.NewFile(3, "from systemd")
|
||||
l, err := net.FileListener(f)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
log.Println("Server listening on " + l.Addr().String())
|
||||
s.Serve(l)
|
||||
} else {
|
||||
|
||||
log.Println("Server listening on " + s.Addr)
|
||||
log.Fatalln(s.ListenAndServe())
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user