adding rest-api
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.DS_Store
|
||||||
1
README.md
Normal file
1
README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
A companion repo for the Udemy course ("Go - The Complete Guide")[https://www.udemy.com/share/109Zxy3@5weOyI1zPY1wYhrd-_RWBlbsz-IdPECfz9MAMP-VcJdAKgcTfeJsDhVTi6kQt6_PDQ==/] by Maximilian Schwarzmüller.
|
||||||
9
rest-api/api-test/create-event.http
Normal file
9
rest-api/api-test/create-event.http
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
POST http://localhost:8080/events
|
||||||
|
content-type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Test event",
|
||||||
|
"description": "A test event",
|
||||||
|
"location": "A test location",
|
||||||
|
"dateTime": "2025-01-01T15:30:00.000Z"
|
||||||
|
}
|
||||||
7
rest-api/api-test/create-user.http
Normal file
7
rest-api/api-test/create-user.http
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
POST http://localhost:8080/signup
|
||||||
|
content-type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"email": "test@example.com",
|
||||||
|
"password": "test"
|
||||||
|
}
|
||||||
1
rest-api/api-test/delete-event.http
Normal file
1
rest-api/api-test/delete-event.http
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DELETE http://localhost:8080/events/1
|
||||||
1
rest-api/api-test/get-events.http
Normal file
1
rest-api/api-test/get-events.http
Normal file
@@ -0,0 +1 @@
|
|||||||
|
GET http://localhost:8080/events
|
||||||
1
rest-api/api-test/get-single-event.http
Normal file
1
rest-api/api-test/get-single-event.http
Normal file
@@ -0,0 +1 @@
|
|||||||
|
GET http://localhost:8080/events/1
|
||||||
9
rest-api/api-test/update-event.http
Normal file
9
rest-api/api-test/update-event.http
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
PUT http://localhost:8080/events/1
|
||||||
|
content-type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Updated test event",
|
||||||
|
"description": "A test event",
|
||||||
|
"location": "Test location (updated)",
|
||||||
|
"dateTime": "2025-01-01T15:30:00.000Z"
|
||||||
|
}
|
||||||
BIN
rest-api/api.db
Normal file
BIN
rest-api/api.db
Normal file
Binary file not shown.
57
rest-api/db/db.go
Normal file
57
rest-api/db/db.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DB *sql.DB
|
||||||
|
|
||||||
|
func InitDB() {
|
||||||
|
var err error
|
||||||
|
DB, err = sql.Open("sqlite3", "api.db")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic("Could not connect to database")
|
||||||
|
}
|
||||||
|
|
||||||
|
DB.SetMaxOpenConns(10)
|
||||||
|
DB.SetMaxIdleConns(5)
|
||||||
|
|
||||||
|
createTables()
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTables() {
|
||||||
|
createUsersTable := `
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
email TEXT NOT NULL UNIQUE,
|
||||||
|
password TEXT NOT NULL
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err := DB.Exec(createUsersTable)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic("Could not create users table.")
|
||||||
|
}
|
||||||
|
|
||||||
|
createEventsTable := `
|
||||||
|
CREATE TABLE IF NOT EXISTS events (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT NOT NULL,
|
||||||
|
location TEXT NOT NULL,
|
||||||
|
dateTime DATETIME NOT NULL,
|
||||||
|
user_id INTEGER,
|
||||||
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err = DB.Exec(createEventsTable)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic("Could not create table")
|
||||||
|
}
|
||||||
|
}
|
||||||
37
rest-api/go.mod
Normal file
37
rest-api/go.mod
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
module example.com/rest-api
|
||||||
|
|
||||||
|
go 1.25.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bytedance/gopkg v0.1.4 // indirect
|
||||||
|
github.com/bytedance/sonic v1.15.2 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.5.1 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.7 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
|
||||||
|
github.com/gin-contrib/sse v1.1.1 // indirect
|
||||||
|
github.com/gin-gonic/gin v1.12.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.30.3 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.6 // indirect
|
||||||
|
github.com/goccy/go-yaml v1.19.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.4.0 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.47 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.4.2 // indirect
|
||||||
|
github.com/quic-go/qpack v0.6.0 // indirect
|
||||||
|
github.com/quic-go/quic-go v0.60.0 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||||
|
go.mongodb.org/mongo-driver/v2 v2.7.0 // indirect
|
||||||
|
golang.org/x/arch v0.28.0 // indirect
|
||||||
|
golang.org/x/crypto v0.53.0 // indirect
|
||||||
|
golang.org/x/net v0.56.0 // indirect
|
||||||
|
golang.org/x/sys v0.46.0 // indirect
|
||||||
|
golang.org/x/text v0.38.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
|
)
|
||||||
79
rest-api/go.sum
Normal file
79
rest-api/go.sum
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM=
|
||||||
|
github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4=
|
||||||
|
github.com/bytedance/sonic v1.15.2 h1:90H+rcF/FwLXwfB1cudOLq/je83n683Utf4Cbp0xHCo=
|
||||||
|
github.com/bytedance/sonic v1.15.2/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA=
|
||||||
|
github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI=
|
||||||
|
github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||||
|
github.com/cloudwego/base64x v0.1.7 h1:NppS+Fgzg5ovhn4NkUXaDT3x9jldgH5ToMCqzBSi2zI=
|
||||||
|
github.com/cloudwego/base64x v0.1.7/go.mod h1:Cu1PV9zfrSf7ET2tIbWbbEy7jO7HHJ13q4X2SQ8aWYg=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
|
github.com/gin-contrib/sse v1.1.1 h1:uGYpNwTacv5R68bSGMapo62iLTRa9l5zxGCps4hK6ko=
|
||||||
|
github.com/gin-contrib/sse v1.1.1/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s=
|
||||||
|
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
|
||||||
|
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.30.3 h1:4MU6YkEwx7GbcPJOZxrtbu+QfF3pJLJuaYTeAH0DYy8=
|
||||||
|
github.com/go-playground/validator/v10 v10.30.3/go.mod h1:4Axh7oCNGcoGkqLoE4YWt6n20mcEIsPRlB7vPk3lpyc=
|
||||||
|
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
|
||||||
|
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||||
|
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||||
|
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.47 h1:jOBI62gS7nKeZv+as1oGEy0+1qISgXwH/QBlR6KbfIo=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.47/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
|
||||||
|
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=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.4.2 h1:M2fKKbmyvI+hGId/D0W64qDBMVhJnNR10O5gIbMc//Q=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.4.2/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||||
|
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||||
|
github.com/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0=
|
||||||
|
github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
|
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
||||||
|
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||||
|
go.mongodb.org/mongo-driver/v2 v2.7.0 h1:RO+zqavD2/GCL3cxOMyZhx6R9Irzr8/6gsoqx5tcY/c=
|
||||||
|
go.mongodb.org/mongo-driver/v2 v2.7.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||||
|
golang.org/x/arch v0.28.0 h1:wVwVdqsTuUbJvhYVCspQYwZXHNYeLSoZnmHD+ggddpQ=
|
||||||
|
golang.org/x/arch v0.28.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
|
||||||
|
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||||
|
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||||
|
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||||
|
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||||
|
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||||
|
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||||
|
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
16
rest-api/main.go
Normal file
16
rest-api/main.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"example.com/rest-api/db"
|
||||||
|
"example.com/rest-api/routes"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
db.InitDB()
|
||||||
|
server := gin.Default()
|
||||||
|
|
||||||
|
routes.RegisterRoutes(server)
|
||||||
|
|
||||||
|
server.Run(":8080")
|
||||||
|
}
|
||||||
0
rest-api/main.txt
Normal file
0
rest-api/main.txt
Normal file
107
rest-api/models/event.go
Normal file
107
rest-api/models/event.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"example.com/rest-api/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
ID int64
|
||||||
|
Name string `binding:"required"`
|
||||||
|
Description string `binding:"required"`
|
||||||
|
Location string `binding:"required"`
|
||||||
|
DateTime time.Time `binding:"required"`
|
||||||
|
UserID int
|
||||||
|
}
|
||||||
|
|
||||||
|
var events []Event = []Event{}
|
||||||
|
|
||||||
|
func (e Event) Save() error {
|
||||||
|
query := `
|
||||||
|
INSERT INTO events(name, description, location, dateTime, user_id)
|
||||||
|
VALUES (?, ?, ?, ?, ?)`
|
||||||
|
stmt, err := db.DB.Prepare(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// defer stmt.Close()
|
||||||
|
result, err := stmt.Exec(e.Name, e.Description, e.Location, e.DateTime, e.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id, err := result.LastInsertId()
|
||||||
|
e.ID = id
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllEvents() ([]Event, error) {
|
||||||
|
query := "SELECT * FROM events"
|
||||||
|
rows, err := db.DB.Query(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var events []Event
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var event Event
|
||||||
|
err := rows.Scan(&event.ID, &event.Name, &event.Description, &event.Location, &event.DateTime, &event.UserID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
events = append(events, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
return events, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetEventByID(id int64) (*Event, error) {
|
||||||
|
query := "SELECT * FROM events WHERE id = ?"
|
||||||
|
row := db.DB.QueryRow(query, id)
|
||||||
|
|
||||||
|
var event Event
|
||||||
|
err := row.Scan(&event.ID, &event.Name, &event.Description, &event.Location, &event.DateTime, &event.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (event Event) Update() error {
|
||||||
|
query := `
|
||||||
|
UPDATE events
|
||||||
|
SET name = ?, description = ?, location = ?, dateTime = ?
|
||||||
|
WHERE id = ?
|
||||||
|
`
|
||||||
|
stmt, err := db.DB.Prepare(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
_, err = stmt.Exec(event.Name, event.Description, event.Location, event.DateTime, event.UserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (event Event) Delete() error {
|
||||||
|
query := "DELETE FROM events WHERE id = ?"
|
||||||
|
stmt, err := db.DB.Prepare(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
_, err = stmt.Exec(event.ID)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
40
rest-api/models/user.go
Normal file
40
rest-api/models/user.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"example.com/rest-api/db"
|
||||||
|
"example.com/rest-api/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int64
|
||||||
|
Email string `binding:"required"`
|
||||||
|
Password string `binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u User) Save() error {
|
||||||
|
query := "INSERT INTO users(email, password) VALUES (?, ?)"
|
||||||
|
stmt, err := db.DB.Prepare(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
hashedPassword, err := utils.HashPassword(u.Password)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := stmt.Exec(u.Email, hashedPassword)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userId, err := result.LastInsertId()
|
||||||
|
|
||||||
|
u.ID = userId
|
||||||
|
return err
|
||||||
|
}
|
||||||
110
rest-api/routes/events.go
Normal file
110
rest-api/routes/events.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"example.com/rest-api/models"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getEvents(context *gin.Context) {
|
||||||
|
events, err := models.GetAllEvents()
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusInternalServerError, gin.H{"message": "Could not fetch events."})
|
||||||
|
}
|
||||||
|
context.JSON(http.StatusOK, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEvent(context *gin.Context) {
|
||||||
|
eventId, err := strconv.ParseInt(context.Param("id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusBadRequest, gin.H{"message": "Could not parse event id."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event, err := models.GetEventByID(eventId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusInternalServerError, gin.H{"message": "Could not fetch event."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
context.JSON(http.StatusOK, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createEvent(context *gin.Context) {
|
||||||
|
var event models.Event
|
||||||
|
err := context.ShouldBindJSON(&event)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusBadRequest, gin.H{"message": "Could not parse request data"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event.ID = 1
|
||||||
|
event.UserID = 1
|
||||||
|
|
||||||
|
err = event.Save()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusInternalServerError, gin.H{"message": "Could not create event."})
|
||||||
|
}
|
||||||
|
|
||||||
|
context.JSON(http.StatusCreated, gin.H{"message": "Event created!", "event": event})
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateEvent(context *gin.Context) {
|
||||||
|
eventId, err := strconv.ParseInt(context.Param("id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusBadRequest, gin.H{"message": "Could not parse event id."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = models.GetEventByID(eventId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusInternalServerError, gin.H{"message": "Could not fetch the event."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var updatedEvent models.Event
|
||||||
|
err = context.ShouldBindJSON(&updatedEvent)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusBadRequest, gin.H{"message": "Could not parse request data"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedEvent.ID = eventId
|
||||||
|
err = updatedEvent.Update()
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusInternalServerError, gin.H{"message": "Could not update the event."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.JSON(http.StatusOK, gin.H{"message": "Event updated successfully."})
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteEvent(context *gin.Context) {
|
||||||
|
eventId, err := strconv.ParseInt(context.Param("id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusBadRequest, gin.H{"message": "Could not parse event id."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event, err := models.GetEventByID(eventId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusInternalServerError, gin.H{"message": "Could not fetch the event."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = event.Delete()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusInternalServerError, gin.H{"message": "Could not delete the event."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
context.JSON(http.StatusOK, gin.H{"message": "Event deleted successfully."})
|
||||||
|
}
|
||||||
12
rest-api/routes/routes.go
Normal file
12
rest-api/routes/routes.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
func RegisterRoutes(server *gin.Engine) {
|
||||||
|
server.GET("/events", getEvents)
|
||||||
|
server.GET("/events/:id", getEvent)
|
||||||
|
server.POST("/events", createEvent)
|
||||||
|
server.PUT("/events/:id", updateEvent)
|
||||||
|
server.DELETE("/events/:id", deleteEvent)
|
||||||
|
server.POST("/signup", signup)
|
||||||
|
}
|
||||||
28
rest-api/routes/users.go
Normal file
28
rest-api/routes/users.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"example.com/rest-api/models"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func signup(context *gin.Context) {
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
err := context.ShouldBindJSON(&user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusBadRequest, gin.H{"message": "Could not parse request data."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = user.Save()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
context.JSON(http.StatusInternalServerError, gin.H{"message": "Could not save user."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
context.JSON(http.StatusCreated, gin.H{"message": "User created successfully"})
|
||||||
|
}
|
||||||
8
rest-api/utils/hash.go
Normal file
8
rest-api/utils/hash.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import "golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
func HashPassword(password string) (string, error) {
|
||||||
|
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
||||||
|
return string(bytes), err
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user