Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generated models and request builders #2163

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.microsoft.graph.applications.item.restore;

import com.microsoft.kiota.serialization.AdditionalDataHolder;
import com.microsoft.kiota.serialization.Parsable;
import com.microsoft.kiota.serialization.ParseNode;
import com.microsoft.kiota.serialization.SerializationWriter;
import com.microsoft.kiota.store.BackedModel;
import com.microsoft.kiota.store.BackingStore;
import com.microsoft.kiota.store.BackingStoreFactorySingleton;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@jakarta.annotation.Generated("com.microsoft.kiota")
public class RestorePostRequestBody implements AdditionalDataHolder, BackedModel, Parsable {
/**
* Stores model information.
*/
@jakarta.annotation.Nonnull
protected BackingStore backingStore;
/**
* Instantiates a new {@link RestorePostRequestBody} and sets the default values.
*/
public RestorePostRequestBody() {
this.backingStore = BackingStoreFactorySingleton.instance.createBackingStore();
this.setAdditionalData(new HashMap<>());
}
/**
* Creates a new instance of the appropriate class based on discriminator value
* @param parseNode The parse node to use to read the discriminator value and create the object
* @return a {@link RestorePostRequestBody}
*/
@jakarta.annotation.Nonnull
public static RestorePostRequestBody createFromDiscriminatorValue(@jakarta.annotation.Nonnull final ParseNode parseNode) {
Objects.requireNonNull(parseNode);
return new RestorePostRequestBody();
}
/**
* Gets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.
* @return a {@link Map<String, Object>}
*/
@jakarta.annotation.Nonnull
public Map<String, Object> getAdditionalData() {
Map<String, Object> value = this.backingStore.get("additionalData");
if(value == null) {
value = new HashMap<>();
this.setAdditionalData(value);
}
return value;
}
/**
* Gets the autoReconcileProxyConflict property value. The autoReconcileProxyConflict property
* @return a {@link Boolean}
*/
@jakarta.annotation.Nullable
public Boolean getAutoReconcileProxyConflict() {
return this.backingStore.get("autoReconcileProxyConflict");
}
/**
* Gets the backingStore property value. Stores model information.
* @return a {@link BackingStore}
*/
@jakarta.annotation.Nonnull
public BackingStore getBackingStore() {
return this.backingStore;
}
/**
* The deserialization information for the current model
* @return a {@link Map<String, java.util.function.Consumer<ParseNode>>}
*/
@jakarta.annotation.Nonnull
public Map<String, java.util.function.Consumer<ParseNode>> getFieldDeserializers() {
final HashMap<String, java.util.function.Consumer<ParseNode>> deserializerMap = new HashMap<String, java.util.function.Consumer<ParseNode>>(1);
deserializerMap.put("autoReconcileProxyConflict", (n) -> { this.setAutoReconcileProxyConflict(n.getBooleanValue()); });
return deserializerMap;
}
/**
* Serializes information the current object
* @param writer Serialization writer to use to serialize this model
*/
public void serialize(@jakarta.annotation.Nonnull final SerializationWriter writer) {
Objects.requireNonNull(writer);
writer.writeBooleanValue("autoReconcileProxyConflict", this.getAutoReconcileProxyConflict());
writer.writeAdditionalData(this.getAdditionalData());
}
/**
* Sets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.
* @param value Value to set for the AdditionalData property.
*/
public void setAdditionalData(@jakarta.annotation.Nullable final Map<String, Object> value) {
this.backingStore.set("additionalData", value);
}
/**
* Sets the autoReconcileProxyConflict property value. The autoReconcileProxyConflict property
* @param value Value to set for the autoReconcileProxyConflict property.
*/
public void setAutoReconcileProxyConflict(@jakarta.annotation.Nullable final Boolean value) {
this.backingStore.set("autoReconcileProxyConflict", value);
}
/**
* Sets the backingStore property value. Stores model information.
* @param value Value to set for the backingStore property.
*/
public void setBackingStore(@jakarta.annotation.Nonnull final BackingStore value) {
Objects.requireNonNull(value);
this.backingStore = value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,47 +36,54 @@ public RestoreRequestBuilder(@jakarta.annotation.Nonnull final String rawUrl, @j
super(requestAdapter, "{+baseurl}/applications/{application%2Did}/restore", rawUrl);
}
/**
* Restore a recently deleted application, group, servicePrincipal, administrative unit, or user object from deleted items. If an item was accidentally deleted, you can fully restore the item. However, security groups cannot be restored. Also, restoring an application doesn't restore the associated service principal automatically. You must call this API to explicitly restore the deleted service principal. A recently deleted item remains available for up to 30 days. After 30 days, the item is permanently deleted.
* Restore a recently deleted application, group, servicePrincipal, administrative unit, or user object from deleted items. If an item was accidentally deleted, you can fully restore the item. However, security groups can't be restored. Also, restoring an application doesn't restore the associated service principal automatically. You must call this API to explicitly restore the deleted service principal. A recently deleted item remains available for up to 30 days. After 30 days, the item is permanently deleted.
* @param body The request body
* @return a {@link DirectoryObject}
* @throws ODataError When receiving a 4XX or 5XX status code
* @see <a href="https://learn.microsoft.com/graph/api/directory-deleteditems-restore?view=graph-rest-1.0">Find more info here</a>
*/
@jakarta.annotation.Nullable
public DirectoryObject post() {
return post(null);
public DirectoryObject post(@jakarta.annotation.Nonnull final RestorePostRequestBody body) {
return post(body, null);
}
/**
* Restore a recently deleted application, group, servicePrincipal, administrative unit, or user object from deleted items. If an item was accidentally deleted, you can fully restore the item. However, security groups cannot be restored. Also, restoring an application doesn't restore the associated service principal automatically. You must call this API to explicitly restore the deleted service principal. A recently deleted item remains available for up to 30 days. After 30 days, the item is permanently deleted.
* Restore a recently deleted application, group, servicePrincipal, administrative unit, or user object from deleted items. If an item was accidentally deleted, you can fully restore the item. However, security groups can't be restored. Also, restoring an application doesn't restore the associated service principal automatically. You must call this API to explicitly restore the deleted service principal. A recently deleted item remains available for up to 30 days. After 30 days, the item is permanently deleted.
* @param body The request body
* @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
* @return a {@link DirectoryObject}
* @throws ODataError When receiving a 4XX or 5XX status code
* @see <a href="https://learn.microsoft.com/graph/api/directory-deleteditems-restore?view=graph-rest-1.0">Find more info here</a>
*/
@jakarta.annotation.Nullable
public DirectoryObject post(@jakarta.annotation.Nullable final java.util.function.Consumer<PostRequestConfiguration> requestConfiguration) {
final RequestInformation requestInfo = toPostRequestInformation(requestConfiguration);
public DirectoryObject post(@jakarta.annotation.Nonnull final RestorePostRequestBody body, @jakarta.annotation.Nullable final java.util.function.Consumer<PostRequestConfiguration> requestConfiguration) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flagged breaking changes seem to be a bug fix to allow posting a body.

cc; @baywet @andrueastman

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first question: how did you spot it? was the new workflow any help?

then, from the docs, it seems the service supports BOTH sending or not sending a body.
our XSLT doesn't have any modification for this, and the parameter is optional

<Action Name="restore" IsBound="true">
        <Parameter Name="bindingParameter" Type="graph.directoryObject" Nullable="false" />
        <Parameter Name="autoReconcileProxyConflict" Type="Edm.Boolean">
          <Annotation Term="Org.OData.Core.V1.OptionalParameter" />
        </Parameter>
        <ReturnType Type="graph.directoryObject" />
      </Action>

The workload added the new optional parameter to existing actions. (default for nullable is true when not specified)

This is what OAS we have for this operation since the change:

  '/directory/deletedItems/{directoryObject-id}/restore':
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                autoReconcileProxyConflict:
                  type: boolean
                  default: false
                  nullable: true
        required: true

And we're missing information here from a strict OpenAPI perspective.

It should instead be

  '/directory/deletedItems/{directoryObject-id}/restore':
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                autoReconcileProxyConflict:
                  type: boolean
                  default: false
                  nullable: true
        required: true
+          */*:
+            schema:
+              type: null

But even if we fixed that in yoko, kiota would probably ignore this second entry as is. Even if we fixed that, we'd then need to add overloads in the code dom, and make sure they translate well in every language. (e.g. in typescript, it wouldn't be an overload, but an optional parameter instead).

These are a big set of changes that need to be coordinated across the board. And I'd like to get @darrelmiller to validate my analysis here first.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type: null is not allowed in OpenAPI 3.0, so that isn't an option. https://spec.openapis.org/oas/v3.0.3.html#data-types

Maybe I am missing something here, but isn't the solution to set requestBody.required = false when all of the properties of the request payload are optional?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right now kiota is not considering this field, but we could vary based on that, and if the body is NOT required, in the context of Java, project an overload without the body parameter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first question: how did you spot it? was the new workflow any help?

Yes. Related to comment that is also at microsoftgraph/msgraph-sdk-dotnet#2671 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created this for now microsoft/OpenAPI.NET.OData#582

Thinking about this a bit more though, if a required parameter is added to this specific action for example, wouldn't we still have a similar problem? The request body would now become required making the optional overloads "dissappear".

From the generation perspective, would it make sense to always generate a requestBody parameter and have the marshalling not send anything in the scenario with an empty payload/object?

Copy link
Contributor

@Ndiritu Ndiritu Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't adding a required property to a previously optional body be a breaking change on the API side? And if an API is happy with that, then the SDKs should reflect the breaking change?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, adding a required parameter to an action is a breaking change at the API level. This is why I didn't consider this scenario.
We'd still have a potential breaking change though in the current scenario if we use optional parameters in the language. I'm not sure there's a solution to that besides not using optimal parameters which comes with duplication etc...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from the meeting today: we could/should patch the metadata in the XSLT in the meanwhile so we don't block all the releases. @Ndiritu can you create in an issue in the metadata repo so the work is prioritized please?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Objects.requireNonNull(body);
final RequestInformation requestInfo = toPostRequestInformation(body, requestConfiguration);
final HashMap<String, ParsableFactory<? extends Parsable>> errorMapping = new HashMap<String, ParsableFactory<? extends Parsable>>();
errorMapping.put("XXX", ODataError::createFromDiscriminatorValue);
return this.requestAdapter.send(requestInfo, errorMapping, DirectoryObject::createFromDiscriminatorValue);
}
/**
* Restore a recently deleted application, group, servicePrincipal, administrative unit, or user object from deleted items. If an item was accidentally deleted, you can fully restore the item. However, security groups cannot be restored. Also, restoring an application doesn't restore the associated service principal automatically. You must call this API to explicitly restore the deleted service principal. A recently deleted item remains available for up to 30 days. After 30 days, the item is permanently deleted.
* Restore a recently deleted application, group, servicePrincipal, administrative unit, or user object from deleted items. If an item was accidentally deleted, you can fully restore the item. However, security groups can't be restored. Also, restoring an application doesn't restore the associated service principal automatically. You must call this API to explicitly restore the deleted service principal. A recently deleted item remains available for up to 30 days. After 30 days, the item is permanently deleted.
* @param body The request body
* @return a {@link RequestInformation}
*/
@jakarta.annotation.Nonnull
public RequestInformation toPostRequestInformation() {
return toPostRequestInformation(null);
public RequestInformation toPostRequestInformation(@jakarta.annotation.Nonnull final RestorePostRequestBody body) {
return toPostRequestInformation(body, null);
}
/**
* Restore a recently deleted application, group, servicePrincipal, administrative unit, or user object from deleted items. If an item was accidentally deleted, you can fully restore the item. However, security groups cannot be restored. Also, restoring an application doesn't restore the associated service principal automatically. You must call this API to explicitly restore the deleted service principal. A recently deleted item remains available for up to 30 days. After 30 days, the item is permanently deleted.
* Restore a recently deleted application, group, servicePrincipal, administrative unit, or user object from deleted items. If an item was accidentally deleted, you can fully restore the item. However, security groups can't be restored. Also, restoring an application doesn't restore the associated service principal automatically. You must call this API to explicitly restore the deleted service principal. A recently deleted item remains available for up to 30 days. After 30 days, the item is permanently deleted.
* @param body The request body
* @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
* @return a {@link RequestInformation}
*/
@jakarta.annotation.Nonnull
public RequestInformation toPostRequestInformation(@jakarta.annotation.Nullable final java.util.function.Consumer<PostRequestConfiguration> requestConfiguration) {
public RequestInformation toPostRequestInformation(@jakarta.annotation.Nonnull final RestorePostRequestBody body, @jakarta.annotation.Nullable final java.util.function.Consumer<PostRequestConfiguration> requestConfiguration) {
Objects.requireNonNull(body);
final RequestInformation requestInfo = new RequestInformation(HttpMethod.POST, urlTemplate, pathParameters);
requestInfo.configure(requestConfiguration, PostRequestConfiguration::new);
requestInfo.headers.tryAdd("Accept", "application/json");
requestInfo.setContentFromParsable(requestAdapter, "application/json", body);
return requestInfo;
}
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,21 @@ public void delete(@jakarta.annotation.Nullable final java.util.function.Consume
this.requestAdapter.sendPrimitive(requestInfo, errorMapping, Void.class);
}
/**
* Retrieve a conversationMember from a chat or channel.
* Retrieve a conversationMember from a chat.
* @return a {@link ConversationMember}
* @throws ODataError When receiving a 4XX or 5XX status code
* @see <a href="https://learn.microsoft.com/graph/api/conversationmember-get?view=graph-rest-1.0">Find more info here</a>
* @see <a href="https://learn.microsoft.com/graph/api/chat-get-members?view=graph-rest-1.0">Find more info here</a>
*/
@jakarta.annotation.Nullable
public ConversationMember get() {
return get(null);
}
/**
* Retrieve a conversationMember from a chat or channel.
* Retrieve a conversationMember from a chat.
* @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
* @return a {@link ConversationMember}
* @throws ODataError When receiving a 4XX or 5XX status code
* @see <a href="https://learn.microsoft.com/graph/api/conversationmember-get?view=graph-rest-1.0">Find more info here</a>
* @see <a href="https://learn.microsoft.com/graph/api/chat-get-members?view=graph-rest-1.0">Find more info here</a>
*/
@jakarta.annotation.Nullable
public ConversationMember get(@jakarta.annotation.Nullable final java.util.function.Consumer<GetRequestConfiguration> requestConfiguration) {
Expand Down Expand Up @@ -126,15 +126,15 @@ public RequestInformation toDeleteRequestInformation(@jakarta.annotation.Nullabl
return requestInfo;
}
/**
* Retrieve a conversationMember from a chat or channel.
* Retrieve a conversationMember from a chat.
* @return a {@link RequestInformation}
*/
@jakarta.annotation.Nonnull
public RequestInformation toGetRequestInformation() {
return toGetRequestInformation(null);
}
/**
* Retrieve a conversationMember from a chat or channel.
* Retrieve a conversationMember from a chat.
* @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
* @return a {@link RequestInformation}
*/
Expand Down Expand Up @@ -186,7 +186,7 @@ public ConversationMemberItemRequestBuilder withUrl(@jakarta.annotation.Nonnull
public class DeleteRequestConfiguration extends BaseRequestConfiguration {
}
/**
* Retrieve a conversationMember from a chat or channel.
* Retrieve a conversationMember from a chat.
*/
@jakarta.annotation.Generated("com.microsoft.kiota")
public class GetQueryParameters implements QueryParameters {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,23 +93,23 @@ public ChatMessageCollectionResponse get(@jakarta.annotation.Nullable final java
return this.requestAdapter.send(requestInfo, errorMapping, ChatMessageCollectionResponse::createFromDiscriminatorValue);
}
/**
* Send a new chatMessage in the specified channel or a chat.
* Send a new chatMessage in the specified chat. This API can't create a new chat; you must use the list chats method to retrieve the ID of an existing chat before you can create a chat message.
* @param body The request body
* @return a {@link ChatMessage}
* @throws ODataError When receiving a 4XX or 5XX status code
* @see <a href="https://learn.microsoft.com/graph/api/chatmessage-post?view=graph-rest-1.0">Find more info here</a>
* @see <a href="https://learn.microsoft.com/graph/api/chat-post-messages?view=graph-rest-1.0">Find more info here</a>
*/
@jakarta.annotation.Nullable
public ChatMessage post(@jakarta.annotation.Nonnull final ChatMessage body) {
return post(body, null);
}
/**
* Send a new chatMessage in the specified channel or a chat.
* Send a new chatMessage in the specified chat. This API can't create a new chat; you must use the list chats method to retrieve the ID of an existing chat before you can create a chat message.
* @param body The request body
* @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
* @return a {@link ChatMessage}
* @throws ODataError When receiving a 4XX or 5XX status code
* @see <a href="https://learn.microsoft.com/graph/api/chatmessage-post?view=graph-rest-1.0">Find more info here</a>
* @see <a href="https://learn.microsoft.com/graph/api/chat-post-messages?view=graph-rest-1.0">Find more info here</a>
*/
@jakarta.annotation.Nullable
public ChatMessage post(@jakarta.annotation.Nonnull final ChatMessage body, @jakarta.annotation.Nullable final java.util.function.Consumer<PostRequestConfiguration> requestConfiguration) {
Expand Down Expand Up @@ -140,7 +140,7 @@ public RequestInformation toGetRequestInformation(@jakarta.annotation.Nullable f
return requestInfo;
}
/**
* Send a new chatMessage in the specified channel or a chat.
* Send a new chatMessage in the specified chat. This API can't create a new chat; you must use the list chats method to retrieve the ID of an existing chat before you can create a chat message.
* @param body The request body
* @return a {@link RequestInformation}
*/
Expand All @@ -149,7 +149,7 @@ public RequestInformation toPostRequestInformation(@jakarta.annotation.Nonnull f
return toPostRequestInformation(body, null);
}
/**
* Send a new chatMessage in the specified channel or a chat.
* Send a new chatMessage in the specified chat. This API can't create a new chat; you must use the list chats method to retrieve the ID of an existing chat before you can create a chat message.
* @param body The request body
* @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
* @return a {@link RequestInformation}
Expand Down
Loading
Loading