Skip to content

Commit

Permalink
✨ feat(main.go): add index.html route to display available routes and…
Browse files Browse the repository at this point in the history
… url params

🐛 fix(main.go): fix picsum route to return the same content type as the request
✨ feat(main.go): add checkError function to handle errors and return http status codes
✨ feat(main.go): add stringToInt64 function to convert string to int64 for seed
✨ feat(main.go): add getWHUrlParams function to get width and height url params and check if they are in range
✨ feat(main.go): add seed to picsum route and print it to console
✨ feat(main.go): add support for configurable port from .env file in main function and print it to console
  • Loading branch information
readyyyk committed Jun 2, 2023
1 parent af05b70 commit b6fb8d2
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 60 deletions.
1 change: 0 additions & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
PORT=8080
PORT=3001
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Hash maps
# Random Image API

## Usage
**http://`host`:`port`/render?seed=`any`&w=`[1..100]`&h=`[1..100]`**
> width and height are not required, default is 7x7
host: https://readyyyk-randimgapi.onrender.com/
**http://`host`:`port`/hashmaps?`...[url params]`**
**http://`host`:`port`/picsum?`...[url params]`**
> width and height defaults:
> - hashmaps - 7x7
> - picsum - 64x64
> returns `svg` image
> returns:
> - hashmaps - `svg` image
> - picsum - `jpeg` image
## Installation

Expand Down
Binary file added hashMaps
Binary file not shown.
17 changes: 17 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<main style="text-align: center;">
<a href="https://github.com/readyyyk/randImgAPI"> <h1> https://github.com/readyyyk/randImgAPI </h1> </a>
</main>

<h2>
Use some of these routes:
</h2>
<ul>
<li> <i>/hashmap</i> </li>
<li> <i>/picsum</i> </li>
</ul>
<h2> Use these url params: </h2>
<ul>
<li> <b> seed </b> <small>int/string</small> </li>
<li> <b> w </b> <small>int (for hashmaps <100)</small> </li>
<li> <b> h </b> <small>int (for hashmaps <100)</small> </li>
</ul>
163 changes: 108 additions & 55 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,95 @@ import (
svg "github.com/ajstarks/svgo"
"github.com/joho/godotenv"
"io"
"math"
"math/rand"
"net/http"
"os"
"strconv"
"time"
)

func checkError(err error, httpCode int, httpRes http.ResponseWriter) bool {
if err != nil {
httpRes.WriteHeader(httpCode)
fmt.Println(" [ERROR] - " + err.Error())
return true
}
return false
}

func stringToInt64(s string) int64 {
seed := int64(1)
for _, c := range s {
seed *= int64(c - '0')
}
return seed
}

func getWHUrlParams(req *http.Request, w *int, h *int, maxW int, maxH int) (err error) {
if !req.URL.Query().Has("w") && !req.URL.Query().Has("h") {
return nil
}
if req.URL.Query().Has("w") {
wUrl, err := strconv.Atoi(req.URL.Query().Get("w"))
if err != nil {
return err
}
if wUrl < 1 || wUrl > maxW {
return err
}
*w, *h = wUrl, wUrl
}
if req.URL.Query().Has("h") {
hUrl, err := strconv.Atoi(req.URL.Query().Get("h"))
if err != nil {
return err
}
if hUrl < 1 || hUrl > maxH {
return err
}
*h = hUrl
}
return nil
}

func main() {
http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
fileData, err := os.ReadFile("index.html")
if checkError(err, http.StatusInternalServerError, res) {
return
}
res.Header().Set("Content-Type", "text/html")
_, _ = res.Write(fileData)
})

// seed - required
// w - width (if not defined 7) in range [1..100]
// h - height (if not defined 7 or same as defined width) in range [1..100]
// <host>/render?seed=any&w=number&h=number
http.HandleFunc("/render", func(res http.ResponseWriter, req *http.Request) {
fmt.Println("[hashMap]")
http.HandleFunc("/hashmap", func(res http.ResponseWriter, req *http.Request) {
fmt.Println("\n[hashMap]")
if req.Method != "GET" {
res.WriteHeader(http.StatusBadRequest)
return
}
res.Header().Set("Content-Type", "image/svg+xml")

// setting random seed
seedStr := req.URL.Query().Get("seed")
seed := int64(1)
for _, c := range seedStr {
seed *= int64(c - '0')
seed := time.Now().UnixNano()
if req.URL.Query().Has("seed") {
seed = stringToInt64(req.URL.Query().Get("seed"))
}
fmt.Println(seed)
rand.Seed(seed)
fmt.Println("seed: ", seed)

// getting width and height with default 7x7 and in range of [1..100]
w, h := 7, 7
if req.URL.Query().Has("w") {
wUrl, err := strconv.Atoi(req.URL.Query().Get("w"))
if err != nil {
res.WriteHeader(http.StatusBadRequest)
return
}
if wUrl < 1 || wUrl > 100 {
res.WriteHeader(http.StatusBadRequest)
return
}
w, h = wUrl, wUrl
}
if req.URL.Query().Has("w") {
hUrl, err := strconv.Atoi(req.URL.Query().Get("h"))
if err != nil {
res.WriteHeader(http.StatusBadRequest)
return
}
if hUrl < 1 || hUrl > 100 {
res.WriteHeader(http.StatusBadRequest)
return
}
h = hUrl
}
checkError(
getWHUrlParams(req, &w, &h, 100, 100),
http.StatusBadRequest,
res,
)

colors := []string{"#000", "#fff"}
img := svg.New(res)
Expand All @@ -72,64 +107,82 @@ func main() {
}
img.End()
})

http.HandleFunc("/picsum", func(res http.ResponseWriter, req *http.Request) {
fmt.Println("[picsum]")
fmt.Println("\n[picsum]")
if req.Method != "GET" {
res.WriteHeader(http.StatusBadRequest)
return
}
if !req.URL.Query().Has("seed") {
res.WriteHeader(http.StatusBadRequest)
return

// setting random seed
seed := strconv.Itoa(int(time.Now().UnixNano()))
if req.URL.Query().Has("seed") {
seed = req.URL.Query().Get("seed")
}
fmt.Println(" seed: " + seed)

// fetching info from picsum/.../info and getting donwload url
fetchedData, err := http.Get("https://picsum.photos/seed/" + req.URL.Query().Get("seed") + "/info")
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
panic(err)
fetchedData, err := http.Get("https://picsum.photos/seed/" + seed + "/info")
if checkError(err, http.StatusInternalServerError, res) {
return
}

data, err := io.ReadAll(fetchedData.Body)
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
panic(err)
if checkError(err, http.StatusInternalServerError, res) {
return
}

type downloadUrl struct {
Url string `json:"download_url"`
}
var url downloadUrl
err = json.Unmarshal(data, &url)
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
panic(err)
if checkError(err, http.StatusInternalServerError, res) {
return
}

// processing download url
url.Url = url.Url[:len(url.Url)-9] + "64/64"
w, h := 64, 64
checkError(
getWHUrlParams(req, &w, &h, math.MaxInt, math.MaxInt),
http.StatusBadRequest,
res,
)

// fetching entire image
isSecondSlash := false
for i := len(url.Url) - 1; i >= -1; i-- {
if url.Url[i] != '/' {
continue
}
if !isSecondSlash {
isSecondSlash = true
continue
}
url.Url = url.Url[0 : i+1]
break
}
url.Url = url.Url + strconv.Itoa(w) + "/" + strconv.Itoa(h)

// reading image
fetchedData, err = http.Get(url.Url)
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
panic(err)
if checkError(err, http.StatusInternalServerError, res) {
return
}

data, err = io.ReadAll(fetchedData.Body)
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
panic(err)
if checkError(err, http.StatusInternalServerError, res) {
return
}

res.Header().Set("Content-Type", "image/jpeg")
// writing response
res.Header().Set("Content-Type", req.Header.Get("Content-Type"))
_, _ = res.Write(data)
res.WriteHeader(http.StatusOK)
return
})

err := godotenv.Load(".env")
fmt.Println("[SERVER] - starting on :" + os.Getenv("PORT") + " ...")
err = http.ListenAndServe(":"+os.Getenv("PORT"), nil)
if err != nil {
panic(err)
Expand Down

0 comments on commit b6fb8d2

Please sign in to comment.