github.com/weaviate/weaviate@v1.24.6/adapters/handlers/rest/handlers_objects.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 rest 13 14 import ( 15 "context" 16 "errors" 17 "fmt" 18 "strings" 19 20 middleware "github.com/go-openapi/runtime/middleware" 21 "github.com/go-openapi/strfmt" 22 "github.com/sirupsen/logrus" 23 "github.com/weaviate/weaviate/adapters/handlers/rest/operations" 24 "github.com/weaviate/weaviate/adapters/handlers/rest/operations/objects" 25 "github.com/weaviate/weaviate/entities/additional" 26 "github.com/weaviate/weaviate/entities/models" 27 "github.com/weaviate/weaviate/entities/schema/crossref" 28 autherrs "github.com/weaviate/weaviate/usecases/auth/authorization/errors" 29 "github.com/weaviate/weaviate/usecases/config" 30 "github.com/weaviate/weaviate/usecases/monitoring" 31 uco "github.com/weaviate/weaviate/usecases/objects" 32 "github.com/weaviate/weaviate/usecases/replica" 33 ) 34 35 type objectHandlers struct { 36 manager objectsManager 37 logger logrus.FieldLogger 38 config config.Config 39 modulesProvider ModulesProvider 40 metricRequestsTotal restApiRequestsTotal 41 } 42 43 type ModulesProvider interface { 44 RestApiAdditionalProperties(includeProp string, class *models.Class) map[string]interface{} 45 GetMeta() (map[string]interface{}, error) 46 HasMultipleVectorizers() bool 47 } 48 49 type objectsManager interface { 50 AddObject(context.Context, *models.Principal, *models.Object, 51 *additional.ReplicationProperties) (*models.Object, error) 52 ValidateObject(context.Context, *models.Principal, 53 *models.Object, *additional.ReplicationProperties) error 54 GetObject(context.Context, *models.Principal, string, strfmt.UUID, 55 additional.Properties, *additional.ReplicationProperties, string) (*models.Object, error) 56 DeleteObject(context.Context, *models.Principal, string, 57 strfmt.UUID, *additional.ReplicationProperties, string) error 58 UpdateObject(context.Context, *models.Principal, string, strfmt.UUID, 59 *models.Object, *additional.ReplicationProperties) (*models.Object, error) 60 HeadObject(ctx context.Context, principal *models.Principal, class string, id strfmt.UUID, 61 repl *additional.ReplicationProperties, tenant string) (bool, *uco.Error) 62 GetObjects(context.Context, *models.Principal, *int64, *int64, 63 *string, *string, *string, additional.Properties, string) ([]*models.Object, error) 64 Query(ctx context.Context, principal *models.Principal, 65 params *uco.QueryParams) ([]*models.Object, *uco.Error) 66 MergeObject(context.Context, *models.Principal, *models.Object, 67 *additional.ReplicationProperties) *uco.Error 68 AddObjectReference(context.Context, *models.Principal, *uco.AddReferenceInput, 69 *additional.ReplicationProperties, string) *uco.Error 70 UpdateObjectReferences(context.Context, *models.Principal, 71 *uco.PutReferenceInput, *additional.ReplicationProperties, string) *uco.Error 72 DeleteObjectReference(context.Context, *models.Principal, *uco.DeleteReferenceInput, 73 *additional.ReplicationProperties, string) *uco.Error 74 GetObjectsClass(ctx context.Context, principal *models.Principal, id strfmt.UUID) (*models.Class, error) 75 GetObjectClassFromName(ctx context.Context, principal *models.Principal, className string) (*models.Class, error) 76 } 77 78 func (h *objectHandlers) addObject(params objects.ObjectsCreateParams, 79 principal *models.Principal, 80 ) middleware.Responder { 81 repl, err := getReplicationProperties(params.ConsistencyLevel, nil) 82 if err != nil { 83 h.metricRequestsTotal.logError("", err) 84 return objects.NewObjectsCreateBadRequest(). 85 WithPayload(errPayloadFromSingleErr(err)) 86 } 87 className := getClassName(params.Body) 88 89 object, err := h.manager.AddObject(params.HTTPRequest.Context(), 90 principal, params.Body, repl) 91 if err != nil { 92 h.metricRequestsTotal.logError(className, err) 93 if errors.As(err, &uco.ErrInvalidUserInput{}) { 94 return objects.NewObjectsCreateUnprocessableEntity(). 95 WithPayload(errPayloadFromSingleErr(err)) 96 } else if errors.As(err, &uco.ErrMultiTenancy{}) { 97 return objects.NewObjectsCreateUnprocessableEntity(). 98 WithPayload(errPayloadFromSingleErr(err)) 99 } else if errors.As(err, &autherrs.Forbidden{}) { 100 return objects.NewObjectsCreateForbidden(). 101 WithPayload(errPayloadFromSingleErr(err)) 102 } else { 103 return objects.NewObjectsCreateInternalServerError(). 104 WithPayload(errPayloadFromSingleErr(err)) 105 } 106 } 107 108 propertiesMap, ok := object.Properties.(map[string]interface{}) 109 if ok { 110 object.Properties = h.extendPropertiesWithAPILinks(propertiesMap) 111 } 112 113 h.metricRequestsTotal.logOk(className) 114 return objects.NewObjectsCreateOK().WithPayload(object) 115 } 116 117 func (h *objectHandlers) validateObject(params objects.ObjectsValidateParams, 118 principal *models.Principal, 119 ) middleware.Responder { 120 className := getClassName(params.Body) 121 err := h.manager.ValidateObject(params.HTTPRequest.Context(), principal, params.Body, nil) 122 if err != nil { 123 h.metricRequestsTotal.logError(className, err) 124 switch err.(type) { 125 case autherrs.Forbidden: 126 return objects.NewObjectsValidateForbidden(). 127 WithPayload(errPayloadFromSingleErr(err)) 128 case uco.ErrInvalidUserInput: 129 return objects.NewObjectsValidateUnprocessableEntity(). 130 WithPayload(errPayloadFromSingleErr(err)) 131 case uco.ErrMultiTenancy: 132 return objects.NewObjectsValidateUnprocessableEntity(). 133 WithPayload(errPayloadFromSingleErr(err)) 134 default: 135 return objects.NewObjectsValidateInternalServerError(). 136 WithPayload(errPayloadFromSingleErr(err)) 137 } 138 } 139 140 h.metricRequestsTotal.logOk(className) 141 return objects.NewObjectsValidateOK() 142 } 143 144 // getObject gets object of a specific class 145 func (h *objectHandlers) getObject(params objects.ObjectsClassGetParams, 146 principal *models.Principal, 147 ) middleware.Responder { 148 var additional additional.Properties 149 150 // The process to extract additional params depends on knowing the schema 151 // which in turn requires a preflight load of the object. We can save this 152 // second db request if we know that the user did not specify any additional 153 // params. This could potentially be optimized further by checking if only 154 // non-module specific params are contained and decide then, but we do not 155 // know if this path is critical enough for this level of optimization. 156 if params.Include != nil { 157 var class *models.Class 158 var err error 159 if params.ClassName == "" { // deprecated request without classname 160 class, err = h.manager.GetObjectsClass(params.HTTPRequest.Context(), principal, params.ID) 161 } else { 162 class, err = h.manager.GetObjectClassFromName(params.HTTPRequest.Context(), principal, params.ClassName) 163 } 164 if err != nil { 165 h.metricRequestsTotal.logUserError(params.ClassName) 166 return objects.NewObjectsClassGetBadRequest(). 167 WithPayload(errPayloadFromSingleErr(err)) 168 } 169 170 additional, err = parseIncludeParam(params.Include, h.modulesProvider, true, class) 171 if err != nil { 172 h.metricRequestsTotal.logError(params.ClassName, err) 173 return objects.NewObjectsClassGetBadRequest(). 174 WithPayload(errPayloadFromSingleErr(err)) 175 } 176 } 177 178 replProps, err := getReplicationProperties(params.ConsistencyLevel, params.NodeName) 179 if err != nil { 180 h.metricRequestsTotal.logError(params.ClassName, err) 181 return objects.NewObjectsClassGetBadRequest(). 182 WithPayload(errPayloadFromSingleErr(err)) 183 } 184 185 tenant := getTenant(params.Tenant) 186 187 object, err := h.manager.GetObject(params.HTTPRequest.Context(), principal, 188 params.ClassName, params.ID, additional, replProps, tenant) 189 if err != nil { 190 h.metricRequestsTotal.logError(getClassName(object), err) 191 switch err.(type) { 192 case autherrs.Forbidden: 193 return objects.NewObjectsClassGetForbidden(). 194 WithPayload(errPayloadFromSingleErr(err)) 195 case uco.ErrNotFound: 196 return objects.NewObjectsClassGetNotFound() 197 case uco.ErrMultiTenancy: 198 return objects.NewObjectsClassGetUnprocessableEntity(). 199 WithPayload(errPayloadFromSingleErr(err)) 200 default: 201 return objects.NewObjectsClassGetInternalServerError(). 202 WithPayload(errPayloadFromSingleErr(err)) 203 } 204 } 205 206 propertiesMap, ok := object.Properties.(map[string]interface{}) 207 if ok { 208 object.Properties = h.extendPropertiesWithAPILinks(propertiesMap) 209 } 210 211 h.metricRequestsTotal.logOk(getClassName(object)) 212 return objects.NewObjectsClassGetOK().WithPayload(object) 213 } 214 215 func (h *objectHandlers) getObjects(params objects.ObjectsListParams, 216 principal *models.Principal, 217 ) middleware.Responder { 218 if params.Class != nil && *params.Class != "" { 219 return h.query(params, principal) 220 } 221 additional, err := parseIncludeParam(params.Include, h.modulesProvider, h.shouldIncludeGetObjectsModuleParams(), nil) 222 if err != nil { 223 h.metricRequestsTotal.logError("", err) 224 return objects.NewObjectsListBadRequest(). 225 WithPayload(errPayloadFromSingleErr(err)) 226 } 227 228 var deprecationsRes []*models.Deprecation 229 230 list, err := h.manager.GetObjects(params.HTTPRequest.Context(), principal, 231 params.Offset, params.Limit, params.Sort, params.Order, params.After, additional, 232 getTenant(params.Tenant)) 233 if err != nil { 234 h.metricRequestsTotal.logError("", err) 235 switch err.(type) { 236 case autherrs.Forbidden: 237 return objects.NewObjectsListForbidden(). 238 WithPayload(errPayloadFromSingleErr(err)) 239 case uco.ErrMultiTenancy: 240 return objects.NewObjectsListUnprocessableEntity(). 241 WithPayload(errPayloadFromSingleErr(err)) 242 default: 243 return objects.NewObjectsListInternalServerError(). 244 WithPayload(errPayloadFromSingleErr(err)) 245 } 246 } 247 248 for i, object := range list { 249 propertiesMap, ok := object.Properties.(map[string]interface{}) 250 if ok { 251 list[i].Properties = h.extendPropertiesWithAPILinks(propertiesMap) 252 } 253 } 254 255 h.metricRequestsTotal.logOk("") 256 return objects.NewObjectsListOK(). 257 WithPayload(&models.ObjectsListResponse{ 258 Objects: list, 259 TotalResults: int64(len(list)), 260 Deprecations: deprecationsRes, 261 }) 262 } 263 264 func (h *objectHandlers) query(params objects.ObjectsListParams, 265 principal *models.Principal, 266 ) middleware.Responder { 267 additional, err := parseIncludeParam(params.Include, h.modulesProvider, h.shouldIncludeGetObjectsModuleParams(), nil) 268 if err != nil { 269 h.metricRequestsTotal.logError(*params.Class, err) 270 return objects.NewObjectsListBadRequest(). 271 WithPayload(errPayloadFromSingleErr(err)) 272 } 273 req := uco.QueryParams{ 274 Class: *params.Class, 275 Offset: params.Offset, 276 Limit: params.Limit, 277 After: params.After, 278 Sort: params.Sort, 279 Order: params.Order, 280 Tenant: params.Tenant, 281 Additional: additional, 282 } 283 resultSet, rerr := h.manager.Query(params.HTTPRequest.Context(), principal, &req) 284 if rerr != nil { 285 h.metricRequestsTotal.logError(req.Class, rerr) 286 switch rerr.Code { 287 case uco.StatusForbidden: 288 return objects.NewObjectsListForbidden(). 289 WithPayload(errPayloadFromSingleErr(rerr)) 290 case uco.StatusNotFound: 291 return objects.NewObjectsListNotFound() 292 case uco.StatusBadRequest: 293 return objects.NewObjectsListUnprocessableEntity(). 294 WithPayload(errPayloadFromSingleErr(rerr)) 295 case uco.StatusUnprocessableEntity: 296 return objects.NewObjectsListUnprocessableEntity(). 297 WithPayload(errPayloadFromSingleErr(rerr)) 298 default: 299 return objects.NewObjectsListInternalServerError(). 300 WithPayload(errPayloadFromSingleErr(rerr)) 301 } 302 } 303 304 for i, object := range resultSet { 305 propertiesMap, ok := object.Properties.(map[string]interface{}) 306 if ok { 307 resultSet[i].Properties = h.extendPropertiesWithAPILinks(propertiesMap) 308 } 309 } 310 311 h.metricRequestsTotal.logOk(req.Class) 312 return objects.NewObjectsListOK(). 313 WithPayload(&models.ObjectsListResponse{ 314 Objects: resultSet, 315 TotalResults: int64(len(resultSet)), 316 Deprecations: []*models.Deprecation{}, 317 }) 318 } 319 320 // deleteObject delete a single object of giving class 321 func (h *objectHandlers) deleteObject(params objects.ObjectsClassDeleteParams, 322 principal *models.Principal, 323 ) middleware.Responder { 324 repl, err := getReplicationProperties(params.ConsistencyLevel, nil) 325 if err != nil { 326 h.metricRequestsTotal.logError(params.ClassName, err) 327 return objects.NewObjectsCreateBadRequest(). 328 WithPayload(errPayloadFromSingleErr(err)) 329 } 330 331 tenant := getTenant(params.Tenant) 332 333 err = h.manager.DeleteObject(params.HTTPRequest.Context(), 334 principal, params.ClassName, params.ID, repl, tenant) 335 if err != nil { 336 h.metricRequestsTotal.logError(params.ClassName, err) 337 switch err.(type) { 338 case autherrs.Forbidden: 339 return objects.NewObjectsClassDeleteForbidden(). 340 WithPayload(errPayloadFromSingleErr(err)) 341 case uco.ErrNotFound: 342 return objects.NewObjectsClassDeleteNotFound() 343 case uco.ErrMultiTenancy: 344 return objects.NewObjectsClassDeleteUnprocessableEntity(). 345 WithPayload(errPayloadFromSingleErr(err)) 346 default: 347 return objects.NewObjectsClassDeleteInternalServerError(). 348 WithPayload(errPayloadFromSingleErr(err)) 349 } 350 } 351 352 h.metricRequestsTotal.logOk(params.ClassName) 353 return objects.NewObjectsClassDeleteNoContent() 354 } 355 356 func (h *objectHandlers) updateObject(params objects.ObjectsClassPutParams, 357 principal *models.Principal, 358 ) middleware.Responder { 359 className := getClassName(params.Body) 360 repl, err := getReplicationProperties(params.ConsistencyLevel, nil) 361 if err != nil { 362 h.metricRequestsTotal.logError(className, err) 363 return objects.NewObjectsCreateBadRequest(). 364 WithPayload(errPayloadFromSingleErr(err)) 365 } 366 367 object, err := h.manager.UpdateObject(params.HTTPRequest.Context(), 368 principal, params.ClassName, params.ID, params.Body, repl) 369 if err != nil { 370 h.metricRequestsTotal.logError(className, err) 371 if errors.As(err, &uco.ErrInvalidUserInput{}) { 372 return objects.NewObjectsClassPutUnprocessableEntity(). 373 WithPayload(errPayloadFromSingleErr(err)) 374 } else if errors.As(err, &uco.ErrMultiTenancy{}) { 375 return objects.NewObjectsClassPutUnprocessableEntity(). 376 WithPayload(errPayloadFromSingleErr(err)) 377 } else if errors.As(err, &autherrs.Forbidden{}) { 378 return objects.NewObjectsClassPutForbidden(). 379 WithPayload(errPayloadFromSingleErr(err)) 380 } else { 381 return objects.NewObjectsClassPutInternalServerError(). 382 WithPayload(errPayloadFromSingleErr(err)) 383 } 384 } 385 386 propertiesMap, ok := object.Properties.(map[string]interface{}) 387 if ok { 388 object.Properties = h.extendPropertiesWithAPILinks(propertiesMap) 389 } 390 391 h.metricRequestsTotal.logOk(className) 392 return objects.NewObjectsClassPutOK().WithPayload(object) 393 } 394 395 func (h *objectHandlers) headObject(params objects.ObjectsClassHeadParams, 396 principal *models.Principal, 397 ) middleware.Responder { 398 repl, err := getReplicationProperties(params.ConsistencyLevel, nil) 399 if err != nil { 400 h.metricRequestsTotal.logError(params.ClassName, err) 401 return objects.NewObjectsCreateBadRequest(). 402 WithPayload(errPayloadFromSingleErr(err)) 403 } 404 405 tenant := getTenant(params.Tenant) 406 407 exists, objErr := h.manager.HeadObject(params.HTTPRequest.Context(), 408 principal, params.ClassName, params.ID, repl, tenant) 409 if objErr != nil { 410 h.metricRequestsTotal.logError(params.ClassName, objErr) 411 switch { 412 case objErr.Forbidden(): 413 return objects.NewObjectsClassHeadForbidden(). 414 WithPayload(errPayloadFromSingleErr(objErr)) 415 case objErr.UnprocessableEntity(): 416 return objects.NewObjectsClassHeadUnprocessableEntity(). 417 WithPayload(errPayloadFromSingleErr(objErr)) 418 default: 419 return objects.NewObjectsClassHeadInternalServerError(). 420 WithPayload(errPayloadFromSingleErr(objErr)) 421 } 422 } 423 424 h.metricRequestsTotal.logOk(params.ClassName) 425 if !exists { 426 return objects.NewObjectsClassHeadNotFound() 427 } 428 return objects.NewObjectsClassHeadNoContent() 429 } 430 431 func (h *objectHandlers) patchObject(params objects.ObjectsClassPatchParams, principal *models.Principal) middleware.Responder { 432 updates := params.Body 433 updates.ID = params.ID 434 updates.Class = params.ClassName 435 436 repl, err := getReplicationProperties(params.ConsistencyLevel, nil) 437 if err != nil { 438 h.metricRequestsTotal.logError(getClassName(updates), err) 439 return objects.NewObjectsCreateBadRequest(). 440 WithPayload(errPayloadFromSingleErr(err)) 441 } 442 443 objErr := h.manager.MergeObject(params.HTTPRequest.Context(), principal, updates, repl) 444 if objErr != nil { 445 h.metricRequestsTotal.logError(getClassName(updates), objErr) 446 switch { 447 case objErr.NotFound(): 448 return objects.NewObjectsClassPatchNotFound() 449 case objErr.Forbidden(): 450 return objects.NewObjectsClassPatchForbidden(). 451 WithPayload(errPayloadFromSingleErr(objErr)) 452 case objErr.BadRequest(): 453 return objects.NewObjectsClassPatchUnprocessableEntity(). 454 WithPayload(errPayloadFromSingleErr(objErr)) 455 case objErr.UnprocessableEntity(): 456 return objects.NewObjectsClassPatchUnprocessableEntity(). 457 WithPayload(errPayloadFromSingleErr(objErr)) 458 default: 459 return objects.NewObjectsClassPatchInternalServerError(). 460 WithPayload(errPayloadFromSingleErr(objErr)) 461 } 462 } 463 464 h.metricRequestsTotal.logOk(getClassName(updates)) 465 return objects.NewObjectsClassPatchNoContent() 466 } 467 468 func (h *objectHandlers) addObjectReference( 469 params objects.ObjectsClassReferencesCreateParams, 470 principal *models.Principal, 471 ) middleware.Responder { 472 input := uco.AddReferenceInput{ 473 Class: params.ClassName, 474 ID: params.ID, 475 Property: params.PropertyName, 476 Ref: *params.Body, 477 } 478 479 repl, err := getReplicationProperties(params.ConsistencyLevel, nil) 480 if err != nil { 481 h.metricRequestsTotal.logError(params.ClassName, err) 482 return objects.NewObjectsCreateBadRequest(). 483 WithPayload(errPayloadFromSingleErr(err)) 484 } 485 tenant := getTenant(params.Tenant) 486 487 objErr := h.manager.AddObjectReference(params.HTTPRequest.Context(), principal, &input, repl, tenant) 488 if objErr != nil { 489 h.metricRequestsTotal.logError(params.ClassName, objErr) 490 switch { 491 case objErr.Forbidden(): 492 return objects.NewObjectsClassReferencesCreateForbidden(). 493 WithPayload(errPayloadFromSingleErr(objErr)) 494 case objErr.NotFound(): 495 return objects.NewObjectsClassReferencesCreateNotFound() 496 case objErr.BadRequest(): 497 return objects.NewObjectsClassReferencesCreateUnprocessableEntity(). 498 WithPayload(errPayloadFromSingleErr(objErr)) 499 case objErr.UnprocessableEntity(): 500 return objects.NewObjectsClassReferencesCreateUnprocessableEntity(). 501 WithPayload(errPayloadFromSingleErr(objErr)) 502 default: 503 return objects.NewObjectsClassReferencesCreateInternalServerError(). 504 WithPayload(errPayloadFromSingleErr(objErr)) 505 } 506 } 507 508 h.metricRequestsTotal.logOk(params.ClassName) 509 return objects.NewObjectsClassReferencesCreateOK() 510 } 511 512 func (h *objectHandlers) putObjectReferences(params objects.ObjectsClassReferencesPutParams, 513 principal *models.Principal, 514 ) middleware.Responder { 515 input := uco.PutReferenceInput{ 516 Class: params.ClassName, 517 ID: params.ID, 518 Property: params.PropertyName, 519 Refs: params.Body, 520 } 521 522 repl, err := getReplicationProperties(params.ConsistencyLevel, nil) 523 if err != nil { 524 h.metricRequestsTotal.logError(params.ClassName, err) 525 return objects.NewObjectsCreateBadRequest(). 526 WithPayload(errPayloadFromSingleErr(err)) 527 } 528 529 tenant := getTenant(params.Tenant) 530 531 objErr := h.manager.UpdateObjectReferences(params.HTTPRequest.Context(), principal, &input, repl, tenant) 532 if objErr != nil { 533 h.metricRequestsTotal.logError(params.ClassName, objErr) 534 switch { 535 case objErr.Forbidden(): 536 return objects.NewObjectsClassReferencesPutForbidden(). 537 WithPayload(errPayloadFromSingleErr(objErr)) 538 case objErr.NotFound(): 539 return objects.NewObjectsClassReferencesPutNotFound() 540 case objErr.BadRequest(): 541 return objects.NewObjectsClassReferencesPutUnprocessableEntity(). 542 WithPayload(errPayloadFromSingleErr(objErr)) 543 case objErr.UnprocessableEntity(): 544 return objects.NewObjectsClassReferencesPutUnprocessableEntity(). 545 WithPayload(errPayloadFromSingleErr(objErr)) 546 default: 547 return objects.NewObjectsClassReferencesPutInternalServerError(). 548 WithPayload(errPayloadFromSingleErr(objErr)) 549 } 550 } 551 552 h.metricRequestsTotal.logOk(params.ClassName) 553 return objects.NewObjectsClassReferencesPutOK() 554 } 555 556 func (h *objectHandlers) deleteObjectReference(params objects.ObjectsClassReferencesDeleteParams, 557 principal *models.Principal, 558 ) middleware.Responder { 559 input := uco.DeleteReferenceInput{ 560 Class: params.ClassName, 561 ID: params.ID, 562 Property: params.PropertyName, 563 Reference: *params.Body, 564 } 565 566 repl, err := getReplicationProperties(params.ConsistencyLevel, nil) 567 if err != nil { 568 h.metricRequestsTotal.logError(params.ClassName, err) 569 return objects.NewObjectsCreateBadRequest(). 570 WithPayload(errPayloadFromSingleErr(err)) 571 } 572 tenant := getTenant(params.Tenant) 573 574 objErr := h.manager.DeleteObjectReference(params.HTTPRequest.Context(), principal, &input, repl, tenant) 575 if objErr != nil { 576 h.metricRequestsTotal.logError(params.ClassName, objErr) 577 switch objErr.Code { 578 case uco.StatusForbidden: 579 return objects.NewObjectsClassReferencesDeleteForbidden(). 580 WithPayload(errPayloadFromSingleErr(objErr)) 581 case uco.StatusNotFound: 582 return objects.NewObjectsClassReferencesDeleteNotFound() 583 case uco.StatusBadRequest: 584 return objects.NewObjectsClassReferencesDeleteUnprocessableEntity(). 585 WithPayload(errPayloadFromSingleErr(objErr)) 586 case uco.StatusUnprocessableEntity: 587 return objects.NewObjectsClassReferencesDeleteUnprocessableEntity(). 588 WithPayload(errPayloadFromSingleErr(objErr)) 589 default: 590 return objects.NewObjectsClassReferencesDeleteInternalServerError(). 591 WithPayload(errPayloadFromSingleErr(objErr)) 592 } 593 } 594 595 h.metricRequestsTotal.logOk(params.ClassName) 596 return objects.NewObjectsClassReferencesDeleteNoContent() 597 } 598 599 func setupObjectHandlers(api *operations.WeaviateAPI, 600 manager *uco.Manager, config config.Config, logger logrus.FieldLogger, 601 modulesProvider ModulesProvider, metrics *monitoring.PrometheusMetrics, 602 ) { 603 h := &objectHandlers{manager, logger, config, modulesProvider, newObjectsRequestsTotal(metrics, logger)} 604 api.ObjectsObjectsCreateHandler = objects. 605 ObjectsCreateHandlerFunc(h.addObject) 606 api.ObjectsObjectsValidateHandler = objects. 607 ObjectsValidateHandlerFunc(h.validateObject) 608 api.ObjectsObjectsClassGetHandler = objects. 609 ObjectsClassGetHandlerFunc(h.getObject) 610 api.ObjectsObjectsClassHeadHandler = objects. 611 ObjectsClassHeadHandlerFunc(h.headObject) 612 api.ObjectsObjectsClassDeleteHandler = objects. 613 ObjectsClassDeleteHandlerFunc(h.deleteObject) 614 api.ObjectsObjectsListHandler = objects. 615 ObjectsListHandlerFunc(h.getObjects) 616 api.ObjectsObjectsClassPutHandler = objects. 617 ObjectsClassPutHandlerFunc(h.updateObject) 618 api.ObjectsObjectsClassPatchHandler = objects. 619 ObjectsClassPatchHandlerFunc(h.patchObject) 620 api.ObjectsObjectsClassReferencesCreateHandler = objects. 621 ObjectsClassReferencesCreateHandlerFunc(h.addObjectReference) 622 api.ObjectsObjectsClassReferencesDeleteHandler = objects. 623 ObjectsClassReferencesDeleteHandlerFunc(h.deleteObjectReference) 624 api.ObjectsObjectsClassReferencesPutHandler = objects. 625 ObjectsClassReferencesPutHandlerFunc(h.putObjectReferences) 626 // deprecated handlers 627 api.ObjectsObjectsGetHandler = objects. 628 ObjectsGetHandlerFunc(h.getObjectDeprecated) 629 api.ObjectsObjectsDeleteHandler = objects. 630 ObjectsDeleteHandlerFunc(h.deleteObjectDeprecated) 631 api.ObjectsObjectsHeadHandler = objects. 632 ObjectsHeadHandlerFunc(h.headObjectDeprecated) 633 api.ObjectsObjectsUpdateHandler = objects. 634 ObjectsUpdateHandlerFunc(h.updateObjectDeprecated) 635 api.ObjectsObjectsPatchHandler = objects. 636 ObjectsPatchHandlerFunc(h.patchObjectDeprecated) 637 api.ObjectsObjectsReferencesCreateHandler = objects. 638 ObjectsReferencesCreateHandlerFunc(h.addObjectReferenceDeprecated) 639 api.ObjectsObjectsReferencesUpdateHandler = objects. 640 ObjectsReferencesUpdateHandlerFunc(h.updateObjectReferencesDeprecated) 641 api.ObjectsObjectsReferencesDeleteHandler = objects. 642 ObjectsReferencesDeleteHandlerFunc(h.deleteObjectReferenceDeprecated) 643 } 644 645 func (h *objectHandlers) getObjectDeprecated(params objects.ObjectsGetParams, 646 principal *models.Principal, 647 ) middleware.Responder { 648 h.logger.Warn("deprecated endpoint: ", "GET "+params.HTTPRequest.URL.Path) 649 ps := objects.ObjectsClassGetParams{ 650 HTTPRequest: params.HTTPRequest, 651 ID: params.ID, 652 Include: params.Include, 653 } 654 return h.getObject(ps, principal) 655 } 656 657 func (h *objectHandlers) headObjectDeprecated(params objects.ObjectsHeadParams, 658 principal *models.Principal, 659 ) middleware.Responder { 660 h.logger.Warn("deprecated endpoint: ", "HEAD "+params.HTTPRequest.URL.Path) 661 r := objects.ObjectsClassHeadParams{ 662 HTTPRequest: params.HTTPRequest, 663 ID: params.ID, 664 } 665 return h.headObject(r, principal) 666 } 667 668 func (h *objectHandlers) patchObjectDeprecated(params objects.ObjectsPatchParams, principal *models.Principal) middleware.Responder { 669 h.logger.Warn("deprecated endpoint: ", "PATCH "+params.HTTPRequest.URL.Path) 670 args := objects.ObjectsClassPatchParams{ 671 HTTPRequest: params.HTTPRequest, 672 ID: params.ID, 673 Body: params.Body, 674 } 675 if params.Body != nil { 676 args.ClassName = params.Body.Class 677 } 678 return h.patchObject(args, principal) 679 } 680 681 func (h *objectHandlers) updateObjectDeprecated(params objects.ObjectsUpdateParams, 682 principal *models.Principal, 683 ) middleware.Responder { 684 h.logger.Warn("deprecated endpoint: ", "PUT "+params.HTTPRequest.URL.Path) 685 ps := objects.ObjectsClassPutParams{ 686 HTTPRequest: params.HTTPRequest, 687 ClassName: params.Body.Class, 688 Body: params.Body, 689 ID: params.ID, 690 } 691 return h.updateObject(ps, principal) 692 } 693 694 func (h *objectHandlers) deleteObjectDeprecated(params objects.ObjectsDeleteParams, 695 principal *models.Principal, 696 ) middleware.Responder { 697 h.logger.Warn("deprecated endpoint: ", "DELETE "+params.HTTPRequest.URL.Path) 698 ps := objects.ObjectsClassDeleteParams{ 699 HTTPRequest: params.HTTPRequest, 700 ID: params.ID, 701 } 702 return h.deleteObject(ps, principal) 703 } 704 705 func (h *objectHandlers) addObjectReferenceDeprecated(params objects.ObjectsReferencesCreateParams, 706 principal *models.Principal, 707 ) middleware.Responder { 708 h.logger.Warn("deprecated endpoint: ", "POST "+params.HTTPRequest.URL.Path) 709 req := objects.ObjectsClassReferencesCreateParams{ 710 HTTPRequest: params.HTTPRequest, 711 Body: params.Body, 712 ID: params.ID, 713 PropertyName: params.PropertyName, 714 } 715 return h.addObjectReference(req, principal) 716 } 717 718 func (h *objectHandlers) updateObjectReferencesDeprecated(params objects.ObjectsReferencesUpdateParams, 719 principal *models.Principal, 720 ) middleware.Responder { 721 h.logger.Warn("deprecated endpoint: ", "PUT "+params.HTTPRequest.URL.Path) 722 req := objects.ObjectsClassReferencesPutParams{ 723 HTTPRequest: params.HTTPRequest, 724 ID: params.ID, 725 PropertyName: params.PropertyName, 726 Body: params.Body, 727 } 728 return h.putObjectReferences(req, principal) 729 } 730 731 func (h *objectHandlers) deleteObjectReferenceDeprecated(params objects.ObjectsReferencesDeleteParams, 732 principal *models.Principal, 733 ) middleware.Responder { 734 h.logger.Warn("deprecated endpoint: ", "DELETE "+params.HTTPRequest.URL.Path) 735 req := objects.ObjectsClassReferencesDeleteParams{ 736 HTTPRequest: params.HTTPRequest, 737 Body: params.Body, 738 ID: params.ID, 739 PropertyName: params.PropertyName, 740 } 741 return h.deleteObjectReference(req, principal) 742 } 743 744 func (h *objectHandlers) extendPropertiesWithAPILinks(schema map[string]interface{}) map[string]interface{} { 745 if schema == nil { 746 return schema 747 } 748 749 for key, value := range schema { 750 asMultiRef, ok := value.(models.MultipleRef) 751 if !ok { 752 continue 753 } 754 755 schema[key] = h.extendReferencesWithAPILinks(asMultiRef) 756 } 757 return schema 758 } 759 760 func (h *objectHandlers) extendReferencesWithAPILinks(refs models.MultipleRef) models.MultipleRef { 761 for i, ref := range refs { 762 refs[i] = h.extendReferenceWithAPILink(ref) 763 } 764 765 return refs 766 } 767 768 func (h *objectHandlers) extendReferenceWithAPILink(ref *models.SingleRef) *models.SingleRef { 769 parsed, err := crossref.Parse(ref.Beacon.String()) 770 if err != nil { 771 // ignore return unchanged 772 return ref 773 } 774 href := fmt.Sprintf("%s/v1/objects/%s/%s", h.config.Origin, parsed.Class, parsed.TargetID) 775 if parsed.Class == "" { 776 href = fmt.Sprintf("%s/v1/objects/%s", h.config.Origin, parsed.TargetID) 777 } 778 ref.Href = strfmt.URI(href) 779 return ref 780 } 781 782 func (h *objectHandlers) shouldIncludeGetObjectsModuleParams() bool { 783 if h.modulesProvider == nil || !h.modulesProvider.HasMultipleVectorizers() { 784 return true 785 } 786 return false 787 } 788 789 type objectsRequestsTotal struct { 790 *restApiRequestsTotalImpl 791 } 792 793 func newObjectsRequestsTotal(metrics *monitoring.PrometheusMetrics, logger logrus.FieldLogger) restApiRequestsTotal { 794 return &objectsRequestsTotal{ 795 restApiRequestsTotalImpl: &restApiRequestsTotalImpl{newRequestsTotalMetric(metrics, "rest"), "rest", "objects", logger}, 796 } 797 } 798 799 func (e *objectsRequestsTotal) logError(className string, err error) { 800 switch err := err.(type) { 801 case uco.ErrMultiTenancy: 802 e.logUserError(className) 803 case errReplication, errUnregonizedProperty: 804 e.logUserError(className) 805 case autherrs.Forbidden: 806 e.logUserError(className) 807 case uco.ErrInvalidUserInput, uco.ErrNotFound: 808 e.logUserError(className) 809 case *uco.Error: 810 switch err.Code { 811 case uco.StatusInternalServerError: 812 e.logServerError(className, err) 813 default: 814 e.logUserError(className) 815 } 816 default: 817 if errors.As(err, &uco.ErrInvalidUserInput{}) || 818 errors.As(err, &uco.ErrMultiTenancy{}) || 819 errors.As(err, &autherrs.Forbidden{}) { 820 e.logUserError(className) 821 } else { 822 e.logServerError(className, err) 823 } 824 } 825 } 826 827 func parseIncludeParam(in *string, modulesProvider ModulesProvider, includeModuleParams bool, 828 class *models.Class, 829 ) (additional.Properties, error) { 830 out := additional.Properties{} 831 if in == nil { 832 return out, nil 833 } 834 835 parts := strings.Split(*in, ",") 836 837 for _, prop := range parts { 838 if prop == "classification" { 839 out.Classification = true 840 out.RefMeta = true 841 continue 842 } 843 if prop == "vector" { 844 out.Vector = true 845 continue 846 } 847 if includeModuleParams && modulesProvider != nil { 848 moduleParams := modulesProvider.RestApiAdditionalProperties(prop, class) 849 if len(moduleParams) > 0 { 850 out.ModuleParams = getModuleParams(out.ModuleParams) 851 for param, value := range moduleParams { 852 out.ModuleParams[param] = value 853 } 854 continue 855 } 856 } 857 return out, newErrUnregonizedProperty(fmt.Errorf("unrecognized property '%s' in ?include list", prop)) 858 } 859 860 return out, nil 861 } 862 863 func getModuleParams(moduleParams map[string]interface{}) map[string]interface{} { 864 if moduleParams == nil { 865 return map[string]interface{}{} 866 } 867 return moduleParams 868 } 869 870 func getReplicationProperties(consistencyLvl, nodeName *string) (*additional.ReplicationProperties, error) { 871 if nodeName == nil && consistencyLvl == nil { 872 return nil, nil 873 } 874 875 repl := additional.ReplicationProperties{} 876 if nodeName != nil { 877 repl.NodeName = *nodeName 878 } 879 880 cl, err := getConsistencyLevel(consistencyLvl) 881 if err != nil { 882 return nil, newErrReplication(err) 883 } 884 repl.ConsistencyLevel = cl 885 886 if repl.ConsistencyLevel != "" && repl.NodeName != "" { 887 return nil, newErrReplication(fmt.Errorf("consistency_level and node_name are mutually exclusive")) 888 } 889 890 return &repl, nil 891 } 892 893 func getConsistencyLevel(lvl *string) (string, error) { 894 if lvl != nil { 895 switch replica.ConsistencyLevel(*lvl) { 896 case replica.One, replica.Quorum, replica.All: 897 return *lvl, nil 898 default: 899 return "", fmt.Errorf("unrecognized consistency level '%v', "+ 900 "try one of the following: ['ONE', 'QUORUM', 'ALL']", *lvl) 901 } 902 } 903 904 return "", nil 905 } 906 907 func getTenant(maybeKey *string) string { 908 if maybeKey != nil { 909 return *maybeKey 910 } 911 return "" 912 } 913 914 func getClassName(obj *models.Object) string { 915 if obj != nil { 916 return obj.Class 917 } 918 return "" 919 } 920 921 type errReplication struct { 922 err error 923 } 924 925 func newErrReplication(err error) errReplication { 926 return errReplication{err} 927 } 928 929 func (e errReplication) Error() string { 930 return fmt.Sprintf("%v", e.err) 931 } 932 933 type errUnregonizedProperty struct { 934 err error 935 } 936 937 func newErrUnregonizedProperty(err error) errUnregonizedProperty { 938 return errUnregonizedProperty{err} 939 } 940 941 func (e errUnregonizedProperty) Error() string { 942 return fmt.Sprintf("%v", e.err) 943 }