OpenAPI.NET icon indicating copy to clipboard operation
OpenAPI.NET copied to clipboard

OpenApiDocument.SerializeAsV2 throws UriFormatException when given schemes and basePath, but no host

Open KalleOlaviNiemitalo opened this issue 5 years ago • 4 comments

Summary

When Microsoft.OpenAPI.Readers reads an OpenAPI 2.0 document in which the Swagger Object has properties "schemes": [ "http" ] and "basePath": "/api" but does not have a "host" property, it sets OpenApiServer.Url ="http:///api". If OpenApiDocument.SerializeAsV2 is then called, it throws UriFormatException.

OpenAPI Specification Version 2.0 does not require host, regardless of whether schemes is empty.

To reproduce

Console1App.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <LangVersion>7.3</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.OpenApi" Version="1.2.2" />
    <PackageReference Include="Microsoft.OpenApi.Readers" Version="1.2.2" />
  </ItemGroup>

</Project>

Program.cs:

using System.IO;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Writers;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string originalYaml = @"
swagger: '2.0'
info:
  title: 'Demo'
  version: '1.0'
basePath: '/api'
schemes:
- 'http'
paths:
  '/demo':
    get:
      responses:
        '200':
          description: 'OK'
";

            var openApiReader = new OpenApiStringReader();
            OpenApiDocument document = openApiReader.Read(originalYaml, out _);

            var openApiWriter = new OpenApiJsonWriter(new StringWriter());
            document.SerializeAsV2(openApiWriter); // fails with exception
        }
    }
}

Expected behaviour

No exception is thrown, and the resulting JSON likewise has basePath and schemes but no host.

Actual behaviour

An exception is thrown:

Unhandled Exception: System.UriFormatException: Invalid URI: The hostname could not be parsed.
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
   at System.Uri..ctor(String uriString, UriKind uriKind)
   at Microsoft.OpenApi.Models.OpenApiDocument.WriteHostInfoV2(IOpenApiWriter writer, IList`1 servers) in d:\a\1\s\src\Microsoft.OpenApi\Models\OpenApiDocument.cs:line 263
   at Microsoft.OpenApi.Models.OpenApiDocument.SerializeAsV2(IOpenApiWriter writer) in d:\a\1\s\src\Microsoft.OpenApi\Models\OpenApiDocument.cs:line 123
   at ConsoleApp1.Program.Main(String[] args) in …\ConsoleApp1\Program.cs:line 32

The stack trace is the same as in https://github.com/microsoft/OpenAPI.NET/issues/440, but the Exception.Message is different.

KalleOlaviNiemitalo avatar Jul 02 '20 14:07 KalleOlaviNiemitalo

This is not quite a duplicate of https://github.com/microsoft/OpenAPI.NET/issues/350 because that one does not cover the UriFormatException that is thrown during roundtripping.

I mean, in https://github.com/microsoft/OpenAPI.NET/issues/350, the complaint is that OpenApiServer.Url should be "/v2" rather than "http:///v2". Here, I'd be happy with OpenApiServer.Url being "http:///api" if the library just were able to serialize it back to OpenAPI 2.0.

KalleOlaviNiemitalo avatar Jul 02 '20 15:07 KalleOlaviNiemitalo

The OpenAPI 2.0 specification says:

If the host is not included, the host serving the documentation is to be used

However, in your case, the OpenAPI description is not coming from somewhere we can infer a host from.

I don't think it is possible to have a relative reference with no host that includes a scheme. If you really just want a relative reference in the URL, then you will need to drop the scheme. That will give you this:

image

darrelmiller avatar Jul 03 '20 02:07 darrelmiller

However, in your case, the OpenAPI description is not coming from somewhere we can infer a host from.

The plan was to use this library to serialize the OpenAPI 2.0 document and place it on an HTTP server, and the host would be implied when the document is later retrieved from that server.

KalleOlaviNiemitalo avatar Jul 03 '20 05:07 KalleOlaviNiemitalo

@KalleOlaviNiemitalo So, then the example I showed that just includes the basePath should be sufficient for your scenario. Just don't include the host or scheme and the basePath will be relative to the host the OpenAPI description was found on.

darrelmiller avatar Sep 28 '20 01:09 darrelmiller