api.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package api
  2. import (
  3. "encoding/json"
  4. "io"
  5. "net/http"
  6. "github.com/annybs/ezdb"
  7. "github.com/annybs/go/rest"
  8. "github.com/annybs/go/validate"
  9. "github.com/annybs/shorty/internal/types"
  10. "github.com/rs/zerolog"
  11. )
  12. type API struct {
  13. DB ezdb.Collection[*types.Redirect]
  14. Log zerolog.Logger
  15. AllPath string
  16. Token string
  17. }
  18. func (api *API) Delete(w http.ResponseWriter, req *http.Request) {
  19. if !rest.IsAuthenticated(req, api.Token) {
  20. w.WriteHeader(http.StatusUnauthorized)
  21. w.Write([]byte{})
  22. return
  23. }
  24. if req.URL.Path == api.AllPath {
  25. w.WriteHeader(http.StatusBadRequest)
  26. return
  27. }
  28. path := req.URL.Path
  29. if exist, _ := api.DB.Has(path); !exist {
  30. w.Write([]byte{})
  31. return
  32. }
  33. if err := api.DB.Delete(path); err != nil {
  34. w.WriteHeader(http.StatusInternalServerError)
  35. w.Write([]byte(err.Error()))
  36. } else {
  37. w.Write([]byte{})
  38. }
  39. }
  40. func (api *API) Get(w http.ResponseWriter, req *http.Request) {
  41. if req.URL.Path == api.AllPath {
  42. api.GetAll(w, req)
  43. return
  44. }
  45. path := req.URL.Path
  46. redirect, err := api.DB.Get(path)
  47. if err != nil {
  48. w.WriteHeader(http.StatusNotFound)
  49. w.Write([]byte(err.Error()))
  50. return
  51. }
  52. if len(redirect.Destination) == 0 || redirect.StatusCode == 0 {
  53. w.WriteHeader(http.StatusInternalServerError)
  54. w.Write([]byte("invalid redirect"))
  55. }
  56. w.Header().Set("Location", string(redirect.Destination))
  57. w.WriteHeader(redirect.StatusCode)
  58. w.Write([]byte{})
  59. }
  60. func (api *API) GetAll(w http.ResponseWriter, req *http.Request) {
  61. if !rest.IsAuthenticated(req, api.Token) {
  62. w.WriteHeader(http.StatusUnauthorized)
  63. w.Write([]byte{})
  64. return
  65. }
  66. all, err := api.DB.Iter().GetAll()
  67. if err != nil {
  68. w.WriteHeader(http.StatusInternalServerError)
  69. w.Write([]byte(err.Error()))
  70. return
  71. }
  72. data, err := json.Marshal(all)
  73. if err != nil {
  74. w.WriteHeader(http.StatusInternalServerError)
  75. w.Write([]byte(err.Error()))
  76. return
  77. }
  78. w.Write(data)
  79. }
  80. func (api *API) Put(w http.ResponseWriter, req *http.Request) {
  81. if !rest.IsAuthenticated(req, api.Token) {
  82. w.WriteHeader(http.StatusUnauthorized)
  83. w.Write([]byte{})
  84. return
  85. }
  86. if req.URL.Path == api.AllPath {
  87. w.WriteHeader(http.StatusBadRequest)
  88. return
  89. }
  90. path := req.URL.Path
  91. dest, err := io.ReadAll(req.Body)
  92. if err != nil {
  93. w.WriteHeader(http.StatusBadRequest)
  94. w.Write([]byte(err.Error()))
  95. return
  96. }
  97. if err := validate.URL(string(dest)); err != nil {
  98. w.WriteHeader(http.StatusBadRequest)
  99. w.Write([]byte(err.Error()))
  100. return
  101. }
  102. redirect := &types.Redirect{
  103. Destination: string(dest),
  104. StatusCode: http.StatusPermanentRedirect,
  105. }
  106. if err := api.DB.Put(path, redirect); err != nil {
  107. w.WriteHeader(http.StatusInternalServerError)
  108. w.Write([]byte(err.Error()))
  109. } else {
  110. w.Write([]byte{})
  111. }
  112. }
  113. func (api *API) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  114. api.Log.Info().Msgf("%s %s", req.Method, req.URL.Path)
  115. switch req.Method {
  116. case http.MethodGet:
  117. api.Get(w, req)
  118. case http.MethodPut:
  119. api.Put(w, req)
  120. case http.MethodDelete:
  121. api.Delete(w, req)
  122. default:
  123. w.WriteHeader(http.StatusBadRequest)
  124. w.Write([]byte("unsupported method"))
  125. }
  126. }