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

adds error handling support #1100

Merged
merged 36 commits into from
Feb 10, 2022
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4bbef38
- adds support for builder getting error mappings
baywet Feb 1, 2022
d45a713
- adds support for creating the error mapping in executor method in C…
baywet Feb 2, 2022
b20bc66
- adds error mapping as parameter to http request adapter dotnet
baywet Feb 2, 2022
a04b2de
- adds missing throw error in http request adapter
baywet Feb 3, 2022
51421db
- adds a refiner to add the usings for exception and the inheritance
baywet Feb 3, 2022
34d330b
- adds error types as usings for error mappings
baywet Feb 3, 2022
42b92b8
- updates native response handler to pass the error mapping
baywet Feb 3, 2022
70ae1f0
- fixes an issue where CSharp error inheritance would try to hide ine…
baywet Feb 3, 2022
c1fc363
Apply suggestions from code review
baywet Feb 4, 2022
b40d59c
- adds error mapping parameter for java request adapter interface
baywet Feb 4, 2022
0cac5de
- implements errors deserialization for java
baywet Feb 4, 2022
fab35cb
- udpates class path
baywet Feb 4, 2022
a49bea7
- updates project settings
baywet Feb 4, 2022
21d6212
- adds exception inheritance in java refiner
baywet Feb 4, 2022
f534a36
- adds error mapping to java method code generation
baywet Feb 4, 2022
85424b8
- adds intermediate exception type for Java
baywet Feb 4, 2022
1c31f32
- adds intermediate exception type for CSharp
baywet Feb 4, 2022
3c3479c
- fixes error mapping declaration for inheritance
baywet Feb 4, 2022
5ef9313
- adds intermediat error type for typescript
baywet Feb 4, 2022
90c63b8
- implements error mapping in typescript code-generation
baywet Feb 4, 2022
3798eb5
- fixes error throw in typescript request adapter
baywet Feb 4, 2022
dbd72ec
- adds error mapping to go request adapter
baywet Feb 7, 2022
5cce319
- adds custom error type inheritance in go refiner
baywet Feb 7, 2022
90510cb
- adds missing parsable refrence to executor methods
baywet Feb 7, 2022
646690e
- fixes inheritance declarion for Go
baywet Feb 7, 2022
49c7ff0
- adds error mapping generation for Go
baywet Feb 7, 2022
11bb61e
- adds missing constructor for go api error
baywet Feb 7, 2022
1210f3e
- fixes go error deserialization
baywet Feb 7, 2022
638b949
- bumps version numbers for error handling
baywet Feb 7, 2022
5532a43
- updates documentation for error handling
baywet Feb 7, 2022
8ce76e0
- adds changelog entry for error management
baywet Feb 7, 2022
c9512ab
- moves method invocation for clarity
baywet Feb 7, 2022
3b5f7a3
- fixes error response implementation in java to avoid bypassing nati…
baywet Feb 7, 2022
5a74e8c
- changes ts api error to inheerit from the base error class
baywet Feb 9, 2022
9713b9c
- adds error prototype inheritance for typescript
baywet Feb 10, 2022
992d206
Update abstractions/typescript/src/nativeResponseHandler.ts
baywet Feb 10, 2022
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
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"cSpell.words": [
"npmrc",
"serializers"
]
],
"java.configuration.updateBuildConfiguration": "automatic"
}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Modified the TypeScript RequestInformation content data type to ArrayBuffer.
- Updated PHP abstractions to make property keys and values nullable in `SerializationWriter.php`.
- Fixed an issue where enum collections parsing would fail in Go.
- Breaking. Kiota clients generate error types and throw when the target API returns a failed response (dotnet, go, java, typescript). #1100

## [0.0.15] - 2021-12-17

Expand Down
26 changes: 26 additions & 0 deletions abstractions/dotnet/src/ApiException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// ------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
// ------------------------------------------------------------------------------
using System;

namespace Microsoft.Kiota.Abstractions;

/// <summary>
/// Parent type for exceptions thrown by the client when receiving failed responses to its requests.
/// </summary>
public class ApiException : Exception
{
/// <inheritdoc/>
public ApiException(): base()
{

}
/// <inheritdoc/>
public ApiException(string message) : base(message)
{
}
/// <inheritdoc/>
public ApiException(string message, Exception innerException) : base(message, innerException)
{
}
}
16 changes: 11 additions & 5 deletions abstractions/dotnet/src/IRequestAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
// ------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -29,41 +30,46 @@ public interface IRequestAdapter
/// </summary>
/// <param name="requestInfo">The RequestInformation object to use for the HTTP request.</param>
/// <param name="responseHandler">The response handler to use for the HTTP request instead of the default handler.</param>
/// <param name="errorMapping">The error factories mapping to use in case of a failed request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use for cancelling the requests.</param>
/// <returns>The deserialized response model.</returns>
Task<ModelType> SendAsync<ModelType>(RequestInformation requestInfo, IResponseHandler responseHandler = default, CancellationToken cancellationToken = default) where ModelType : IParsable;
Task<ModelType> SendAsync<ModelType>(RequestInformation requestInfo, IResponseHandler responseHandler = default, Dictionary<string, Func<IParsable>> errorMapping = default, CancellationToken cancellationToken = default) where ModelType : IParsable;
/// <summary>
/// Executes the HTTP request specified by the given RequestInformation and returns the deserialized response model collection.
/// </summary>
/// <param name="requestInfo">The RequestInformation object to use for the HTTP request.</param>
/// <param name="responseHandler">The response handler to use for the HTTP request instead of the default handler.</param>
/// <param name="errorMapping">The error factories mapping to use in case of a failed request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use for cancelling the requests.</param>
/// <returns>The deserialized response model collection.</returns>
Task<IEnumerable<ModelType>> SendCollectionAsync<ModelType>(RequestInformation requestInfo, IResponseHandler responseHandler = default, CancellationToken cancellationToken = default) where ModelType : IParsable;
Task<IEnumerable<ModelType>> SendCollectionAsync<ModelType>(RequestInformation requestInfo, IResponseHandler responseHandler = default, Dictionary<string, Func<IParsable>> errorMapping = default, CancellationToken cancellationToken = default) where ModelType : IParsable;
/// <summary>
/// Executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive response model.
/// </summary>
/// <param name="requestInfo">The RequestInformation object to use for the HTTP request.</param>
/// <param name="responseHandler">The response handler to use for the HTTP request instead of the default handler.</param>
/// <param name="errorMapping">The error factories mapping to use in case of a failed request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use for cancelling the requests.</param>
/// <returns>The deserialized primitive response model.</returns>
Task<ModelType> SendPrimitiveAsync<ModelType>(RequestInformation requestInfo, IResponseHandler responseHandler = default, CancellationToken cancellationToken = default);
Task<ModelType> SendPrimitiveAsync<ModelType>(RequestInformation requestInfo, IResponseHandler responseHandler = default, Dictionary<string, Func<IParsable>> errorMapping = default, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive response model collection.
/// </summary>
/// <param name="requestInfo">The RequestInformation object to use for the HTTP request.</param>
/// <param name="responseHandler">The response handler to use for the HTTP request instead of the default handler.</param>
/// <param name="errorMapping">The error factories mapping to use in case of a failed request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use for cancelling the requests.</param>
/// <returns>The deserialized primitive response model collection.</returns>
Task<IEnumerable<ModelType>> SendPrimitiveCollectionAsync<ModelType>(RequestInformation requestInfo, IResponseHandler responseHandler = default, CancellationToken cancellationToken = default);
Task<IEnumerable<ModelType>> SendPrimitiveCollectionAsync<ModelType>(RequestInformation requestInfo, IResponseHandler responseHandler = default, Dictionary<string, Func<IParsable>> errorMapping = default, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the HTTP request specified by the given RequestInformation with no return content.
/// </summary>
/// <param name="requestInfo">The RequestInformation object to use for the HTTP request.</param>
/// <param name="responseHandler">The response handler to use for the HTTP request instead of the default handler.</param>
/// <param name="errorMapping">The error factories mapping to use in case of a failed request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use for cancelling the requests.</param>
/// <returns>A Task to await completion.</returns>
Task SendNoContentAsync(RequestInformation requestInfo, IResponseHandler responseHandler = default, CancellationToken cancellationToken = default);
Task SendNoContentAsync(RequestInformation requestInfo, IResponseHandler responseHandler = default, Dictionary<string, Func<IParsable>> errorMapping = default, CancellationToken cancellationToken = default);
/// <summary>
/// The base url for every request.
/// </summary>
Expand Down
6 changes: 5 additions & 1 deletion abstractions/dotnet/src/IResponseHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// ------------------------------------------------------------------------------

using System.Threading.Tasks;
using System.Collections.Generic;
using System;
using Microsoft.Kiota.Abstractions.Serialization;

namespace Microsoft.Kiota.Abstractions
{
Expand All @@ -15,9 +18,10 @@ public interface IResponseHandler
/// Callback method that is invoked when a response is received.
/// </summary>
/// <param name="response">The native response object.</param>
/// <param name="errorMappings">The error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present.</param>
/// <typeparam name="NativeResponseType">The type of the native response object.</typeparam>
/// <typeparam name="ModelType">The type of the response model object.</typeparam>
/// <returns>A task that represents the asynchronous operation and contains the deserialized response.</returns>
Task<ModelType> HandleResponseAsync<NativeResponseType, ModelType>(NativeResponseType response);
Task<ModelType> HandleResponseAsync<NativeResponseType, ModelType>(NativeResponseType response, Dictionary<string, Func<IParsable>> errorMappings);
andrueastman marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<LangVersion>latest</LangVersion>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<RepositoryUrl>https://github.com/microsoft/kiota</RepositoryUrl>
<Version>1.0.28</Version>
<Version>1.0.29</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- Enable this line once we go live to prevent breaking changes -->
Expand Down
13 changes: 9 additions & 4 deletions abstractions/dotnet/src/NativeResponseHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// ------------------------------------------------------------------------------

using System.Threading.Tasks;
using System.Collections.Generic;
using System;
using Microsoft.Kiota.Abstractions.Serialization;

namespace Microsoft.Kiota.Abstractions
{
Expand All @@ -17,13 +20,15 @@ public class NativeResponseHandler : IResponseHandler
public object Value;

/// <summary>
/// Handles the response of type <typeparam name="NativeResponseType"/>and return an instance of <typeparam name="ModelType"/>
/// The error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present.
/// </summary>
/// <param name="response">The response to be handled</param>
/// <returns></returns>
public Task<ModelType> HandleResponseAsync<NativeResponseType, ModelType>(NativeResponseType response)
public Dictionary<string, Func<IParsable>> ErrorMappings { get; set; }

/// <inheritdoc />
public Task<ModelType> HandleResponseAsync<NativeResponseType, ModelType>(NativeResponseType response, Dictionary<string, Func<IParsable>> errorMappings)
{
Value = response;
ErrorMappings = errorMappings;
return Task.FromResult(default(ModelType));
}
}
Expand Down
6 changes: 6 additions & 0 deletions abstractions/dotnet/src/serialization/IParseNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ public interface IParseNode
/// <returns>The model object value of the node.</returns>
T GetObjectValue<T>() where T : IParsable;
/// <summary>
/// Gets the resulting error from the node.
/// </summary>
/// <returns>The error object value of the node.</returns>
/// <param name="factory">The error factory.</param>
IParsable GetErrorValue(Func<IParsable> factory);
/// <summary>
/// Callback called before the node is deserialized.
/// </summary>
Action<IParsable> OnBeforeAssignFieldValues { get; set; }
Expand Down
21 changes: 21 additions & 0 deletions abstractions/go/api_error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package abstractions

import "fmt"

// ApiError is the parent type for errors thrown by the client when receiving failed responses to its requests
type ApiError struct {
Message string
}

func (e *ApiError) Error() string {
if len(e.Message) > 0 {
return fmt.Sprint(e.Message)
} else {
return "error status code received from the API"
}
}

// NewApiError creates a new ApiError instance
func NewApiError() *ApiError {
jobala marked this conversation as resolved.
Show resolved Hide resolved
return &ApiError{}
}
13 changes: 8 additions & 5 deletions abstractions/go/request_adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ import (
s "github.com/microsoft/kiota/abstractions/go/serialization"
)

// ErrorMappings is a mapping of status codes to error types factories.
type ErrorMappings map[string]s.ParsableFactory
jobala marked this conversation as resolved.
Show resolved Hide resolved

// RequestAdapter is the service responsible for translating abstract RequestInformation into native HTTP requests.
type RequestAdapter interface {
// SendAsync executes the HTTP request specified by the given RequestInformation and returns the deserialized response model.
SendAsync(requestInfo RequestInformation, constructor func() s.Parsable, responseHandler ResponseHandler) (s.Parsable, error)
SendAsync(requestInfo RequestInformation, constructor s.ParsableFactory, responseHandler ResponseHandler, errorMappings ErrorMappings) (s.Parsable, error)
// SendCollectionAsync executes the HTTP request specified by the given RequestInformation and returns the deserialized response model collection.
SendCollectionAsync(requestInfo RequestInformation, constructor func() s.Parsable, responseHandler ResponseHandler) ([]s.Parsable, error)
SendCollectionAsync(requestInfo RequestInformation, constructor s.ParsableFactory, responseHandler ResponseHandler, errorMappings ErrorMappings) ([]s.Parsable, error)
// SendPrimitiveAsync executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive response model.
SendPrimitiveAsync(requestInfo RequestInformation, typeName string, responseHandler ResponseHandler) (interface{}, error)
SendPrimitiveAsync(requestInfo RequestInformation, typeName string, responseHandler ResponseHandler, errorMappings ErrorMappings) (interface{}, error)
// SendPrimitiveCollectionAsync executes the HTTP request specified by the given RequestInformation and returns the deserialized primitive response model collection.
SendPrimitiveCollectionAsync(requestInfo RequestInformation, typeName string, responseHandler ResponseHandler) ([]interface{}, error)
SendPrimitiveCollectionAsync(requestInfo RequestInformation, typeName string, responseHandler ResponseHandler, errorMappings ErrorMappings) ([]interface{}, error)
// SendNoContentAsync executes the HTTP request specified by the given RequestInformation with no return content.
SendNoContentAsync(requestInfo RequestInformation, responseHandler ResponseHandler) error
SendNoContentAsync(requestInfo RequestInformation, responseHandler ResponseHandler, errorMappings ErrorMappings) error
// GetSerializationWriterFactory returns the serialization writer factory currently in use for the request adapter service.
GetSerializationWriterFactory() s.SerializationWriterFactory
// EnableBackingStore enables the backing store proxies for the SerializationWriters and ParseNodes in use.
Expand Down
2 changes: 1 addition & 1 deletion abstractions/go/response_handler.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package abstractions

// ResponseHandler handler to implement when a request's response should be handled a specific way.
type ResponseHandler func(response interface{}) (interface{}, error)
type ResponseHandler func(response interface{}, errorMappings ErrorMappings) (interface{}, error)
3 changes: 3 additions & 0 deletions abstractions/go/serialization/parsable.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ type Parsable interface {
// IsNil returns whether the current object is nil or not.
IsNil() bool
}

// ParsableFactory is a factory for creating Parsable.
type ParsableFactory func() Parsable
2 changes: 1 addition & 1 deletion abstractions/java/lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ publishing {
publications {
gpr(MavenPublication) {
artifactId 'kiota-abstractions'
version '1.0.25'
version '1.0.26'
from(components.java)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.microsoft.kiota;

/** Parent type for exceptions thrown by the client when receiving failed responses to its requests. */
public class ApiException extends Exception {
/** {@inheritdoc} */
public ApiException() {
super();
}
/** {@inheritdoc} */
public ApiException(String message) {
super(message);
}
/** {@inheritdoc} */
public ApiException(String message, Throwable cause) {
super(message, cause);
}
/** {@inheritdoc} */
public ApiException(Throwable cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
package com.microsoft.kiota;

import java.util.HashMap;
import java.util.concurrent.CompletableFuture;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.microsoft.kiota.serialization.Parsable;

/** Default response handler to access the native response object. */
public class NativeResponseHandler implements ResponseHandler {
/** Native response object as returned by the core service */
@Nullable
public Object value;

/** The error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present. */
@Nullable
public HashMap<String, Class<? extends Parsable>> errorMappings;

/** {@inheritdoc} */
@Nonnull
@Override
public <NativeResponseType, ModelType> CompletableFuture<ModelType> handleResponseAsync(
NativeResponseType response) {
NativeResponseType response,
HashMap<String, Class<? extends Parsable>> errorMappings) {
this.value = response;
this.errorMappings = errorMappings;
return CompletableFuture.completedFuture(null);
}

Expand Down
Loading