Refactor and rename storage to Json
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
65
pkg/deesee/storage/json.go
Normal file
65
pkg/deesee/storage/json.go
Normal 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)
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user