better hierarchy and better way to make a CRUD
This commit is contained in:
+2
-2
@@ -1,7 +1,7 @@
|
||||
# ---> VisualStudioCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
vendor/*
|
||||
blog
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package driver
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
// DB ...
|
||||
type DB struct {
|
||||
SQL *sql.DB
|
||||
// Mgo *mgo.database
|
||||
}
|
||||
|
||||
var dbConn = &DB{}
|
||||
|
||||
// ConnectSQL ...
|
||||
func ConnectSQL(host, port, uname, pass, dbname string) (*DB, error) {
|
||||
dbSource := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%s)/%s?charset=utf8",
|
||||
uname,
|
||||
pass,
|
||||
host,
|
||||
port,
|
||||
dbname,
|
||||
)
|
||||
d, err := sql.Open("mysql", dbSource)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dbConn.SQL = d
|
||||
return dbConn, err
|
||||
}
|
||||
|
||||
// connectMongo ...
|
||||
func connectMongo(host, port, uname, pass string) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"blog/driver"
|
||||
models "blog/models"
|
||||
repository "blog/repository"
|
||||
post "blog/repository/post"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// NewPostHandler ...
|
||||
func NewPostHandler(db *driver.DB) *Post {
|
||||
return &Post{
|
||||
repo: post.NewSQLPostRepo(db.SQL),
|
||||
}
|
||||
}
|
||||
|
||||
// Post ...
|
||||
type Post struct {
|
||||
repo repository.PostRepo
|
||||
}
|
||||
|
||||
// Fetch ...
|
||||
func (p *Post) Fetch(w http.ResponseWriter, r *http.Request) {
|
||||
payload, _ := p.repo.Fetch(r.Context(), 25)
|
||||
|
||||
respondwithJSON(w, http.StatusOK, payload)
|
||||
}
|
||||
|
||||
// Create a new post
|
||||
func (p *Post) Create(w http.ResponseWriter, r *http.Request) {
|
||||
post := models.Post{}
|
||||
json.NewDecoder(r.Body).Decode(&post)
|
||||
|
||||
newID, err := p.repo.Create(r.Context(), &post)
|
||||
fmt.Println(newID)
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, "Server Error")
|
||||
}
|
||||
respondwithJSON(w, http.StatusCreated, map[string]string{"message": "Successfully Created"})
|
||||
}
|
||||
|
||||
// Update a post by id
|
||||
func (p *Post) Update(w http.ResponseWriter, r *http.Request) {
|
||||
id, _ := strconv.Atoi(chi.URLParam(r, "id"))
|
||||
data := models.Post{ID: int(id)}
|
||||
json.NewDecoder(r.Body).Decode(&data)
|
||||
payload, err := p.repo.Update(r.Context(), &data)
|
||||
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, "Server Error")
|
||||
}
|
||||
|
||||
respondwithJSON(w, http.StatusOK, payload)
|
||||
}
|
||||
|
||||
// GetByID returns a post details
|
||||
func (p *Post) GetByID(w http.ResponseWriter, r *http.Request) {
|
||||
id, _ := strconv.Atoi(chi.URLParam(r, "id"))
|
||||
payload, err := p.repo.GetByID(r.Context(), int64(id))
|
||||
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusNoContent, "Content not found")
|
||||
}
|
||||
|
||||
respondwithJSON(w, http.StatusOK, payload)
|
||||
}
|
||||
|
||||
// Delete a post
|
||||
func (p *Post) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
id, _ := strconv.Atoi(chi.URLParam(r, "id"))
|
||||
_, err := p.repo.Delete(r.Context(), int64(id))
|
||||
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusInternalServerError, "Server Error")
|
||||
}
|
||||
|
||||
respondwithJSON(w, http.StatusMovedPermanently, map[string]string{"message": "Delete Successfully"})
|
||||
}
|
||||
|
||||
// respondwithJSON write json response format
|
||||
func respondwithJSON(w http.ResponseWriter, code int, payload interface{}) {
|
||||
response, _ := json.Marshal(payload)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
w.Write(response)
|
||||
}
|
||||
|
||||
// respondwithError return error message
|
||||
func respondWithError(w http.ResponseWriter, code int, msg string) {
|
||||
respondwithJSON(w, code, map[string]string{"message": msg})
|
||||
}
|
||||
@@ -1,146 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"blog/driver"
|
||||
ph "blog/handler/http"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/go-chi/chi/middleware"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
var router *chi.Mux
|
||||
var db *sql.DB
|
||||
|
||||
const (
|
||||
dbName = "go-mysql-crud"
|
||||
dbPass = ""
|
||||
dbHost = "localhost"
|
||||
dbPort = "3306"
|
||||
)
|
||||
|
||||
func routers() *chi.Mux {
|
||||
router.Get("/posts", AllPosts)
|
||||
router.Get("/posts/{id}", DetailPost)
|
||||
router.Post("/posts", CreatePost)
|
||||
router.Put("/posts/{id}", UpdatePost)
|
||||
router.Delete("/posts/{id}", DeletePost)
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
func init() {
|
||||
router = chi.NewRouter()
|
||||
router.Use(middleware.Recoverer)
|
||||
|
||||
dbSource := fmt.Sprintf("root:%s@tcp(%s:%s)/%s?charset=utf8", dbPass, dbHost, dbPort, dbName)
|
||||
fmt.Println(dbSource)
|
||||
var err error
|
||||
db, err = sql.Open("mysql", dbSource)
|
||||
|
||||
catch(err)
|
||||
}
|
||||
|
||||
// Post ...
|
||||
type Post struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// CreatePost ...
|
||||
func CreatePost(w http.ResponseWriter, r *http.Request) {
|
||||
var post Post
|
||||
json.NewDecoder(r.Body).Decode(&post)
|
||||
|
||||
query, err := db.Prepare("Insert posts SET title=?, content=?")
|
||||
catch(err)
|
||||
|
||||
_, er := query.Exec(post.Title, post.Content)
|
||||
catch(er)
|
||||
defer query.Close()
|
||||
|
||||
respondwithJSON(w, http.StatusCreated, map[string]string{"message": "successfully created"})
|
||||
}
|
||||
|
||||
// UpdatePost ...
|
||||
func UpdatePost(w http.ResponseWriter, r *http.Request) {
|
||||
var post Post
|
||||
id := chi.URLParam(r, "id")
|
||||
json.NewDecoder(r.Body).Decode(&post)
|
||||
|
||||
query, err := db.Prepare("Update posts set title=?, content=? where id=?")
|
||||
catch(err)
|
||||
_, er := query.Exec(post.Title, post.Content, id)
|
||||
catch(er)
|
||||
|
||||
defer query.Close()
|
||||
|
||||
respondwithJSON(w, http.StatusOK, map[string]string{"message": "update successfully"})
|
||||
}
|
||||
|
||||
// DeletePost ...
|
||||
func DeletePost(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
|
||||
query, err := db.Prepare("delete from post where id=?")
|
||||
catch(err)
|
||||
_, er := query.Exec(id)
|
||||
catch(er)
|
||||
query.Close()
|
||||
|
||||
respondwithJSON(w, http.StatusOK, map[string]string{"message": "deleted successfully"})
|
||||
}
|
||||
|
||||
// AllPosts ...
|
||||
func AllPosts(w http.ResponseWriter, r *http.Request) {
|
||||
errors := []error{}
|
||||
payload := []Post{}
|
||||
|
||||
rows, err := db.Query("Select id, title, content From posts")
|
||||
catch(err)
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
data := Post{}
|
||||
|
||||
er := rows.Scan(&data.ID, &data.Title, &data.Content)
|
||||
|
||||
if er != nil {
|
||||
errors = append(errors, er)
|
||||
}
|
||||
payload = append(payload, data)
|
||||
}
|
||||
|
||||
respondwithJSON(w, http.StatusOK, payload)
|
||||
}
|
||||
|
||||
// DetailPost ...
|
||||
func DetailPost(w http.ResponseWriter, r *http.Request) {
|
||||
payload := Post{}
|
||||
id := chi.URLParam(r, "id")
|
||||
|
||||
row := db.QueryRow("Select if, title, content From posts where id=?", id)
|
||||
|
||||
err := row.Scan(
|
||||
&payload.ID,
|
||||
&payload.Title,
|
||||
&payload.Content,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
respondWithError(w, http.StatusNotFound, "no rows in result set")
|
||||
return
|
||||
}
|
||||
|
||||
respondwithJSON(w, http.StatusOK, payload)
|
||||
}
|
||||
|
||||
//
|
||||
func main() {
|
||||
routers()
|
||||
http.ListenAndServe(":8005", Logger())
|
||||
dbName := os.Getenv("DB_NAME")
|
||||
dbPass := os.Getenv("DB_PASS")
|
||||
dbHost := os.Getenv("DB_HOST")
|
||||
dbPort := os.Getenv("DB_PORT")
|
||||
|
||||
println("this is db")
|
||||
|
||||
connection, err := driver.ConnectSQL(dbHost, dbPort, "root", dbPass, dbName)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.Recoverer)
|
||||
r.Use(middleware.Logger)
|
||||
|
||||
pHandler := ph.NewPostHandler(connection)
|
||||
r.Get("/posts", pHandler.Fetch)
|
||||
r.Get("/posts/{id}", pHandler.GetByID)
|
||||
r.Post("/posts", pHandler.Create)
|
||||
r.Put("/posts/{id}", pHandler.Update)
|
||||
r.Delete("/posts/{id}", pHandler.Delete)
|
||||
|
||||
fmt.Println("Server listen at :8005")
|
||||
http.ListenAndServe(":8005", r)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package models
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrNotFound ...
|
||||
ErrNotFound = errors.New("requested item is not found")
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package models
|
||||
|
||||
// Post ...
|
||||
type Post struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package post
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
models "blog/models"
|
||||
pRepo "blog/repository"
|
||||
)
|
||||
|
||||
// NewSQLPostRepo ...
|
||||
func NewSQLPostRepo(Conn *sql.DB) pRepo.PostRepo {
|
||||
return &mysqlPostRepo{
|
||||
Conn: Conn,
|
||||
}
|
||||
}
|
||||
|
||||
type mysqlPostRepo struct {
|
||||
Conn *sql.DB
|
||||
}
|
||||
|
||||
// fetch ...
|
||||
func (m *mysqlPostRepo) fetch(ctx context.Context, query string, args ...interface{}) ([]*models.Post, error) {
|
||||
rows, err := m.Conn.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
payload := make([]*models.Post, 0)
|
||||
for rows.Next() {
|
||||
data := new(models.Post)
|
||||
err := rows.Scan(
|
||||
&data.ID,
|
||||
&data.Title,
|
||||
&data.Content,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payload = append(payload, data)
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func (m *mysqlPostRepo) Fetch(ctx context.Context, num int64) ([]*models.Post, error) {
|
||||
query := "Select id, title, content From posts limit ?"
|
||||
|
||||
return m.fetch(ctx, query, num)
|
||||
}
|
||||
|
||||
func (m *mysqlPostRepo) GetByID(ctx context.Context, id int64) (*models.Post, error) {
|
||||
query := "Select id, title, content From posts where id=?"
|
||||
|
||||
rows, err := m.fetch(ctx, query, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payload := &models.Post{}
|
||||
if len(rows) > 0 {
|
||||
payload = rows[0]
|
||||
} else {
|
||||
return nil, models.ErrNotFound
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func (m *mysqlPostRepo) Create(ctx context.Context, p *models.Post) (int64, error) {
|
||||
query := "Insert posts SET title=?, content=?"
|
||||
|
||||
stmt, err := m.Conn.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
res, err := stmt.ExecContext(ctx, p.Title, p.Content)
|
||||
defer stmt.Close()
|
||||
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
func (m *mysqlPostRepo) Update(ctx context.Context, p *models.Post) (*models.Post, error) {
|
||||
query := "Update posts set title=?, content=? where id=?"
|
||||
|
||||
stmt, err := m.Conn.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = stmt.ExecContext(
|
||||
ctx,
|
||||
p.Title,
|
||||
p.Content,
|
||||
p.ID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.Close()
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (m *mysqlPostRepo) Delete(ctx context.Context, id int64) (bool, error) {
|
||||
query := "Delete From posts Where id=?"
|
||||
|
||||
stmt, err := m.Conn.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = stmt.ExecContext(ctx, id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer stmt.Close()
|
||||
return true, nil
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"blog/models"
|
||||
)
|
||||
|
||||
// PostRepo explain...
|
||||
type PostRepo interface {
|
||||
Fetch(ctx context.Context, num int64) ([]*models.Post, error)
|
||||
GetByID(ctx context.Context, id int64) (*models.Post, error)
|
||||
Create(ctx context.Context, p *models.Post) (int64, error)
|
||||
Update(ctx context.Context, p *models.Post) (*models.Post, error)
|
||||
Delete(ctx context.Context, id int64) (bool, error)
|
||||
}
|
||||
Reference in New Issue
Block a user