Skip to content

Commit

Permalink
refactor(api): migrate v1 to v1beta1 (#61)
Browse files Browse the repository at this point in the history
* refactor(api): migrate v1 to v1beta1

* fix: add default notfound and methodnotallowed handlers
  • Loading branch information
mabdh authored Jan 17, 2022
1 parent 8111b08 commit 8bee2d6
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 79 deletions.
15 changes: 15 additions & 0 deletions api/handlers/default_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package handlers

import (
"net/http"

"github.com/gorilla/mux"
)

func NotFound(w http.ResponseWriter, r *http.Request) {
writeJSONError(w, http.StatusNotFound, mux.ErrNotFound.Error())
}

func MethodNotAllowed(w http.ResponseWriter, r *http.Request) {
writeJSONError(w, http.StatusMethodNotAllowed, mux.ErrMethodMismatch.Error())
}
43 changes: 43 additions & 0 deletions api/handlers/default_handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package handlers_test

import (
"net/http"
"net/http/httptest"
"testing"

"github.com/odpf/columbus/api/handlers"
)

func TestNotFoundHandler(t *testing.T) {
handler := http.HandlerFunc(handlers.NotFound)
rr := httptest.NewRequest("GET", "/xxx", nil)
rw := httptest.NewRecorder()
handler.ServeHTTP(rw, rr)
if rw.Code != 404 {
t.Errorf("expected handler to respond with HTTP 404, got HTTP %d instead", rw.Code)
return
}
expectedResponse := "{\"reason\":\"no matching route was found\"}\n"
actualResponse := rw.Body.String()
if actualResponse != expectedResponse {
t.Errorf("expected handler response to be %q, was %q instead", expectedResponse, actualResponse)
return
}
}

func TestMethodNotAllowedHandler(t *testing.T) {
handler := http.HandlerFunc(handlers.MethodNotAllowed)
rr := httptest.NewRequest("POST", "/ping", nil)
rw := httptest.NewRecorder()
handler.ServeHTTP(rw, rr)
if rw.Code != 405 {
t.Errorf("expected handler to respond with HTTP 405, got HTTP %d instead", rw.Code)
return
}
expectedResponse := "{\"reason\":\"method is not allowed\"}\n"
actualResponse := rw.Body.String()
if actualResponse != expectedResponse {
t.Errorf("expected handler response to be %q, was %q instead", expectedResponse, actualResponse)
return
}
}
1 change: 0 additions & 1 deletion api/middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ func decodeURLMiddleware(logger logrus.FieldLogger) mux.MiddlewareFunc {

newVars[key] = decodedVal
}

r = mux.SetURLVars(r, newVars)
h.ServeHTTP(rw, r)
})
Expand Down
98 changes: 33 additions & 65 deletions api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@ type Config struct {
LineageProvider handlers.LineageProvider
}

func RegisterRoutes(router *mux.Router, config Config) {
// By default mux will decode url and then match the decoded url against the route
// we reverse the steps by telling mux to use encoded path to match the url
// then we manually decode via custom middleware (decodeURLMiddleware).
//
// This is to allow urn that has "/" to be matched correctly to the route
router.UseEncodedPath()
router.Use(decodeURLMiddleware(config.Logger))
type Handlers struct {
Type *handlers.TypeHandler
Record *handlers.RecordHandler
Search *handlers.SearchHandler
Lineage *handlers.LineageHandler
Tag *handlers.TagHandler
TagTemplate *handlers.TagTemplateHandler
}

func initHandlers(config Config) *Handlers {
typeHandler := handlers.NewTypeHandler(
config.Logger.WithField("reporter", "type-handler"),
config.TypeRepository,
Expand Down Expand Up @@ -58,68 +59,35 @@ func RegisterRoutes(router *mux.Router, config Config) {
config.TagTemplateService,
)

router.PathPrefix("/ping").Handler(handlers.NewHeartbeatHandler())
setupV1TypeRoutes(router, typeHandler, recordHandler)
setupV1TagRoutes(router, "/v1/tags", tagHandler, tagTemplateHandler)

router.Path("/v1/search").
Methods(http.MethodGet).
HandlerFunc(searchHandler.Search)

router.Path("/v1/search/suggest").
Methods(http.MethodGet).
HandlerFunc(searchHandler.Suggest)

router.PathPrefix("/v1/lineage/{type}/{id}").
Methods(http.MethodGet).
HandlerFunc(lineageHandler.GetLineage)

router.PathPrefix("/v1/lineage").
Methods(http.MethodGet).
HandlerFunc(lineageHandler.ListLineage)
return &Handlers{
Type: typeHandler,
Record: recordHandler,
Search: searchHandler,
Lineage: lineageHandler,
Tag: tagHandler,
TagTemplate: tagTemplateHandler,
}
}

func setupV1TypeRoutes(router *mux.Router, th *handlers.TypeHandler, rh *handlers.RecordHandler) {
typeURL := "/v1/types"

router.Path(typeURL).
Methods(http.MethodGet, http.MethodHead).
HandlerFunc(th.Get)

recordURL := "/v1/types/{name}/records"
router.Path(recordURL).
Methods(http.MethodPut, http.MethodHead).
HandlerFunc(rh.UpsertBulk)

router.Path(recordURL).
Methods(http.MethodGet, http.MethodHead).
HandlerFunc(rh.GetByType)

router.Path(recordURL+"/{id}").
Methods(http.MethodGet, http.MethodHead).
HandlerFunc(rh.GetOneByType)

router.Path(recordURL+"/{id}").
Methods(http.MethodDelete, http.MethodHead).
HandlerFunc(rh.Delete)

}
func RegisterRoutes(router *mux.Router, config Config) {
// By default mux will decode url and then match the decoded url against the route
// we reverse the steps by telling mux to use encoded path to match the url
// then we manually decode via custom middleware (decodeURLMiddleware).
//
// This is to allow urn that has "/" to be matched correctly to the route
router.UseEncodedPath()
router.Use(decodeURLMiddleware(config.Logger))

func setupV1TagRoutes(router *mux.Router, baseURL string, th *handlers.TagHandler, tth *handlers.TagTemplateHandler) {
router.Methods(http.MethodPost).Path(baseURL).HandlerFunc(th.Create)
handlerCollection := initHandlers(config)

url := baseURL + "/types/{type}/records/{record_urn}/templates/{template_urn}"
router.Methods(http.MethodGet).Path(url).HandlerFunc(th.FindByRecordAndTemplate)
router.Methods(http.MethodPut).Path(url).HandlerFunc(th.Update)
router.Methods(http.MethodDelete).Path(url).HandlerFunc(th.Delete)
router.PathPrefix("/ping").Handler(handlers.NewHeartbeatHandler())

router.Methods(http.MethodGet).Path(baseURL + "/types/{type}/records/{record_urn}").HandlerFunc(th.GetByRecord)
v1Beta1SubRouter := router.PathPrefix("/v1beta1").Subrouter()
setupV1Beta1Router(v1Beta1SubRouter, handlerCollection)

templateURL := baseURL + "/templates"
router.Methods(http.MethodGet).Path(templateURL).HandlerFunc(tth.Index)
router.Methods(http.MethodPost).Path(templateURL).HandlerFunc(tth.Create)
router.Methods(http.MethodGet).Path(templateURL + "/{template_urn}").HandlerFunc(tth.Find)
router.Methods(http.MethodPut).Path(templateURL + "/{template_urn}").HandlerFunc(tth.Update)
router.Methods(http.MethodDelete).Path(templateURL + "/{template_urn}").HandlerFunc(tth.Delete)
v1SubRouter := router.PathPrefix("/v1").Subrouter()
setupV1Beta1Router(v1SubRouter, handlerCollection)

router.NotFoundHandler = http.HandlerFunc(handlers.NotFound)
router.MethodNotAllowedHandler = http.HandlerFunc(handlers.MethodNotAllowed)
}
76 changes: 76 additions & 0 deletions api/v1beta1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package api

import (
"net/http"

"github.com/gorilla/mux"
"github.com/odpf/columbus/api/handlers"
)

func setupV1Beta1Router(router *mux.Router, handlers *Handlers) *mux.Router {
setupV1Beta1TypeRoutes(router, handlers.Type, handlers.Record)
setupV1Beta1TagRoutes(router, "/tags", handlers.Tag, handlers.TagTemplate)

router.Path("/search").
Methods(http.MethodGet).
HandlerFunc(handlers.Search.Search)

router.Path("/search/suggest").
Methods(http.MethodGet).
HandlerFunc(handlers.Search.Suggest)

router.PathPrefix("/lineage/{type}/{id}").
Methods(http.MethodGet).
HandlerFunc(handlers.Lineage.GetLineage)

router.PathPrefix("/lineage").
Methods(http.MethodGet).
HandlerFunc(handlers.Lineage.ListLineage)

return router
}

func setupV1Beta1TypeRoutes(router *mux.Router, th *handlers.TypeHandler, rh *handlers.RecordHandler) {
typeURL := "/types"

router.Path(typeURL).
Methods(http.MethodGet, http.MethodHead).
HandlerFunc(th.Get)

recordURL := "/types/{name}/records"
router.Path(recordURL).
Methods(http.MethodPut, http.MethodHead).
HandlerFunc(rh.UpsertBulk)

router.Path(recordURL).
Methods(http.MethodGet, http.MethodHead).
HandlerFunc(rh.GetByType)

router.Path(recordURL+"/{id}").
Methods(http.MethodGet, http.MethodHead).
HandlerFunc(rh.GetOneByType)

router.Path(recordURL+"/{id}").
Methods(http.MethodDelete, http.MethodHead).
HandlerFunc(rh.Delete)

}

func setupV1Beta1TagRoutes(router *mux.Router, baseURL string, th *handlers.TagHandler, tth *handlers.TagTemplateHandler) {
router.Methods(http.MethodPost).Path(baseURL).HandlerFunc(th.Create)

url := baseURL + "/types/{type}/records/{record_urn}/templates/{template_urn}"
router.Methods(http.MethodGet).Path(url).HandlerFunc(th.FindByRecordAndTemplate)
router.Methods(http.MethodPut).Path(url).HandlerFunc(th.Update)
router.Methods(http.MethodDelete).Path(url).HandlerFunc(th.Delete)

router.Methods(http.MethodGet).Path(baseURL + "/types/{type}/records/{record_urn}").HandlerFunc(th.GetByRecord)

templateURL := baseURL + "/templates"
router.Methods(http.MethodGet).Path(templateURL).HandlerFunc(tth.Index)
router.Methods(http.MethodPost).Path(templateURL).HandlerFunc(tth.Create)
router.Methods(http.MethodGet).Path(templateURL + "/{template_urn}").HandlerFunc(tth.Find)
router.Methods(http.MethodPut).Path(templateURL + "/{template_urn}").HandlerFunc(tth.Update)
router.Methods(http.MethodDelete).Path(templateURL + "/{template_urn}").HandlerFunc(tth.Delete)

}
2 changes: 1 addition & 1 deletion docs/concepts/internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The script filter is designed to match a document if:
To demonstrate, the following API call:

```text
curl http://localhost:3000/v1/search?text=log&filter.landscape=id
curl http://localhost:3000/v1beta1/search?text=log&filter.landscape=id
```

is internally translated to the following elasticsearch query
Expand Down
24 changes: 12 additions & 12 deletions swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ info:
description: "Data Discovery and Lineage Service"
version: 0.1.0
paths:
"/v1/lineage":
"/v1beta1/lineage":
get:
tags:
- Lineage
Expand All @@ -28,7 +28,7 @@ paths:
description: record not found
schema:
$ref: "#/definitions/Error"
"/v1/lineage/{type}/{record}":
"/v1beta1/lineage/{type}/{record}":
get:
tags:
- Lineage
Expand All @@ -49,7 +49,7 @@ paths:
description: invalid type requested
schema:
$ref: "#/definitions/Error"
"/v1/types":
"/v1beta1/types":
get:
tags:
- Type
Expand All @@ -70,7 +70,7 @@ paths:
count:
type: number
example: 1800
"/v1/types/{name}/records":
"/v1beta1/types/{name}/records":
put:
tags:
- Record
Expand Down Expand Up @@ -132,7 +132,7 @@ paths:
description: not found
schema:
$ref: "#/definitions/Error"
"/v1/types/{name}/records/{id}":
"/v1beta1/types/{name}/records/{id}":
delete:
tags:
- Record
Expand All @@ -158,7 +158,7 @@ paths:
description: type or record cannot be found
schema:
$ref: "#/definitions/Error"
"/v1/types/{name}/{id}":
"/v1beta1/types/{name}/{id}":
get:
tags:
- Record
Expand All @@ -183,7 +183,7 @@ paths:
description: document or type does not exist
schema:
$ref: "#/definitions/Error"
"/v1/search":
"/v1beta1/search":
get:
tags:
- Search
Expand Down Expand Up @@ -236,7 +236,7 @@ paths:
description: misconfigured request parameters
schema:
$ref: "#/definitions/Error"
"/v1/tags":
"/v1beta1/tags":
post:
tags:
- Tag
Expand Down Expand Up @@ -273,7 +273,7 @@ paths:
description: internal server error
schema:
$ref: "#/definitions/Error"
"/v1/tags/templates":
"/v1beta1/tags/templates":
get:
tags:
- Tag
Expand Down Expand Up @@ -327,7 +327,7 @@ paths:
description: internal server error
schema:
$ref: "#/definitions/Error"
"/v1/tags/templates/{template_urn}":
"/v1beta1/tags/templates/{template_urn}":
get:
tags:
- Tag
Expand Down Expand Up @@ -417,7 +417,7 @@ paths:
description: internal server error
schema:
$ref: "#/definitions/Error"
"/v1/tags/types/{type}/records/{record_urn}":
"/v1beta1/tags/types/{type}/records/{record_urn}":
get:
tags:
- Tag
Expand Down Expand Up @@ -445,7 +445,7 @@ paths:
description: internal server error
schema:
$ref: "#/definitions/Error"
"/v1/tags/types/{type}/records/{record_urn}/templates/{template_urn}":
"/v1beta1/tags/types/{type}/records/{record_urn}/templates/{template_urn}":
get:
tags:
- Tag
Expand Down

0 comments on commit 8bee2d6

Please sign in to comment.