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  }