Unbewohnte
4 years ago
committed by
GitHub
3 changed files with 396 additions and 0 deletions
@ -0,0 +1,6 @@
|
||||
curl localhost:8000/randomdata |
||||
curl localhost:8000/randomdata -H "content-type:application/json" -d '{"title":"This is a title","text":"This is a text"}' -X POST |
||||
curl localhost:8000/randomdata/1618064651615612586 -H "content-type:application/json" -d {"title":"This is an updated title","text":"This is an updated text"}' -X PUT |
||||
curl localhost:8000/randomdata/1618065099475731301 |
||||
curl localhost:8000/randomdata/1618065099475731301 -X DELETE |
||||
|
@ -0,0 +1,23 @@
|
||||
[ |
||||
{ |
||||
"ID": 1618064636424100339, |
||||
"DateCreated": "2021-04-10T14:23:56.424100065Z", |
||||
"LastUpdated": "2021-04-10T14:23:56.424100065Z", |
||||
"title": "FUMO?", |
||||
"text": "FUMO" |
||||
}, |
||||
{ |
||||
"ID": 1618064651615612586, |
||||
"DateCreated": "2021-04-10T14:24:11.615612068Z", |
||||
"LastUpdated": "2021-04-10T14:24:11.615612068Z", |
||||
"title": "Title", |
||||
"text": "text" |
||||
}, |
||||
{ |
||||
"ID": 1618065099475731301, |
||||
"DateCreated": "2021-04-10T14:31:39.47573104Z", |
||||
"LastUpdated": "2021-04-10T14:31:39.47573104Z", |
||||
"title": "link", |
||||
"text": "https://youtu.be/dQw4w9WgXcQ" |
||||
} |
||||
] |
@ -0,0 +1,367 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"io" |
||||
"log" |
||||
"net/http" |
||||
"os" |
||||
"path/filepath" |
||||
"strconv" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
type RandomData struct { |
||||
// unexported for json
|
||||
ID int64 |
||||
DateCreated time.Time |
||||
LastUpdated time.Time |
||||
// exported for json
|
||||
Title string `json:"title"` |
||||
Text string `json:"text"` |
||||
} |
||||
|
||||
type randomDataHandler struct { |
||||
dbFilepath string |
||||
} |
||||
|
||||
func InitLogs() { |
||||
var logsDir string = filepath.Join(".", "logs") |
||||
|
||||
err := os.MkdirAll(logsDir, os.ModePerm) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
logfile, err := os.Create(filepath.Join(logsDir, "logs.log")) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
log.SetOutput(logfile) |
||||
} |
||||
|
||||
func homepage(w http.ResponseWriter, r *http.Request) { |
||||
helpMessage := ` |
||||
<h1>REST api in Go's standart library</h1> |
||||
<ul> |
||||
<li> (GET) <a href="/randomdata">/randomdata</a> - to get all database </li> |
||||
<li> (GET) /randomdata/{id} - to get specific random data under corresponding id </li> |
||||
<li> (POST) /randomdata - to create random data</li> |
||||
<li> (DELETE) /randomdata/{id} - to delete specified random data </li> |
||||
<li> (PUT) /randomdata/{id} - to update random data with given id </li> |
||||
</ul> |
||||
` |
||||
fmt.Fprint(w, helpMessage) |
||||
} |
||||
|
||||
func newDatabaseHandler() *randomDataHandler { |
||||
dbDirpath := filepath.Join(".", "database") |
||||
err := os.MkdirAll(dbDirpath, os.ModePerm) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
dbFilepath := filepath.Join(dbDirpath, "database.json") |
||||
|
||||
dbFile, err := os.OpenFile(dbFilepath, os.O_CREATE, os.ModePerm) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
defer dbFile.Close() |
||||
|
||||
log.Println("Successfully created new database handler") |
||||
|
||||
return &randomDataHandler{ |
||||
dbFilepath: dbFilepath, |
||||
} |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) writeRandomData(newData RandomData) error { |
||||
dbBytes, err := dbHandler.readDatabase() |
||||
if err != nil { |
||||
log.Println("Error reading db (writeRandomData) : ", err) |
||||
} |
||||
|
||||
var db []RandomData |
||||
|
||||
err = json.Unmarshal(dbBytes, &db) |
||||
if err != nil { |
||||
log.Println("Error unmarshalling db (writeRandomData) : ", err) |
||||
} |
||||
|
||||
db = append(db, newData) |
||||
|
||||
dbFile, err := os.OpenFile(dbHandler.dbFilepath, os.O_WRONLY, 0644) |
||||
if err != nil { |
||||
log.Println("Error opening db file (writeRandomData) : ", err) |
||||
} |
||||
defer dbFile.Close() |
||||
|
||||
jsonBytes, err := json.MarshalIndent(db, "", " ") |
||||
if err != nil { |
||||
log.Println("Error marshalling db (writeRandomData) : ", err) |
||||
} |
||||
|
||||
dbFile.Write(jsonBytes) |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) readDatabase() ([]byte, error) { |
||||
dbBytes, err := os.ReadFile(dbHandler.dbFilepath) |
||||
if err != nil { |
||||
log.Println("Error reading db (readDatabase) : ", err) |
||||
return nil, err |
||||
} |
||||
return dbBytes, nil |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) removeRandomData(id int64) error { |
||||
dbBytes, err := dbHandler.readDatabase() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
var db []RandomData |
||||
err = json.Unmarshal(dbBytes, &db) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
var counter int64 = 0 |
||||
for _, randomData := range db { |
||||
if id == randomData.ID { |
||||
db = append(db[:counter], db[counter+1:]...) |
||||
err = dbHandler.writeDB(db) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
counter++ |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) writeDB(db []RandomData) error { |
||||
jsonEncodedDB, err := json.MarshalIndent(db, "", " ") |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
dbFile, err := os.OpenFile(dbHandler.dbFilepath, os.O_WRONLY|os.O_TRUNC, 0644) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer dbFile.Close() |
||||
|
||||
dbFile.Write(jsonEncodedDB) |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) get(w http.ResponseWriter, r *http.Request) { |
||||
dbBytes, err := dbHandler.readDatabase() |
||||
if err != nil { |
||||
log.Println("Error reading db (get) : ", err) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
w.Write(dbBytes) |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) create(w http.ResponseWriter, r *http.Request) { |
||||
if r.Header.Get("content-type") != "application/json" { |
||||
w.WriteHeader(http.StatusUnsupportedMediaType) |
||||
w.Write([]byte(fmt.Sprintf("Got `%s` instead of `application/json`", r.Header.Get("content-type")))) |
||||
return |
||||
} |
||||
requestBody, err := io.ReadAll(r.Body) |
||||
if err != nil { |
||||
log.Println("Error reading http request (create) : ", err) |
||||
w.WriteHeader(http.StatusBadRequest) |
||||
return |
||||
} |
||||
defer r.Body.Close() |
||||
|
||||
var newRandomData RandomData |
||||
err = json.Unmarshal(requestBody, &newRandomData) |
||||
if err != nil { |
||||
log.Printf("Error unmarshalling http request (create) : %q \n", err) |
||||
w.WriteHeader(http.StatusBadRequest) |
||||
return |
||||
} |
||||
|
||||
newRandomData.DateCreated = time.Now().UTC() |
||||
newRandomData.LastUpdated = newRandomData.DateCreated |
||||
newRandomData.ID = time.Now().UTC().UnixNano() |
||||
|
||||
err = dbHandler.writeRandomData(newRandomData) |
||||
if err != nil { |
||||
log.Println("Error writing RandomData (create): ", err) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
w.WriteHeader(http.StatusOK) |
||||
|
||||
log.Println("Successfuly added to db : ", newRandomData) |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) getSpecificRandomData(w http.ResponseWriter, r *http.Request) { |
||||
givenID := strings.Split(r.URL.String(), "/")[2] |
||||
|
||||
dbBytes, err := dbHandler.readDatabase() |
||||
if err != nil { |
||||
log.Println("Error reading db (getSpecificRandomData) : ", err) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
var db []RandomData |
||||
|
||||
err = json.Unmarshal(dbBytes, &db) |
||||
if err != nil { |
||||
log.Println("Error unmarshalling database (getSpecificRandomData) : ", err) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
int64GivenID, _ := strconv.ParseInt(givenID, 10, 64) |
||||
for _, randomData := range db { |
||||
if int64GivenID == randomData.ID { |
||||
response, err := json.MarshalIndent(randomData, "", " ") |
||||
if err != nil { |
||||
log.Println("Error marshaling response(getSpecificRandomData) : ", err) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
w.Write(response) |
||||
return |
||||
} |
||||
} |
||||
w.WriteHeader(http.StatusNotFound) |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) updateSpecificRandomData(w http.ResponseWriter, r *http.Request) { |
||||
if r.Header.Get("content-type") != "application/json" { |
||||
w.WriteHeader(http.StatusUnsupportedMediaType) |
||||
w.Write([]byte(fmt.Sprintf("Got `%s` instead of `application/json`", r.Header.Get("content-type")))) |
||||
return |
||||
} |
||||
|
||||
requestBody, err := io.ReadAll(r.Body) |
||||
if err != nil { |
||||
log.Println("Error reading http request (create) : ", err) |
||||
w.WriteHeader(http.StatusBadRequest) |
||||
r.Body.Close() |
||||
return |
||||
} |
||||
defer r.Body.Close() |
||||
|
||||
var givenUpdatedRandomData RandomData |
||||
err = json.Unmarshal(requestBody, &givenUpdatedRandomData) |
||||
if err != nil { |
||||
log.Println("Error unmarshalling request body (updateSpecificRandomData) : ", err) |
||||
return |
||||
} |
||||
|
||||
givenID := strings.Split(r.URL.String(), "/")[2] |
||||
|
||||
dbBytes, err := dbHandler.readDatabase() |
||||
if err != nil { |
||||
log.Println("Error reading db (updateSpecificRandomData) : ", err) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
var db []RandomData |
||||
|
||||
err = json.Unmarshal(dbBytes, &db) |
||||
if err != nil { |
||||
log.Println("Error unmarshalling database (update) : ", err) |
||||
return |
||||
} |
||||
|
||||
int64GivenID, _ := strconv.ParseInt(givenID, 10, 64) |
||||
var counter int64 |
||||
for _, randomData := range db { |
||||
if int64GivenID == randomData.ID { |
||||
var updatedRandomData RandomData |
||||
|
||||
updatedRandomData = givenUpdatedRandomData |
||||
updatedRandomData.ID = randomData.ID |
||||
updatedRandomData.DateCreated = randomData.DateCreated |
||||
updatedRandomData.LastUpdated = time.Now().UTC() |
||||
|
||||
dbHandler.removeRandomData(int64GivenID) |
||||
dbHandler.writeRandomData(updatedRandomData) |
||||
|
||||
log.Printf("Successfully updated RandomData with id %v \n", updatedRandomData.ID) |
||||
return |
||||
} |
||||
counter++ |
||||
} |
||||
|
||||
w.WriteHeader(http.StatusNotFound) |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) deleteSpecificRandomData(w http.ResponseWriter, r *http.Request) { |
||||
givenID := strings.Split(r.URL.String(), "/")[2] |
||||
|
||||
int64GivenID, _ := strconv.ParseInt(givenID, 10, 64) |
||||
|
||||
err := dbHandler.removeRandomData(int64GivenID) |
||||
if err != nil { |
||||
log.Println("Error removing RandomData (deleteSpecificRandomData) : ", err) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
w.WriteHeader(http.StatusOK) |
||||
|
||||
log.Printf("Successfully deleted RandomData with id %v \n", int64GivenID) |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) handle(w http.ResponseWriter, r *http.Request) { |
||||
switch r.Method { |
||||
case "GET": |
||||
dbHandler.get(w, r) |
||||
case "POST": |
||||
dbHandler.create(w, r) |
||||
default: |
||||
w.WriteHeader(http.StatusMethodNotAllowed) |
||||
} |
||||
} |
||||
|
||||
func (dbHandler *randomDataHandler) handleSpecific(w http.ResponseWriter, r *http.Request) { |
||||
switch r.Method { |
||||
case "GET": |
||||
dbHandler.getSpecificRandomData(w, r) |
||||
case "PUT": |
||||
dbHandler.updateSpecificRandomData(w, r) |
||||
case "DELETE": |
||||
dbHandler.deleteSpecificRandomData(w, r) |
||||
default: |
||||
w.WriteHeader(http.StatusMethodNotAllowed) |
||||
} |
||||
} |
||||
|
||||
func main() { |
||||
InitLogs() |
||||
|
||||
databaseHandler := newDatabaseHandler() |
||||
|
||||
servemux := http.NewServeMux() |
||||
servemux.HandleFunc("/", homepage) |
||||
servemux.HandleFunc("/randomdata", databaseHandler.handle) |
||||
servemux.HandleFunc("/randomdata/", databaseHandler.handleSpecific) |
||||
|
||||
server := &http.Server{ |
||||
Addr: ":8000", |
||||
Handler: servemux, |
||||
ReadTimeout: 5 * time.Second, |
||||
WriteTimeout: 5 * time.Second, |
||||
} |
||||
log.Fatal(server.ListenAndServe()) |
||||
} |
Loading…
Reference in new issue