Refactor and rename storage to Json

This commit is contained in:
2023-02-08 18:33:44 +00:00
parent 6aebdc8b5e
commit 38a200c648
5 changed files with 90 additions and 66 deletions

View File

@@ -15,15 +15,13 @@ import (
// main is the entry point of the application // main is the entry point of the application
func main() { func main() {
var ( var (
dataPath = "data/heros.json" // store to JSON file dataPath = "data/heros.json" // Path to read superheros from JSON file
port = 8080 // Port to serve port = 8080 // Port to serve
key = 5 // DeeSee encryption key key = 5 // Json encryption key
err error logger = log.Default() // Logger
err error // Error
) )
// Create logger
logger := log.Default()
// Get port from environment variable // Get port from environment variable
if os.Getenv("PORT") != "" { if os.Getenv("PORT") != "" {
port, err = strconv.Atoi(os.Getenv("PORT")) port, err = strconv.Atoi(os.Getenv("PORT"))
@@ -54,8 +52,8 @@ func main() {
logger.Fatalf("Invalid data path: %s", dataPath) logger.Fatalf("Invalid data path: %s", dataPath)
} }
// Create DeeSee storage // Create Json storage
s, err := storage.New(dataPath) s, err := storage.NewJson(dataPath)
if err != nil { if err != nil {
logger.Fatalf("Invalid data format: %s", dataPath) logger.Fatalf("Invalid data format: %s", dataPath)
} }

View File

@@ -3,7 +3,6 @@ package router
import ( import (
"encoding/json" "encoding/json"
"github.com/eslider/superherohub/pkg/deesee" "github.com/eslider/superherohub/pkg/deesee"
"github.com/eslider/superherohub/pkg/deesee/storage"
"log" "log"
"net/http" "net/http"
"strings" "strings"
@@ -13,10 +12,18 @@ import (
// Router is a custom router that encapsulates the mux.Router // Router is a custom router that encapsulates the mux.Router
type Router struct { type Router struct {
store *storage.DeeSee // The store where superheroes are stored store Storage // The store where superheroes are stored
router *mux.Router // Encapsulated mux router router *mux.Router // Encapsulated mux router
logger *log.Logger // The logger to use for this router logger *log.Logger // The logger to use for this router
key int // The key to use for DeeSee encryption key int // The key to use for DeeSee encryption
}
type Storage interface {
// List of superheroes
List() []*deesee.Superhero
// Put stores a superhero in the store.
Put(*deesee.Superhero) error
} }
// New creates a new encapsulated router. // New creates a new encapsulated router.
@@ -30,14 +37,14 @@ type Router struct {
// require different resources and development progresses. // require different resources and development progresses.
// //
// And handlers shouldn't have prefix like "handle", course they are methods of the Router // And handlers shouldn't have prefix like "handle", course they are methods of the Router
func New(heros *storage.DeeSee, key int, logger *log.Logger) *Router { func New(store Storage, key int, logger *log.Logger) *Router {
// Set the logger // Set the logger
if logger == nil { if logger == nil {
logger = log.Default() logger = log.Default()
} }
r := &Router{ r := &Router{
store: heros, store: store,
key: key, key: key,
logger: logger, logger: logger,
router: mux.NewRouter(), router: mux.NewRouter(),
@@ -90,7 +97,7 @@ func (r *Router) GetHandler() http.Handler {
func (r *Router) GetSuperHeroes(w http.ResponseWriter, req *http.Request) { func (r *Router) GetSuperHeroes(w http.ResponseWriter, req *http.Request) {
var ( var (
// Resulting // Resulting
heroes = *r.store heroes = r.store.List()
// Get query parameter values // Get query parameter values
params = req.URL.Query() params = req.URL.Query()
err error err error
@@ -134,8 +141,8 @@ func (r *Router) StoreSuperHero(w http.ResponseWriter, req *http.Request) {
return return
} }
// Store superhero // Put superhero
if err = r.store.Store(hero); err != nil { if err = r.store.Put(hero); err != nil {
http.Error(w, err.Error(), http.StatusConflict) http.Error(w, err.Error(), http.StatusConflict)
return return
} }

View File

@@ -20,7 +20,7 @@ func TestWebserviceGetSuperHeros(t *testing.T) {
} }
// Load heros // Load heros
heros, err := storage.New(path + "/data/heros.json") heros, err := storage.NewJson(path + "/data/heros.json")
if err != nil { if err != nil {
t.Fatalf("Error loading heros: %heros", err) t.Fatalf("Error loading heros: %heros", err)
@@ -128,7 +128,7 @@ func TestWebserviceStoreSuperhero(t *testing.T) {
} }
// Load heros // Load heros
heros, err := storage.New(path + "/data/heros.json") heros, err := storage.NewJson(path + "/data/heros.json")
if err != nil { if err != nil {
t.Fatalf("Error loading heros: %heros", err) t.Fatalf("Error loading heros: %heros", err)

View File

@@ -0,0 +1,65 @@
package storage
import (
"encoding/json"
"errors"
"fmt"
"github.com/eslider/superherohub/pkg/deesee"
"os"
"strings"
)
// Json simple JSON memory storage.
type Json struct {
path string // Path to json file
list []*deesee.Superhero // List of loaded superheroes
}
// NewJson Json storage.
func NewJson(path string) (d *Json, err error) {
d = &Json{
path: path,
}
err = d.Load(path)
return
}
// Load superheroes from JSON file.
func (s *Json) Load(path string) error {
f, err := os.OpenFile(path, os.O_RDONLY, 0644)
if err != nil {
return fmt.Errorf("unable to read f: %w", err)
}
return json.NewDecoder(f).Decode(&s.list)
}
// List superheros
func (s *Json) List() []*deesee.Superhero {
return s.list
}
// Put superhero.
func (s *Json) Put(hero *deesee.Superhero) (err error) {
// Check if superhero superpower is acceptable
if !hero.IsAcceptable() {
return errors.New(fmt.Sprintf("Hero power is not acceptable: %s", hero.Name))
}
// Prevent to store duplicate superheroes
if deesee.FindByName(s.list, strings.TrimSpace(hero.Name)) != nil {
return errors.New(fmt.Sprintf("Hero already exists: %s", hero.Name))
}
s.list = append(s.list, hero)
return
}
// Persist superheroes to JSON file.
func (s *Json) Persist() error {
f, err := os.OpenFile(s.path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return fmt.Errorf("unable to write file: %w", err)
}
return json.NewEncoder(f).Encode(s.list)
}

View File

@@ -1,46 +0,0 @@
package storage
import (
"encoding/json"
"errors"
"fmt"
"github.com/eslider/superherohub/pkg/deesee"
"os"
"strings"
)
type DeeSee []*deesee.Superhero
// New DeeSee storage.
func New(path string) (d *DeeSee, err error) {
d = &DeeSee{}
err = d.Load(path)
return
}
// Load superheroes from json file
func (s *DeeSee) Load(path string) (err error) {
// Read and unmarshal s from json f path
f, err := os.OpenFile(path, os.O_RDONLY, 0644)
if err != nil {
return fmt.Errorf("unable to read f: %w", err)
}
return json.NewDecoder(f).Decode(s)
}
// Store superhero
func (s *DeeSee) Store(hero *deesee.Superhero) (err error) {
// Check if superhero superpower is acceptable
if !hero.IsAcceptable() {
return errors.New(fmt.Sprintf("Hero power is not acceptable: %s", hero.Name))
}
// Prevent to store duplicate superheroes
if deesee.FindByName(*s, strings.TrimSpace(hero.Name)) != nil {
return errors.New(fmt.Sprintf("Hero already exists: %s", hero.Name))
}
*s = append(*s, hero)
return
}