├── .env ├── .gitignore ├── README.md ├── db └── db_config.go ├── domain └── mahasiswa.go ├── dto └── mahasiswa_dto.go ├── go.mod ├── go.sum ├── handler ├── mahasiswa_api.go └── response.go ├── images └── clean.jpg ├── injection ├── wire.go └── wire_gen.go ├── main.go ├── mapper └── mahasiswa_mapper.go ├── repository └── mahasiswa_repository.go ├── routes ├── mahasiswa_route.go └── route.go └── service └── mahasiswa_service.go /.env: -------------------------------------------------------------------------------- 1 | DB_USERNAME=root 2 | DB_PASSWORD=root 3 | DB_HOST=localhost 4 | DB_PORT=3306 5 | DB_DATABASE=golang_crud 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | .idea 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Table of contents 2 | * [General info](#general-info) 3 | * [Technologies](#technologies) 4 | * [Setup](#setup) 5 | 6 | ## General info 7 | Repository adalah hasil percobaan penulis dalam belajar Golang yang mana menggunakan Clean Architecture, yang memisahkan setiap layer aplikasi. Pada umumnya dibedakan menjadi layer : 8 | 9 | 1. Repository 10 | 2. Service 11 | 3. Handler 12 | 13 | ![clean](images/clean.jpg "clean") 14 | 15 | ## Technologies 16 | Project ini menggunakan beberapa teknologi yaitu : 17 | * Golang Versi 1.15 18 | * Echo Labstack 19 | * GORM 20 | * Godotenv 21 | * Logrush 22 | * MySQL 23 | ## Setup 24 | Sebelum itu pastikan MySQL sudah running dan buat sebuah database dengan nama **golang_crud** dan sesuaikan dengan yang ada di **file .env** 25 | 26 | Berikut langkah-langkah untuk running repo ini 27 | 28 | ``` 29 | $ git clone https://github.com/teten-nugraha/golang-crud.git 30 | $ go mod download 31 | $ go run main.go 32 | ``` -------------------------------------------------------------------------------- /db/db_config.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | _ "github.com/jinzhu/gorm/dialects/mysql" 6 | "github.com/joho/godotenv" 7 | "github.com/sirupsen/logrus" 8 | "github.com/teten-nugraha/golang-crud/domain" 9 | "os" 10 | ) 11 | 12 | func InitDB() *gorm.DB { 13 | processENV() 14 | 15 | dbUsername := os.Getenv("DB_USERNAME") 16 | dbPassword := os.Getenv("DB_PASSWORD") 17 | dbHost := os.Getenv("DB_HOST") 18 | dbPort := os.Getenv("DB_PORT") 19 | dbName := os.Getenv("DB_DATABASE") 20 | 21 | 22 | db, err := gorm.Open("mysql", dbUsername+":"+dbPassword+"@tcp("+dbHost+":"+dbPort+")/"+dbName+"?parseTime=true") 23 | if err != nil { 24 | logrus.Error("Cannot Connect to MySQL DB") 25 | panic(err) 26 | } 27 | 28 | migrateDDL(db) 29 | 30 | return db 31 | } 32 | 33 | func migrateDDL(db *gorm.DB) { 34 | // migrasi domain ke tabel di mysql 35 | 36 | db.AutoMigrate(&domain.Mahasiswa{}) 37 | } 38 | 39 | func processENV() { 40 | 41 | err := godotenv.Load(".env") 42 | if err != nil { 43 | logrus.Error("Error loading env file") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /domain/mahasiswa.go: -------------------------------------------------------------------------------- 1 | package domain 2 | 3 | type Mahasiswa struct { 4 | ID uint64 `gorm:"primaryKey;autoIncrement:true"` 5 | Nim string 6 | Nama string 7 | Phone string 8 | Alamat string 9 | Email string 10 | } 11 | -------------------------------------------------------------------------------- /dto/mahasiswa_dto.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | type MahasiswaDTO struct { 4 | 5 | Nim string `json:"nim" validate:"required"` 6 | Nama string `json:"nama" validate:"required"` 7 | Phone string `json:"phone" validate:"required"` 8 | Alamat string `json:"alamat" validate:"required"` 9 | Email string `json:"email" validate:"required"` 10 | 11 | } 12 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/teten-nugraha/golang-crud 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 7 | github.com/google/wire v0.4.0 8 | github.com/jinzhu/gorm v1.9.16 9 | github.com/joho/godotenv v1.3.0 10 | github.com/kr/pretty v0.1.0 // indirect 11 | github.com/labstack/echo v3.3.10+incompatible 12 | github.com/labstack/gommon v0.3.0 // indirect 13 | github.com/satori/go.uuid v1.2.0 14 | github.com/sirupsen/logrus v1.7.0 15 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect 16 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= 2 | github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= 7 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= 8 | github.com/dgrijalva/jwt-go v1.0.2 h1:KPldsxuKGsS2FPWsNeg9ZO18aCrGKujPoWXn2yo+KQM= 9 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 10 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 11 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= 12 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= 13 | github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= 14 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 15 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= 16 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 17 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 18 | github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= 19 | github.com/google/wire v0.4.0 h1:kXcsA/rIGzJImVqPdhfnr6q0xsS9gU0515q1EPpJ9fE= 20 | github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= 21 | github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= 22 | github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= 23 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 24 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 25 | github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 26 | github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= 27 | github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 28 | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= 29 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 30 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 31 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 32 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 33 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 34 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 35 | github.com/labstack/echo v1.4.4 h1:1bEiBNeGSUKxcPDGfZ/7IgdhJJZx8wV/pICJh4W2NJI= 36 | github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= 37 | github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= 38 | github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= 39 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 40 | github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= 41 | github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 42 | github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= 43 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 44 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 45 | github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= 46 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 47 | github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= 48 | github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= 49 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 50 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 51 | github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= 52 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 53 | github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= 54 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 55 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 56 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 57 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 58 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 59 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 60 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 61 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 62 | github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= 63 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 64 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 65 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 66 | golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 67 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= 68 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 69 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 70 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 71 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= 72 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 73 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 74 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= 75 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 76 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 77 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 78 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 79 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 80 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= 81 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 82 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= 83 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 84 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 85 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 86 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 87 | golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 88 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 89 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 90 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 91 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 92 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 93 | gorm.io/gorm v1.20.11 h1:jYHQ0LLUViV85V8dM1TP9VBBkfzKTnuTXDjYObkI6yc= 94 | gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= 95 | -------------------------------------------------------------------------------- /handler/mahasiswa_api.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "github.com/labstack/echo" 5 | _ "github.com/labstack/echo" 6 | "github.com/teten-nugraha/golang-crud/dto" 7 | _ "github.com/teten-nugraha/golang-crud/dto" 8 | "github.com/teten-nugraha/golang-crud/service" 9 | "net/http" 10 | ) 11 | 12 | type MahasiswaAPI struct { 13 | MahasiswaService service.MahasiswaService 14 | } 15 | 16 | func ProviderMahasiswaAPI(k service.MahasiswaService) MahasiswaAPI { 17 | return MahasiswaAPI{MahasiswaService: k} 18 | } 19 | 20 | // implementasi 21 | func (m *MahasiswaAPI) FindAll(e echo.Context) error { 22 | 23 | mahasiswas := m.MahasiswaService.FindAll() 24 | 25 | if len(mahasiswas) == 0 { 26 | return SuccessResponse(e, http.StatusNoContent, mahasiswas) 27 | } 28 | 29 | return SuccessResponse(e, http.StatusOK, mahasiswas) 30 | } 31 | 32 | func (m *MahasiswaAPI) SaveOrUpdate(e echo.Context) error { 33 | var newDto dto.MahasiswaDTO 34 | 35 | newDto.Nim = e.FormValue("Nim") 36 | newDto.Nama = e.FormValue("Nama") 37 | newDto.Phone = e.FormValue("Phone") 38 | newDto.Alamat = e.FormValue("Alamat") 39 | newDto.Email = e.FormValue("Email") 40 | 41 | res, err := m.MahasiswaService.SaveOrUpdate(newDto) 42 | if err != nil { 43 | return ErrorResponse(e, http.StatusInternalServerError, err.Error()) 44 | } 45 | 46 | return SuccessResponse(e, http.StatusOK, res) 47 | } 48 | 49 | func (m *MahasiswaAPI) FindByNIM(e echo.Context) error { 50 | nim := e.Param("nim") 51 | 52 | mahasiswa := m.MahasiswaService.FindByNim(nim) 53 | 54 | return SuccessResponse(e, http.StatusOK, mahasiswa) 55 | } 56 | 57 | func (m *MahasiswaAPI) DeleteMahasiswa(e echo.Context) error { 58 | id := e.Param("id") 59 | 60 | err := m.MahasiswaService.DeleteMahasiswa(id) 61 | if err != nil { 62 | return ErrorResponse(e, http.StatusInternalServerError, err.Error()) 63 | } 64 | 65 | return SuccessResponse(e, http.StatusOK, "Delete Success") 66 | } 67 | -------------------------------------------------------------------------------- /handler/response.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import "github.com/labstack/echo" 4 | 5 | type SuccessResp struct { 6 | SuccessCode int 7 | Data interface{} 8 | } 9 | 10 | type ErrorResp struct { 11 | ErrorCode int 12 | Messages interface{} 13 | } 14 | 15 | func SuccessResponse(c echo.Context, statusCode int, data interface{}) error{ 16 | resp := &SuccessResp{ 17 | SuccessCode: statusCode, 18 | Data: data, 19 | } 20 | c.Response().WriteHeader(statusCode) 21 | c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) 22 | return c.JSONPretty(statusCode, resp, " ") 23 | } 24 | 25 | func ErrorResponse(c echo.Context, errorCode int, messages interface{}) error{ 26 | resp := &ErrorResp{ 27 | ErrorCode: errorCode, 28 | Messages: messages, 29 | } 30 | c.Response().WriteHeader(errorCode) 31 | c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) 32 | return c.JSONPretty(errorCode, resp, " ") 33 | } 34 | -------------------------------------------------------------------------------- /images/clean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teten-nugraha/golang-clean-architecture/41ba790cebf71333b569ed843c3297f8ccd48deb/images/clean.jpg -------------------------------------------------------------------------------- /injection/wire.go: -------------------------------------------------------------------------------- 1 | package injection 2 | 3 | import ( 4 | "github.com/google/wire" 5 | "github.com/jinzhu/gorm" 6 | "github.com/teten-nugraha/golang-crud/handler" 7 | "github.com/teten-nugraha/golang-crud/repository" 8 | "github.com/teten-nugraha/golang-crud/service" 9 | ) 10 | 11 | func initMahasiswaAPI(db *gorm.DB) handler.MahasiswaAPI { 12 | wire.Build(repository.ProviderMahasiswaRepository, service.ProviderMahasiswaService, handler.ProviderMahasiswaAPI) 13 | 14 | return handler.MahasiswaAPI{} 15 | } -------------------------------------------------------------------------------- /injection/wire_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by Wire. DO NOT EDIT. 2 | 3 | //go:generate wire 4 | //+build !wireinject 5 | 6 | package injection 7 | 8 | import ( 9 | "github.com/jinzhu/gorm" 10 | "github.com/teten-nugraha/golang-crud/handler" 11 | "github.com/teten-nugraha/golang-crud/repository" 12 | "github.com/teten-nugraha/golang-crud/service" 13 | ) 14 | 15 | // Injectors from wire.go: 16 | 17 | func InitMahasiswaAPI(db *gorm.DB) handler.MahasiswaAPI { 18 | mahasiswaRepository := repository.ProviderMahasiswaRepository(db) 19 | mahasiswaService := service.ProviderMahasiswaService(mahasiswaRepository) 20 | mahasiswaAPI := handler.ProviderMahasiswaAPI(mahasiswaService) 21 | return mahasiswaAPI 22 | } -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | routes2 "github.com/teten-nugraha/golang-crud/routes" 5 | ) 6 | 7 | func main() { 8 | 9 | routes := routes2.Init() 10 | 11 | routes.Logger.Fatal(routes.Start(":9999")) 12 | } 13 | -------------------------------------------------------------------------------- /mapper/mahasiswa_mapper.go: -------------------------------------------------------------------------------- 1 | package mapper 2 | 3 | import ( 4 | "github.com/teten-nugraha/golang-crud/domain" 5 | "github.com/teten-nugraha/golang-crud/dto" 6 | ) 7 | 8 | // From DTO to Domain 9 | func ToMahasiswaDomain(dto dto.MahasiswaDTO) domain.Mahasiswa { 10 | return domain.Mahasiswa{ 11 | Nim: dto.Nim, 12 | Nama: dto.Nama, 13 | Phone: dto.Phone, 14 | Alamat: dto.Alamat, 15 | Email: dto.Email, 16 | } 17 | } 18 | 19 | func ToMahasiswaDomainList(dtos []dto.MahasiswaDTO) []domain.Mahasiswa { 20 | mahasiswas := make([]domain.Mahasiswa, len(dtos)) 21 | 22 | for i, itm := range dtos { 23 | mahasiswas[i] = ToMahasiswaDomain(itm) 24 | } 25 | return mahasiswas 26 | } 27 | 28 | // from domain to DTO 29 | // From DTO to Domain 30 | func ToMahasiswaDto(mahasiswa domain.Mahasiswa) dto.MahasiswaDTO { 31 | return dto.MahasiswaDTO{ 32 | Nim: mahasiswa.Nim, 33 | Nama: mahasiswa.Nama, 34 | Phone: mahasiswa.Phone, 35 | Alamat: mahasiswa.Alamat, 36 | Email: mahasiswa.Email, 37 | } 38 | } 39 | 40 | func ToMahasiswaDtoList(mahasiswas []domain.Mahasiswa) []dto.MahasiswaDTO { 41 | dtos := make([]dto.MahasiswaDTO, len(mahasiswas)) 42 | 43 | for i, itm := range mahasiswas { 44 | dtos[i] = ToMahasiswaDto(itm) 45 | } 46 | 47 | return dtos 48 | } 49 | -------------------------------------------------------------------------------- /repository/mahasiswa_repository.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "github.com/teten-nugraha/golang-crud/domain" 6 | ) 7 | 8 | type MahasiswaRepositoryContract interface { 9 | SaveOrUpdate(mahasiawa domain.Mahasiswa) (domain.Mahasiswa, error) 10 | FindAll() [] domain.Mahasiswa 11 | FindByID(id string) domain.Mahasiswa 12 | FindByNim(nim string) domain.Mahasiswa 13 | DeleteMahasiswa(mahasiswa domain.Mahasiswa) error 14 | } 15 | 16 | type MahasiswaRepository struct { 17 | DB *gorm.DB 18 | } 19 | 20 | func ProviderMahasiswaRepository(DB *gorm.DB) MahasiswaRepository { 21 | return MahasiswaRepository{DB: DB} 22 | } 23 | 24 | // implementation 25 | func (m *MahasiswaRepository) SaveOrUpdate(mahasiswa domain.Mahasiswa) (domain.Mahasiswa, error) { 26 | if err := m.DB.Create(&mahasiswa).Error; err != nil { 27 | return mahasiswa, err 28 | } 29 | return mahasiswa, nil 30 | } 31 | 32 | func (m *MahasiswaRepository) FindAll() [] domain.Mahasiswa { 33 | var mahasiswas []domain.Mahasiswa 34 | 35 | m.DB.Find(&mahasiswas) 36 | 37 | return mahasiswas 38 | } 39 | 40 | func(m *MahasiswaRepository) FindByID(id string) domain.Mahasiswa { 41 | var mahasiswa domain.Mahasiswa 42 | 43 | m.DB.Where("id =? ", id).Find(&mahasiswa) 44 | 45 | return mahasiswa 46 | } 47 | 48 | 49 | func(m *MahasiswaRepository) FindByNim(nim string) domain.Mahasiswa { 50 | var mahasiswa domain.Mahasiswa 51 | 52 | m.DB.Where("nim =? ", nim).Find(&mahasiswa) 53 | 54 | return mahasiswa 55 | } 56 | 57 | func (m *MahasiswaRepository) DeleteMahasiswa(mahasiswa domain.Mahasiswa) error { 58 | if err := m.DB.Delete(&mahasiswa).Error; err!= nil { 59 | return err 60 | } 61 | return nil 62 | } -------------------------------------------------------------------------------- /routes/mahasiswa_route.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/labstack/echo" 5 | "github.com/teten-nugraha/golang-crud/handler" 6 | ) 7 | 8 | func MahasiswaRoute(routes *echo.Echo, api handler.MahasiswaAPI) { 9 | 10 | mhs := routes.Group("/mahasiswa") 11 | { 12 | mhs.GET("/list", api.FindAll) 13 | mhs.POST("/save", api.SaveOrUpdate) 14 | mhs.GET("/findByNIM/:nim", api.FindByNIM) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /routes/route.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/labstack/echo" 5 | "github.com/labstack/echo/middleware" 6 | db2 "github.com/teten-nugraha/golang-crud/db" 7 | "github.com/teten-nugraha/golang-crud/injection" 8 | ) 9 | 10 | func Init() *echo.Echo { 11 | dbConfig := db2.InitDB() 12 | 13 | mahasiswaAPI := injection.InitMahasiswaAPI(dbConfig) 14 | 15 | routes := echo.New() 16 | 17 | // set logger 18 | routes.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ 19 | Format: "method=${method}, time:${time_unix}, uri=${uri}, status=${status}, error=${error}, latency_human=${latency}, bytes_in=${bytes_in}, bytes_out=${bytes_out} \n", 20 | })) 21 | 22 | // Gzip Compression 23 | routes.Use(middleware.GzipWithConfig(middleware.GzipConfig{ 24 | Level: 5, 25 | })) 26 | 27 | MahasiswaRoute(routes, mahasiswaAPI) 28 | 29 | 30 | return routes 31 | } -------------------------------------------------------------------------------- /service/mahasiswa_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "errors" 5 | "github.com/teten-nugraha/golang-crud/domain" 6 | "github.com/teten-nugraha/golang-crud/dto" 7 | "github.com/teten-nugraha/golang-crud/mapper" 8 | "github.com/teten-nugraha/golang-crud/repository" 9 | ) 10 | 11 | type MahasiswaRepositoryContract interface { 12 | SaveOrUpdate(dto dto.MahasiswaDTO) (dto.MahasiswaDTO, error) 13 | FindAll() [] dto.MahasiswaDTO 14 | FindByNim(nim string) dto.MahasiswaDTO 15 | DeleteMahasiswa(id string) error 16 | } 17 | 18 | type MahasiswaService struct { 19 | MahasiswaRepository repository.MahasiswaRepository 20 | } 21 | 22 | func ProviderMahasiswaService(m repository.MahasiswaRepository) MahasiswaService { 23 | return MahasiswaService{ 24 | MahasiswaRepository: m, 25 | } 26 | } 27 | 28 | // implementation 29 | func (m *MahasiswaService) SaveOrUpdate(dto dto.MahasiswaDTO) (dto.MahasiswaDTO, error) { 30 | 31 | mahasiswaEntity := mapper.ToMahasiswaDomain(dto) 32 | 33 | mahasiswa, err := m.MahasiswaRepository.SaveOrUpdate(mahasiswaEntity) 34 | 35 | return mapper.ToMahasiswaDto(mahasiswa), err 36 | } 37 | 38 | func (m *MahasiswaService) FindAll() [] dto.MahasiswaDTO { 39 | 40 | datas := m.MahasiswaRepository.FindAll() 41 | 42 | return mapper.ToMahasiswaDtoList(datas) 43 | } 44 | 45 | func (m *MahasiswaService) FindByNim(nim string) dto.MahasiswaDTO { 46 | mahasiswa := m.MahasiswaRepository.FindByNim(nim) 47 | 48 | return mapper.ToMahasiswaDto(mahasiswa) 49 | } 50 | 51 | func (m *MahasiswaService) DeleteMahasiswa(id string) error { 52 | 53 | mahasiswa := m.MahasiswaRepository.FindByID(id) 54 | 55 | if(mahasiswa == (domain.Mahasiswa{})) { 56 | return errors.New("Mahasiswa Tidak ada") 57 | } 58 | 59 | err := m.MahasiswaRepository.DeleteMahasiswa(mahasiswa) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | return nil 65 | } --------------------------------------------------------------------------------