Error when loading books: {{ error.message }}
-
-
+
diff --git a/front/src/api.js b/front/src/api.js
new file mode 100644
index 0000000..ecb5bb8
--- /dev/null
+++ b/front/src/api.js
@@ -0,0 +1,29 @@
+import { ref } from 'vue'
+
+const baseUrl = "http://localhost:8080"
+
+function useFetch(url) {
+ const data = ref(null)
+ const error = ref(null)
+
+ fetch(url)
+ .then((res) => res.json())
+ .then((json) => (data.value = json))
+ .catch((err) => (error.value = err))
+
+ return { data, error }
+}
+
+export function getBooks() {
+ return useFetch(baseUrl + '/books');
+}
+
+export function postBook(book) {
+ fetch(baseUrl + '/book', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(book.value)
+ });
+}
diff --git a/front/src/fetch.js b/front/src/fetch.js
deleted file mode 100644
index 1f8c22d..0000000
--- a/front/src/fetch.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { ref } from 'vue'
-
-export function useFetch(url) {
- const data = ref(null)
- const error = ref(null)
-
- fetch(url)
- .then((res) => res.json())
- .then((json) => (data.value = json))
- .catch((err) => (error.value = err))
-
- return { data, error }
-}
diff --git a/front/src/main.js b/front/src/main.js
index 01433bc..f71efad 100644
--- a/front/src/main.js
+++ b/front/src/main.js
@@ -1,4 +1,18 @@
import { createApp } from 'vue'
+import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
+import BooksBrowser from './BooksBrowser.vue'
+import AddBook from './AddBook.vue'
-createApp(App).mount('#app')
+
+const routes = [
+ { path: '/', component: BooksBrowser },
+ { path: '/add', component: AddBook },
+]
+
+export const router = createRouter({
+ history: createWebHistory(),
+ routes,
+})
+
+createApp(App).use(router).mount('#app')
diff --git a/go.mod b/go.mod
index b33d56d..cd44c45 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,7 @@ require (
github.com/gin-contrib/cors v1.7.6
github.com/gin-gonic/gin v1.10.1
github.com/pelletier/go-toml v1.9.5
+ github.com/stretchr/testify v1.10.0
gorm.io/driver/sqlite v1.6.0
gorm.io/gorm v1.31.0
)
@@ -15,6 +16,7 @@ require (
github.com/bytedance/sonic v1.14.1 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
@@ -32,6 +34,7 @@ require (
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.2.4 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.0 // indirect
golang.org/x/arch v0.21.0 // indirect
diff --git a/internal/api/dto.go b/internal/api/dto.go
new file mode 100644
index 0000000..dbb0a56
--- /dev/null
+++ b/internal/api/dto.go
@@ -0,0 +1,7 @@
+package api
+
+type bookPostCreate struct {
+ Title string `json:"title" binding:"required"`
+ Author string `json:"author"`
+ Rating int `json:"rating" binding:"min=0,max=10"`
+}
diff --git a/internal/api/mapper.go b/internal/api/mapper.go
new file mode 100644
index 0000000..fbec2a6
--- /dev/null
+++ b/internal/api/mapper.go
@@ -0,0 +1,9 @@
+package api
+
+import "git.artlef.fr/PersonalLibraryManager/internal/model"
+
+func (b bookPostCreate) toBook() model.Book {
+ return model.Book{Title: b.Title,
+ Author: b.Author,
+ Rating: b.Rating}
+}
diff --git a/internal/api/routes.go b/internal/api/routes.go
new file mode 100644
index 0000000..ed17d2a
--- /dev/null
+++ b/internal/api/routes.go
@@ -0,0 +1,27 @@
+package api
+
+import (
+ "net/http"
+
+ "git.artlef.fr/PersonalLibraryManager/internal/model"
+ "github.com/gin-gonic/gin"
+ "gorm.io/gorm"
+)
+
+func GetBooksHanderl(c *gin.Context, db *gorm.DB) {
+ var books []model.Book
+ db.Model(&model.Book{}).Find(&books)
+ c.JSON(http.StatusOK, books)
+}
+
+func PostBookHandler(c *gin.Context, db *gorm.DB) {
+ var book bookPostCreate
+ err := c.ShouldBindJSON(&book)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+ bookDb := book.toBook()
+ db.Model(&model.Book{}).Save(&bookDb)
+ c.String(200, "Success")
+}
diff --git a/internal/config/config.go b/internal/config/config.go
index a4169db..c308ae2 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -9,16 +9,15 @@ import (
)
type Config struct {
- Port string `toml:"port" comment:"The port to listen on for the server."`
- DemoDataPath string `toml:"demo_data_path" comment:"The path to the sql file to load for demo data."`
-
+ Port string `toml:"port" comment:"The port to listen on for the server."`
+ DatabaseFilePath string `toml:"database_file_path" comment:"Path to sqlite database file."`
+ DemoDataPath string `toml:"demo_data_path" comment:"The path to the sql file to load for demo data."`
}
func defaultConfig() Config {
- return Config{Port: "8080", DemoDataPath: ""}
+ return Config{Port: "8080", DatabaseFilePath: "plm.db", DemoDataPath: ""}
}
-
func LoadConfig(configPath string) Config {
f, err := os.ReadFile(configPath)
if err != nil {
diff --git a/internal/db/init.go b/internal/db/init.go
index aad7904..70bee6d 100644
--- a/internal/db/init.go
+++ b/internal/db/init.go
@@ -1,7 +1,6 @@
package db
import (
- "fmt"
"log"
"os"
@@ -11,12 +10,10 @@ import (
"git.artlef.fr/PersonalLibraryManager/internal/model"
)
-func Initdb(databaseDir string, demoDataPath string) *gorm.DB {
- createDbFolderIfMissing(databaseDir)
+func Initdb(databasePath string, demoDataPath string) *gorm.DB {
db, err := gorm.Open(
sqlite.Open(
- fmt.Sprintf(
- "%s/plm.db", databaseDir)), &gorm.Config{})
+ databasePath), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
@@ -38,20 +35,3 @@ func migrateSchema(db *gorm.DB, demoDataPath string) {
}
db.Exec(string(data))
}
-
-func createDbFolderIfMissing(databaseDir string) {
- _, openFileErr := os.Open(databaseDir)
- if os.IsNotExist(openFileErr) {
- createNonExistingDbFolder(databaseDir)
- } else if openFileErr != nil {
- log.Fatal(openFileErr)
- }
-}
-
-func createNonExistingDbFolder(databaseDir string) {
- log.Printf("Creating missing folder %s\n", databaseDir)
- err := os.MkdirAll(databaseDir, 0700)
- if err != nil {
- log.Fatal(err)
- }
-}
diff --git a/main.go b/main.go
index 98a4f92..bb09d61 100644
--- a/main.go
+++ b/main.go
@@ -1,30 +1,29 @@
package main
import (
- "net/http"
-
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
- "gorm.io/gorm"
+ "git.artlef.fr/PersonalLibraryManager/internal/api"
"git.artlef.fr/PersonalLibraryManager/internal/config"
"git.artlef.fr/PersonalLibraryManager/internal/db"
- "git.artlef.fr/PersonalLibraryManager/internal/model"
)
-func GetBookHandler(c *gin.Context, db *gorm.DB) {
- var books []model.Book
- db.Model(&model.Book{}).Find(&books)
- c.JSON(http.StatusOK, books)
-}
-
func main() {
c := config.LoadConfig("plm.toml")
- db := db.Initdb(".", c.DemoDataPath)
- r := gin.Default()
- r.Use(cors.Default()) // All origins allowed by default
- r.GET("/books", func(c *gin.Context) {
- GetBookHandler(c, db)
- })
+ r := setup(&c)
r.Run(":" + c.Port)
}
+
+func setup(config *config.Config) *gin.Engine {
+ db := db.Initdb(config.DatabaseFilePath, config.DemoDataPath)
+ r := gin.Default()
+ r.Use(cors.Default()) // All origins allowed by default
+ r.GET("/books", func(c *gin.Context) {
+ api.GetBooksHanderl(c, db)
+ })
+ r.POST("/book", func(c *gin.Context) {
+ api.PostBookHandler(c, db)
+ })
+ return r
+}