docs: def patch_resource(self, session, json_data, api_type, obj_id):
          """
          Replacement of resource values.
  
          :param session: SQLAlchemy session
          :param json_data: Request JSON Data
          :param api_type: Type of the resource
          :param obj_id: ID of the resource
          """
          model = self._fetch_model(api_type)
          resource = self._fetch_resource(session, api_type, obj_id,
                                          Permissions.EDIT)
          self._check_json_data(json_data)
          orm_desc_keys = resource.__mapper__.all_orm_descriptors.keys()
  
          if not ({'type', 'id'} <= set(json_data['data'].keys())):
              raise BadRequestError('Missing type or id')
  
          if str(json_data['data']['id']) != str(resource.id):
              raise BadRequestError('IDs do not match')
  
          if json_data['data']['type'] != resource.__jsonapi_type__:
              raise BadRequestError('Type does not match')
  
          json_data['data'].setdefault('relationships', {})
          json_data['data'].setdefault('attributes', {})
  
          missing_keys = set(json_data['data'].get('relationships', {}).keys()) \
              - set(resource.__jsonapi_map_to_py__.keys())
  
          if missing_keys:
              raise BadRequestError(
                  '{} not relationships for {}.{}'.format(
                      ', '.join(list(missing_keys)),
                      model.__jsonapi_type__, resource.id))
  
          attrs_to_ignore = {'__mapper__', 'id'}
  
          session.add(resource)
  
          try:
              for key, relationship in resource.__mapper__.relationships.items():
                  api_key = resource.__jsonapi_map_to_api__[key]
                  attrs_to_ignore |= set(relationship.local_columns) | {key}
  
                  if api_key not in json_data['data']['relationships'].keys():
                      continue
  
                  self.patch_relationship(
                      session, json_data['data']['relationships'][api_key],
                      model.__jsonapi_type__, resource.id, api_key)
  
              data_keys = set(map((
                  lambda x: resource.__jsonapi_map_to_py__.get(x, None)),
                  json_data['data']['attributes'].keys()))
              model_keys = set(orm_desc_keys) - attrs_to_ignore
  
              if not data_keys <= model_keys:
                  raise BadRequestError(
                      '{} not attributes for {}.{}'.format(
                          ', '.join(list(data_keys - model_keys)),
                          model.__jsonapi_type__, resource.id))
  
              for key in data_keys & model_keys:
                  setter = get_attr_desc(resource, key, AttributeActions.SET)
                  setter(resource, json_data['data']['attributes'][resource.__jsonapi_map_to_api__[key]])  # NOQA
              session.commit()
          except IntegrityError as e:
              session.rollback()
              raise ValidationError(str(e.orig))
          except AssertionError as e:
              # pragma: no cover
              session.rollback()
              raise ValidationError(e.msg)
          except TypeError as e:
              session.rollback()
              raise ValidationError('Incompatible data type')
          return self.get_resource(
              session, {}, model.__jsonapi_type__, resource.id)