Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

501 Error on Update #73

Closed
rafaelferrari opened this issue May 7, 2019 · 11 comments
Closed

501 Error on Update #73

rafaelferrari opened this issue May 7, 2019 · 11 comments

Comments

@rafaelferrari
Copy link

rafaelferrari commented May 7, 2019

Hello colleagues,

We are working with the Change Master API and we are having some issues updating the status.

We are calling the API as:

this.defaultChangeMasterService
.updateAPIForChangeNumber(changeMaster)
.execute(getConfigContext())

While debugging, we could validate that changemaster is set as:

APIForChangeNumber(super=VdmObject(customFields={}, changedOriginalFields={Status=2}), changeNumber=12345, status=1, authorizationGroup=, function=, relTechnically=, releaseKey=0, reasonForChange=123, description=123, validFrom=9999-01-01T00:00, createdOn=2019-05-07T00:00, createdBy=SCP_RFC, changedOn=null, changedBy=, inUse=false, deletionFlag=false, timeStamp=1972-04-01T00:00Z[GMT], toAlternativeDate=null, toChangeMstrObjectMgmtRecord=null, toChangeMstrObMgReDocInfoRecd=null, toChangeMstrObMgReMaterial=null, toChangeMstrObMgReMatlBOM=null, toCharacteristics=null, toClassification=null, toObjTypeAssignment=null)

However, we get HTTP 501 error with the message:

The endpoint responded with HTTP error code 501.
PATCH requests require components to be updated
Full error message: 
{
"error": {
"code": "/IWFND/CM_MGW/096",
"message": {
"lang": "en",
"value": "PATCH requests require components to be updated"
},
"innererror": {
"application": {
"component_id": "PLM-WUI-OBJ-ECN",
"service_namespace": "/SAP/",
"service_id": "API_CHANGEMASTER",
"service_version": "0002"
},
"transactionid": "83...10",
"timestamp": "20190507201621.8351780",
"Error_Resolution": {
"SAP_Transaction": "For backend administrators: run transaction /IWFND/ERROR_LOG on SAP Gateway hub system and search for entries with the timestamp above for more details",
"SAP_Note": "See SAP Note 1797736 for error analysis (https://service.sap.com/sap/support/notes/1797736)"
},
"errordetails": []
}
}
}

Do you see anything that we could be doing wrong? When we try calling the API using Postman it works fine. Let me know if there's any additional info that we could provide you.

Thanks,
Rafael

@cschubertcs
Copy link

Hi Rafael,

how does your Postman call look like?
Looking at your APIForChangeNumber object the PATCH request body should only contain the key values as well as the Status field (as it was apparently the only changed field).

Another alternative (introduced with version 2.16.0) is using the replacingEntity() modifier in the call chain. This would send the whole object in a PUT request.

Greetings
Chris

@rafaelferrari
Copy link
Author

rafaelferrari commented May 8, 2019

Hi Chris, thanks for the response!

On Postman I'm doing a PATCH /API_ChangeMaster;v=2/A_ChangeMaster('12345').
With the headers Content-Type: application/json, If-Match: * and x-csrf-token set from previous authorization. It works fine and we can check that the changes are commited.

The body of my request looks like:

{
  "d": {
    "ChangeNumberStatus": "1"
  }
}

I'll try to run it with the replacingEntity that you mentioned, I'll let you know how it goes.

Greetings,
Rafael

@rafaelferrari
Copy link
Author

Hi Chris,

We've tested it and the replacingEntity() approach is working as expected.

Thanks for the help! 😄

@cschubertcs
Copy link

Hi Rafael,

one question that came up during further investigation of the issue: which version where you using when the initial problem occurred? Currently we cannot reproduce the behavior with PATCH, neither with 2.16.0 nor with 2.8.1 (some arbitrarily chosen old version).

Greetings
Chris

@rafaelferrari
Copy link
Author

Hi Chris,

We were using version 2.13.2 before. I ran into the same problem with PATCH after updating to 2.16.0, but the PUT approach has solved our problems for now.

Greetings,
Rafael

@JerryZhang0929
Copy link

Hello Rafael,

I ran into the same issue. Could you please share what is your request payload and how you can set attributes to {changedOriginalFields={Status=2}}?

@akhil-agarwal
Copy link

Hi Rafael,

While we get to its root cause and potential resolution, we would like to seek some more information.

We understand that in your request payload

{
    "ChangeNumberStatus": "1"
}

The field "ChangeNumberStatus" is actually not modified. That is, its value is the same as that of the persisted Business Partner entity.

Is this correct?

If so, would it be possible for you to let us know what is the business use case here?

Best regards,
Akhil

@talesdv
Copy link

talesdv commented May 27, 2019

Hi Akhil and all, I'm working with Rafael on this issue.

We were using the builder from APIForChangeNumber to set the properties we wanted to change in S/4 Change Master using PATCH. The problem is that the entity's changedOriginalFields map never change if you set the properties with the builder, therefore the VdmObject::getChangedFields always return empty, thus failing to serialize the fields when processing the PATCH request.

To workaround this behavior, we created a wrapper for APIForChangeNumber to work like a builder, but instead of using the actual builder, this wrapper calls the corresponding set*** method, which ultimately calls the rememberChangedField, registering the field in changedOriginalFields to be considered when PATCHing. But then we faced another issue: the set*** method is registering the field with the property label, not the property name. Then again, VdmObject::getChangedFields won't recognize the field as changed, ignoring it in the PATCH request.

Is that the correct behavior? It seems APIForChangeNumber should expose the methods with label (e.g. setDescription) names, but then internally the field should be registered with the actual name (e.g. ChangeNumberDescription). BTW the nameSource configuration in our pom is set to LABEL (default value).

In case it helps, below is the SDK-generated method on APIForChangeNumber to set the description. It seems the rememberChangedField should be registered with "ChangeNumberDescription".

    /**
     * Constraints: Not nullable, Maximum length: 40 <p>Original property name from the Odata EDM: <b>ChangeNumberDescription</b></p>
     * 
     * @param description
     *     Change number description
     */
    public void setDescription(
        @Nullable
        final String description) {
        rememberChangedField("Description", this.description);
        this.description = description;
    }

Thank you for your help and regards,
Tales Vecchia.

@cschubertcs
Copy link

Hi Tales,

thanks for your response!

The issue with the wrong key in the changedOriginalField map is fixed with version 2.17.0. With this it should always take the name of the field in the Service.

Regarding your workaround: The expected usage of the updateChangedFields (so sending only changed fields via PATCH) is that you retrieve the entity from the S/4 System and update the properties via the set methods. If you create the entity locally via the builder we cannot know which value the properties on the system have (without executing an Http call silently, which we do not want to do).
For me it sounds like you want to create an entity manually which already exists on the system and then trying to update it. This sounds like the perfect use case for the replaceEntity (so the PUT) method.

I hope this clears the issue up!

Greetings
Chris

@talesdv
Copy link

talesdv commented May 28, 2019

Hi Chris,
Thank you for your quick and complete response!

We verified that indeed the 2.17.0 version fixed the property naming issue.

Regarding the PATCH API, we didn't want to perform a GET just to update the entity, since in our case the synchronization is one-way (i.e. object won't be changed in S/4 directly). It seems we'll be able to achieve this with version 2.17.0, calling the API with ignoreVersionIdentifier.

Thank you again for your help.
Tales Vecchia.

@cschubertcs
Copy link

Hi Tales,
good to hear that the actual issue is fixed!

The ignoreVersionIdentifier approach feels a bit "hacky". So from my side it really sounds like you want to set all values of the entity, which would be the exact use case for replaceEntity.
So you would call

this.defaultChangeMasterService
.updateAPIForChangeNumber(changeMaster)
.replaceEntity()
.execute(getConfigContext());

instead of

this.defaultChangeMasterService
.updateAPIForChangeNumber(changeMaster)
.execute(getConfigContext());

as updateEntity is the default behavior.

Greetings
Chris

@sacnl sacnl closed this as completed Aug 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants