2018-07-07 16:10:42 +00:00
|
|
|
package aicra
|
2018-05-21 10:02:24 +00:00
|
|
|
|
|
|
|
import (
|
2021-03-28 17:05:43 +00:00
|
|
|
"log"
|
2020-04-04 08:39:02 +00:00
|
|
|
"net/http"
|
2019-04-30 22:02:28 +00:00
|
|
|
|
2020-04-04 09:50:01 +00:00
|
|
|
"git.xdrm.io/go/aicra/api"
|
2020-04-04 10:05:17 +00:00
|
|
|
"git.xdrm.io/go/aicra/internal/config"
|
2020-04-04 09:50:01 +00:00
|
|
|
"git.xdrm.io/go/aicra/internal/reqdata"
|
2018-05-21 10:02:24 +00:00
|
|
|
)
|
|
|
|
|
2021-03-28 17:03:16 +00:00
|
|
|
// Handler wraps the builder to handle requests
|
|
|
|
type Handler Builder
|
2020-04-04 08:36:52 +00:00
|
|
|
|
2021-03-28 17:03:16 +00:00
|
|
|
// ServeHTTP implements http.Handler
|
|
|
|
func (s Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
2021-03-28 17:05:43 +00:00
|
|
|
defer func() {
|
|
|
|
if rc := recover(); rc != nil {
|
|
|
|
log.Printf("recovering request: %s\n", rc)
|
|
|
|
// try to send error response
|
|
|
|
api.EmptyResponse().WithError(api.ErrUncallableService).ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
}()
|
2021-03-28 17:03:16 +00:00
|
|
|
defer r.Body.Close()
|
2018-07-10 23:36:42 +00:00
|
|
|
|
2021-03-28 17:03:16 +00:00
|
|
|
// 1. find a matching service from config
|
|
|
|
var service = s.conf.Find(r)
|
2020-04-04 09:50:01 +00:00
|
|
|
if service == nil {
|
2021-03-28 16:49:23 +00:00
|
|
|
handleError(api.ErrUnknownService, w, r)
|
2020-04-04 09:50:01 +00:00
|
|
|
return
|
2018-07-06 08:49:52 +00:00
|
|
|
}
|
|
|
|
|
2020-04-04 10:05:17 +00:00
|
|
|
// 2. extract request data
|
2021-03-28 17:03:16 +00:00
|
|
|
var input, err = extractInput(service, *r)
|
2020-04-04 09:50:01 +00:00
|
|
|
if err != nil {
|
2021-03-28 16:49:23 +00:00
|
|
|
handleError(api.ErrMissingParam, w, r)
|
2020-04-04 09:50:01 +00:00
|
|
|
return
|
2020-04-04 09:46:37 +00:00
|
|
|
}
|
|
|
|
|
2020-04-04 10:05:17 +00:00
|
|
|
// 3. find a matching handler
|
2020-04-04 09:50:01 +00:00
|
|
|
var handler *apiHandler
|
2021-03-28 17:03:16 +00:00
|
|
|
for _, h := range s.handlers {
|
2020-04-04 09:50:01 +00:00
|
|
|
if h.Method == service.Method && h.Path == service.Pattern {
|
|
|
|
handler = h
|
2020-03-29 13:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-04 08:36:52 +00:00
|
|
|
|
2021-03-28 17:03:16 +00:00
|
|
|
// 4. fail on no matching handler
|
2020-04-04 09:50:01 +00:00
|
|
|
if handler == nil {
|
2021-03-28 16:49:23 +00:00
|
|
|
handleError(api.ErrUncallableService, w, r)
|
2020-04-04 09:50:01 +00:00
|
|
|
return
|
2020-03-29 13:04:12 +00:00
|
|
|
}
|
|
|
|
|
2021-04-17 12:03:59 +00:00
|
|
|
// 5. create context and run middlewares
|
|
|
|
var ctx = &api.Context{
|
|
|
|
Context: r.Context(),
|
|
|
|
Request: r,
|
|
|
|
Response: w,
|
|
|
|
}
|
|
|
|
for _, mw := range s.middlewares {
|
|
|
|
ctx = mw.Handle(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 6. pass execution to the handler
|
|
|
|
var outData, outErr = handler.dyn.Handle(ctx, input.Data)
|
2020-04-04 10:05:17 +00:00
|
|
|
|
2021-04-17 12:03:59 +00:00
|
|
|
// 7. build res from returned data
|
2021-03-28 17:03:16 +00:00
|
|
|
var res = api.EmptyResponse().WithError(outErr)
|
|
|
|
for key, value := range outData {
|
2020-04-04 09:46:37 +00:00
|
|
|
|
2021-03-28 17:03:16 +00:00
|
|
|
// find original name from 'rename' field
|
2020-04-04 09:50:01 +00:00
|
|
|
for name, param := range service.Output {
|
|
|
|
if param.Rename == key {
|
2021-03-28 17:03:16 +00:00
|
|
|
res.SetData(name, value)
|
2020-03-21 15:53:19 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-04 09:50:01 +00:00
|
|
|
}
|
|
|
|
|
2021-04-17 12:03:59 +00:00
|
|
|
// 8. apply headers
|
2021-03-28 17:03:16 +00:00
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
|
|
for key, values := range res.Headers {
|
2020-04-04 09:50:01 +00:00
|
|
|
for _, value := range values {
|
2021-03-28 17:03:16 +00:00
|
|
|
w.Header().Add(key, value)
|
2020-03-21 15:53:19 +00:00
|
|
|
}
|
2019-09-26 17:03:37 +00:00
|
|
|
}
|
|
|
|
|
2021-03-28 17:03:16 +00:00
|
|
|
res.ServeHTTP(w, r)
|
2019-09-26 17:03:37 +00:00
|
|
|
}
|
2020-04-04 10:05:17 +00:00
|
|
|
|
2021-03-28 16:49:23 +00:00
|
|
|
func handleError(err api.Err, w http.ResponseWriter, r *http.Request) {
|
|
|
|
var response = api.EmptyResponse().WithError(err)
|
|
|
|
response.ServeHTTP(w, r)
|
2020-04-04 10:05:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-28 17:03:16 +00:00
|
|
|
func extractInput(service *config.Service, req http.Request) (*reqdata.T, error) {
|
2021-03-28 16:49:23 +00:00
|
|
|
var dataset = reqdata.New(service)
|
2020-04-04 10:05:17 +00:00
|
|
|
|
2021-03-28 16:49:23 +00:00
|
|
|
// URI data
|
|
|
|
var err = dataset.GetURI(req)
|
2020-04-04 10:05:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-28 16:49:23 +00:00
|
|
|
// query data
|
2020-04-04 12:56:15 +00:00
|
|
|
err = dataset.GetQuery(req)
|
2020-04-04 10:05:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-28 16:49:23 +00:00
|
|
|
// form/json data
|
2020-04-04 12:56:15 +00:00
|
|
|
err = dataset.GetForm(req)
|
2020-04-04 10:05:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return dataset, nil
|
|
|
|
}
|