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 support for url templating #683

Merged
merged 38 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
96488d0
- switches to url templates for dotnet generation
baywet Oct 5, 2021
de6b364
- fixes wrong expected url value
baywet Oct 5, 2021
428976a
- adds support for query string parameters in url templates
baywet Oct 6, 2021
9758577
- adds mapping to url template parameter name for go, java, ruby, and…
baywet Oct 6, 2021
47e0c27
- assigns path parameters in constructor for dotnet
baywet Oct 6, 2021
642c06c
- fixes parameters validation casing
baywet Oct 7, 2021
df299c4
- adds support for raw urls in dotnet
baywet Oct 7, 2021
eab4c5a
- adds support for url templating in java
baywet Oct 7, 2021
83f680e
- fixes java parameters casing issue
baywet Oct 7, 2021
2841416
- additional casing corrections for java
baywet Oct 7, 2021
df62913
- adds support for url template in typescript
baywet Oct 8, 2021
eadfa09
- fixes a bug where path paremeters could be undefined in typescript …
baywet Oct 8, 2021
9d7d49b
- fixes a casing convention for typescript parameters
baywet Oct 8, 2021
8d7a589
- fixes enum collections serialization for typescript
baywet Oct 8, 2021
2cdad56
- adds support for url template for go
baywet Oct 12, 2021
651bd5d
- adds missing path parameters conversions in go
baywet Oct 12, 2021
7cf09fc
- fixes raw url convention in go
baywet Oct 12, 2021
906e167
- fixes a bug where methods writer order would not be deterministic a…
baywet Oct 20, 2021
0105bb6
- fixes a bug where typescript import writing would not be deterministic
baywet Oct 20, 2021
88ea934
- renames url template parameters to path parameters as requested by …
baywet Oct 20, 2021
73bfd78
- updates path parameter description after rename
baywet Oct 20, 2021
ebd8bc2
- fixes unit tests for code element comparer
baywet Oct 20, 2021
b4210ef
- adds support for url template parameters in ruby abstractions
baywet Oct 20, 2021
b8dd9d3
- adds support for url template in ruby
baywet Oct 20, 2021
36700f7
- code-linting
baywet Oct 20, 2021
f6fb310
- fixes cleanup task path
baywet Oct 21, 2021
a808ba2
- adds unit test for url template changes
baywet Oct 21, 2021
ad5beb3
- adds changelog entry for url template change
baywet Oct 21, 2021
2b408dd
- bumps path version for url template change
baywet Oct 21, 2021
28e923c
Apply suggestions from code review
baywet Oct 22, 2021
bf33bfe
- renames close curly method as suggested during review
baywet Oct 22, 2021
dfe5083
- adds path parameter to url template test
baywet Oct 22, 2021
994ca8e
- refactors temp var name definition accross languages conventions
baywet Oct 22, 2021
523594d
Merge branch 'main' into feature/url-template
baywet Oct 22, 2021
6ae5ccc
Merge branch 'main' into feature/url-template
baywet Oct 25, 2021
e1db240
- changes the path parameters map type to accept a broader set of arg…
baywet Oct 25, 2021
2d571a1
Merge branch 'main' into feature/url-template
baywet Oct 26, 2021
26e21b1
Fix for broken test
andrueastman Oct 27, 2021
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
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"command": "powershell",
"args": [
"-command",
"Remove-Item -Recurse -Include TestResults -Path tests"
"Remove-Item -Recurse -Include TestResults -Path ${workspaceFolder}/tests"
]
}
},
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Switched to URL templates instead of string contract for URL building #683
- Fixed a bug where CSharp method names would not follow naming conventions #730

## [0.0.10] - 2021-10-06

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public void SetsSelectQueryParameters()
var requestInfo = new RequestInformation
{
HttpMethod = HttpMethod.GET,
UrlTemplate = "http://localhost/me?select={select}"
};
requestInfo.SetURI("http://localhost/me", "", true);
Action<GetQueryParameters> q = x => x.Select = new[] { "id", "displayName" };
var qParams = new GetQueryParameters();
q.Invoke(qParams);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,20 @@ namespace Microsoft.Kiota.Abstractions.Tests
{
public class RequestInformationTests
{
[Fact]
public void SetUriAppendsUrlSegments()
{
// Arrange
var testRequest = new RequestInformation()
{
HttpMethod = HttpMethod.GET,
URI = new Uri("http://localhost")
};
// Act
testRequest.SetURI(testRequest.URI.OriginalString,"/me",false);
// Assert
Assert.Equal("http://localhost/me", testRequest.URI.OriginalString);
}

[Fact]
public void SetUriExtractsQueryParameters()
{
// Arrange
var testRequest = new RequestInformation()
{
HttpMethod = HttpMethod.GET,
URI = new Uri("http://localhost")
UrlTemplate = "http://localhost/{path}/me?foo={foo}"
};
// Act
testRequest.SetURI("http://localhost/me?foo=bar", "", true);
testRequest.QueryParameters.Add("foo", "bar");
baywet marked this conversation as resolved.
Show resolved Hide resolved
testRequest.PathParameters.Add("path", "baz");
// Assert
Assert.Equal("http://localhost/me", testRequest.URI.OriginalString);
Assert.Equal("http://localhost/baz/me?foo=bar", testRequest.URI.ToString());
Assert.NotEmpty(testRequest.QueryParameters);
Assert.Equal("foo",testRequest.QueryParameters.First().Key);
Assert.Equal("bar", testRequest.QueryParameters.First().Value.ToString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
<TargetFramework>net5.0</TargetFramework>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<RepositoryUrl>https://github.com/microsoft/kiota</RepositoryUrl>
<Version>1.0.21</Version>
<Version>1.0.22</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- Enable this line once we go live to prevent breaking changes -->
<!-- <PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion> -->
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Tavis.UriTemplates" Version="1.1.1" />
</ItemGroup>

</Project>
67 changes: 44 additions & 23 deletions abstractions/dotnet/src/RequestInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.IO;
using System.Linq;
using Microsoft.Kiota.Abstractions.Serialization;
using Tavis.UriTemplates;

namespace Microsoft.Kiota.Abstractions
{
Expand All @@ -15,36 +16,56 @@ namespace Microsoft.Kiota.Abstractions
/// </summary>
public class RequestInformation
{
private Uri _rawUri;
/// <summary>
/// The URI of the request.
/// </summary>
public Uri URI { get; set; }
/// <summary>
/// Sets the URI of the request.
/// </summary>
/// <param name="currentPath">the current path (scheme, host, port, path, query parameters) of the request.</param>
/// <param name="pathSegment">the segment to append to the current path.</param>
/// <param name="isRawUrl">whether the path segment is a raw url. When true, the segment is not happened and the current path is parsed for query parameters.</param>
/// <exception cref="UriFormatException">Thrown when the built URI is an invalid format.</exception>
public void SetURI(string currentPath, string pathSegment, bool isRawUrl)
{
if (isRawUrl)
{
if(string.IsNullOrEmpty(currentPath))
throw new ArgumentNullException(nameof(currentPath));
var parseUri = new Uri(currentPath);
var parseQueryString = parseUri.Query.TrimStart('?'); //remove leading ? if needed
foreach(var qsp in parseQueryString.Split('&').Select(x => x.Split('=')).Where(x => !string.IsNullOrEmpty(x[0]))) {
QueryParameters.Add(qsp[0], qsp.Length > 1 ? qsp[1] : null);
}
URI = new Uri(parseUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.Unescaped));
public Uri URI {
set {
if(value == null)
throw new ArgumentNullException(nameof(value));
QueryParameters.Clear();
PathParameters.Clear();
_rawUri = value;
}
else
{
URI = new Uri(currentPath + pathSegment);
get {
if(_rawUri != null)
return _rawUri;
else if(PathParameters.TryGetValue("request-raw-url", out var rawUrl) &&
rawUrl is string rawUrlString) {
URI = new Uri(rawUrlString);
return _rawUri;
}
else
{
var parsedUrlTemplate = new UriTemplate(UrlTemplate);
foreach(var urlTemplateParameter in PathParameters)
{
// if the value is boolean, lets pass in a lowercase string as the final url will be uppercase due to the way ToString() works for booleans
var sanitizedValue = (urlTemplateParameter.Value is bool boolValue) ? boolValue.ToString().ToLower() : urlTemplateParameter.Value;
parsedUrlTemplate.SetParameter(urlTemplateParameter.Key, sanitizedValue);
}

foreach(var queryStringParameter in QueryParameters)
if(queryStringParameter.Value != null)
{
// if the value is boolean, lets pass in a lowercase string as the final url will be uppercase due to the way ToString() works for booleans
var sanitizedValue = (queryStringParameter.Value is bool boolValue) ? boolValue.ToString().ToLower() : queryStringParameter.Value;
parsedUrlTemplate.SetParameter(queryStringParameter.Key, sanitizedValue);
}
return new Uri(parsedUrlTemplate.Resolve());
}
}
}
/// <summary>
/// The Url template for the current request.
/// </summary>
public string UrlTemplate { get; set; }
/// <summary>
/// The path parameters to use for the URL template when generating the URI.
/// </summary>
public IDictionary<string, object> PathParameters { get; set; } = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// The <see cref="HttpMethod">HTTP method</see> of the request.
/// </summary>
public HttpMethod HttpMethod { get; set; }
Expand Down
5 changes: 4 additions & 1 deletion abstractions/go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/microsoft/kiota/abstractions/go

go 1.16

require github.com/google/uuid v1.3.0 // indirect
require (
github.com/google/uuid v1.3.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.1 // indirect
)
2 changes: 2 additions & 0 deletions abstractions/go/go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/yosida95/uritemplate/v3 v3.0.1 h1:+Fs//CsT+x231WmUQhMHWMxZizMvpnkOVWop02mVCfs=
github.com/yosida95/uritemplate/v3 v3.0.1/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
75 changes: 48 additions & 27 deletions abstractions/go/request_information.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,83 @@ package abstractions
import (
"errors"
"reflect"
"strings"

"net/url"
u "net/url"

s "github.com/microsoft/kiota/abstractions/go/serialization"
t "github.com/yosida95/uritemplate/v3"
)

/* This type represents an abstract HTTP request. */
type RequestInformation struct {
Method HttpMethod
URI u.URL
uri *u.URL
Headers map[string]string
QueryParameters map[string]string
Content []byte
PathParameters map[string]string
UrlTemplate string
options map[string]RequestOption
}

const raw_url_key = "request-raw-url"

func NewRequestInformation() *RequestInformation {
return &RequestInformation{
URI: u.URL{},
Headers: make(map[string]string),
QueryParameters: make(map[string]string),
options: make(map[string]RequestOption),
PathParameters: make(map[string]string),
}
}

func (request *RequestInformation) SetUri(currentPath string, pathSegment string, isRawUrl bool) error {
if isRawUrl {
if currentPath == "" {
return errors.New("current path cannot be empty")
}
questionMarkSplat := strings.Split(currentPath, "?")
schemeHostAndPath := questionMarkSplat[0]
uri, err := url.Parse(schemeHostAndPath)
func (request *RequestInformation) GetUri() (*u.URL, error) {
if request.uri != nil {
return request.uri, nil
} else if request.UrlTemplate == "" {
return nil, errors.New("uri cannot be empty")
} else if request.PathParameters == nil {
return nil, errors.New("uri template parameters cannot be nil")
} else if request.QueryParameters == nil {
return nil, errors.New("uri query parameters cannot be nil")
} else if request.PathParameters[raw_url_key] != "" {
uri, err := u.Parse(request.PathParameters[raw_url_key])
if err != nil {
return err
return nil, err
}
request.URI = *uri
if len(questionMarkSplat) > 1 {
queryParameters := questionMarkSplat[1]
for _, queryParameter := range strings.Split(queryParameters, "&") {
keyValue := strings.Split(queryParameter, "=")
if len(keyValue) == 2 {
request.QueryParameters[keyValue[0]] = keyValue[1]
} else if len(keyValue) == 1 {
request.QueryParameters[keyValue[0]] = ""
}
}
err = request.SetUri(*uri)
if err != nil {
return nil, err
}
return request.uri, nil
} else {
uri, err := url.Parse(currentPath + pathSegment)
uriTemplate, err := t.New(request.UrlTemplate)
if err != nil {
return err
return nil, err
}
request.URI = *uri
values := t.Values{}
for key, value := range request.PathParameters {
values.Set(key, t.String(value))
}
for key, value := range request.QueryParameters {
values.Set(key, t.String(value))
}
url, err := uriTemplate.Expand(values)
if err != nil {
return nil, err
}
uri, err := u.Parse(url)
return uri, err
}
}

func (request *RequestInformation) SetUri(url u.URL) error {
request.uri = &url
for k := range request.PathParameters {
delete(request.PathParameters, k)
}
for k := range request.QueryParameters {
delete(request.QueryParameters, k)
}
return nil
}
Expand Down
4 changes: 3 additions & 1 deletion abstractions/java/lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ dependencies {
implementation 'com.google.guava:guava:31.0.1-jre'

implementation 'org.javatuples:javatuples:1.2'

implementation 'com.github.hal4j:uritemplate:1.2.3'
}

publishing {
Expand All @@ -46,7 +48,7 @@ publishing {
publications {
gpr(MavenPublication) {
artifactId 'kiota-abstractions'
version '1.0.21'
version '1.0.22'
from(components.java)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.lang.reflect.Field;
import java.lang.IllegalAccessException;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nonnull;
Expand All @@ -12,7 +13,14 @@ public void AddQueryParameters(@Nonnull final Map<String, Object> target) {
final Field[] fields = this.getClass().getFields();
for(final Field field : fields) {
try {
target.put(field.getName(), field.get(this));
var value = field.get(this);
if(value != null) {
if(value.getClass().isArray()) {
target.put(field.getName(), Arrays.asList((Object[])value));
} else {
target.put(field.getName(), value);
}
}
} catch (IllegalAccessException ex) {
//TODO log
}
Expand Down
Loading