github.com/weaviate/weaviate@v1.24.6/modules/text2vec-contextionary/extensions/rest_user_facing.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package extensions 13 14 import ( 15 "context" 16 "io" 17 "net/http" 18 19 "github.com/weaviate/weaviate/entities/models" 20 ) 21 22 type RESTUserFacingHandlers struct { 23 proxy Proxy 24 } 25 26 func newRESTUserFacingHandlers(proxy Proxy) *RESTUserFacingHandlers { 27 return &RESTUserFacingHandlers{ 28 proxy: proxy, 29 } 30 } 31 32 func (h *RESTHandlers) UserFacingHandler() http.Handler { 33 return newRESTUserFacingHandlers(h.proxy).Handler() 34 } 35 36 func (h *RESTUserFacingHandlers) Handler() http.Handler { 37 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 38 switch r.Method { 39 case http.MethodPost: 40 h.post(w, r) 41 default: 42 w.WriteHeader(http.StatusMethodNotAllowed) 43 } 44 }) 45 } 46 47 func (h *RESTUserFacingHandlers) post(w http.ResponseWriter, r *http.Request) { 48 ct := r.Header.Get("content-type") 49 if ct != "application/json" { 50 w.WriteHeader(http.StatusUnsupportedMediaType) 51 return 52 } 53 54 defer r.Body.Close() 55 body, err := io.ReadAll(r.Body) 56 if err != nil { 57 h.writeError(w, err, http.StatusInternalServerError) 58 return 59 } 60 61 var ext models.C11yExtension 62 if err := (&ext).UnmarshalBinary(body); err != nil { 63 h.writeError(w, err, http.StatusUnprocessableEntity) 64 return 65 } 66 67 if err := h.proxy.AddExtension(r.Context(), &ext); err != nil { 68 h.writeError(w, err, http.StatusBadRequest) 69 return 70 } 71 72 resBody, err := ext.MarshalBinary() 73 if err != nil { 74 h.writeError(w, err, http.StatusInternalServerError) 75 return 76 } 77 78 w.Header().Add("content-type", "application/json") 79 w.WriteHeader(http.StatusOK) 80 w.Write(resBody) 81 } 82 83 // C11yProxy proxies the request through the separate container, only for it to 84 // come back here for the storage. This is legacy from the pre-module times. 85 // TODO: cleanup, there does not need to be a separation between user-facing 86 // and internal storage endpoint in the long-term 87 type Proxy interface { 88 AddExtension(ctx context.Context, extension *models.C11yExtension) error 89 } 90 91 func (h *RESTUserFacingHandlers) writeError(w http.ResponseWriter, err error, code int) { 92 res := &models.ErrorResponse{Error: []*models.ErrorResponseErrorItems0{{ 93 Message: err.Error(), 94 }}} 95 96 json, mErr := res.MarshalBinary() 97 if mErr != nil { 98 // fallback to text 99 w.Header().Add("content-type", "text/plain") 100 w.WriteHeader(code) 101 w.Write([]byte(err.Error())) 102 } 103 104 w.Header().Add("content-type", "application/json") 105 w.WriteHeader(code) 106 w.Write(json) 107 }