8 changed files with 314 additions and 131 deletions
@ -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" |
|||
"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" |
|||
"github.com/go-chi/chi" |
|||
) |
|||
|
|||
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) |
|||
func main() { |
|||
dbName := os.Getenv("DB_NAME") |
|||
dbPass := os.Getenv("DB_PASS") |
|||
dbHost := os.Getenv("DB_HOST") |
|||
dbPort := os.Getenv("DB_PORT") |
|||
|
|||
err := row.Scan( |
|||
&payload.ID, |
|||
&payload.Title, |
|||
&payload.Content, |
|||
) |
|||
println("this is db") |
|||
|
|||
connection, err := driver.ConnectSQL(dbHost, dbPort, "root", dbPass, dbName) |
|||
if err != nil { |
|||
respondWithError(w, http.StatusNotFound, "no rows in result set") |
|||
return |
|||
fmt.Println(err) |
|||
os.Exit(-1) |
|||
} |
|||
|
|||
respondwithJSON(w, http.StatusOK, payload) |
|||
} |
|||
r := chi.NewRouter() |
|||
r.Use(middleware.Recoverer) |
|||
r.Use(middleware.Logger) |
|||
|
|||
//
|
|||
func main() { |
|||
routers() |
|||
http.ListenAndServe(":8005", 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) |
|||
} |
|||
Loading…
Reference in new issue