-
Notifications
You must be signed in to change notification settings - Fork 46
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
Look into adding appropriate support for OpenAPI #68
Comments
Hm, this can get quite complex. Someone may want to be able to say something like, "this parameter may be any GeoJSON object type, but if it's a Point, then it needs to look like this; if it's a LineString, then it needs to look like this; if it's a FeatureCollection, then it needs to look like this". Immediately off the top of my head, an API to make that work might look something like: var mySchema = new GeoJsonApiSchemaBuilder()
.GeneralOptions(options =>
{
// options is of type GeoJsonGeneralOpenApiOptions
options.AllowedGeoJsonTypes.Clear();
options.AllowedGeoJsonTypes.Add("Point");
options.AllowedGeoJsonTypes.Add("LineString");
options.AllowedGeoJsonTypes.Add("Polygon");
options.AllowedGeoJsonTypes.Add("MultiPoint");
options.AllowedGeoJsonTypes.Add("MultiLineString");
options.AllowedGeoJsonTypes.Add("MultiPolygon");
options.AllowedGeoJsonTypes.Add("Feature");
options.AllowedGeoJsonTypes.Add("FeatureCollection");
options.GeoJsonTypesRequiringBoundingBox.Clear();
options.GeoJsonTypesRequiringBoundingBox.Add("LineString");
options.GeoJsonTypesRequiringBoundingBox.Add("Polygon");
options.GeoJsonTypesRequiringBoundingBox.Add("MultiPoint");
options.GeoJsonTypesRequiringBoundingBox.Add("MultiLineString");
options.GeoJsonTypesRequiringBoundingBox.Add("MultiPolygon");
options.GeoJsonTypesRequiringBoundingBox.Add("Feature");
options.GeoJsonTypesRequiringBoundingBox.Add("FeatureCollection");
})
.GeometryOptions(options =>
{
// options is of type GeoJsonGeometryOpenApiOptions
options.AllowEmpty = false;
options.MaxDimension = 2;
options.ValidBounds = new Envelope(-180, 180, -85.05115, 85.05115);
})
.LineStringOptions(options =>
{
// options is of type GeoJsonLineStringOpenApiOptions
// GeoJsonLineStringOpenApiOptions inherits from GeoJsonGeometryOpenApiOptions
options.MinPointCount = 5; // implies AllowEmpty = false
})
.PolygonOptions(options =>
{
// options is of type GeoJsonPolygonOpenApiOptions
// GeoJsonPolygonOpenApiOptions inherits from GeoJsonGeometryOpenApiOptions
options.MaxRingCount = 1;
options.RingOrder = RingOrders.SingleExteriorThenAllInterior;
////options.RingOrder = RingOrders.Unspecified;
options.ExteriorRingOrientation = OrientationIndex.CounterClockwise;
options.InteriorRingOrientation = OrientationIndex.Clockwise;
options.ExteriorRingOptions(ringOptions =>
{
// ringOptions is of type GeoJsonExteriorRingOpenApiOptions
// GeoJsonExteriorRingOpenApiOptions inherits from GeoJsonLinearRingOpenApiOptions
// GeoJsonLinearRingOpenApiOptions inherits from GeoJsonLineStringOpenApiOptions
ringOptions.MinPointCount = 7; // implies AllowEmpty = false
ringOptions.Orientation = OrientationIndex.CounterClockwise;
});
options.InteriorRingOptions(ringOptions =>
{
// ringOptions is of type GeoJsonInteriorRingOpenApiOptions
// GeoJsonInteriorRingOpenApiOptions inherits from GeoJsonLinearRingOpenApiOptions
// GeoJsonLinearRingOpenApiOptions inherits from GeoJsonLineStringOpenApiOptions
ringOptions.Orientation = OrientationIndex.Clockwise;
});
})
.MultiPointOptions(options =>
{
// options is of type GeoJsonMultiPointOpenApiOptions
// GeoJsonMultiPointOpenApiOptions inherits from GeoJsonGeometryOpenApiOptions
options.MinPointCount = 2; // implies AllowEmpty = false
options.PointOptions(pointOptions =>
{
// pointOptions is of type GeoJsonPointOpenApiOptions
// GeoJsonPointOpenApiOptions inherits from GeoJsonGeometryOpenApiOptions
});
})
/* omitted: .MultiLineStringOptions, .MultiPolygonOptions, they look the same */
.GeometryCollectionOptions(options =>
{
// options is of type GeoJsonGeometryCollectionOpenApiOptions
// GeoJsonGeometryCollectionOpenApiOptions inherits from GeoJsonGeometryOpenApiOptions
options.MinGeometryCount = 3; // implies AllowEmpty = false
options.AllowedGeoJsonTypes.Clear();
options.AllowedGeoJsonTypes.Add("Point");
options.AllowedGeoJsonTypes.Add("LineString");
options.AllowedGeoJsonTypes.Add("Polygon");
options.AllowedGeoJsonTypes.Add("MultiPoint");
options.AllowedGeoJsonTypes.Add("MultiLineString");
options.AllowedGeoJsonTypes.Add("MultiPolygon");
options.AllowedGeoJsonTypes.Add("Feature");
options.AllowedGeoJsonTypes.Add("FeatureCollection");
options
.PointOptions(pointOptions =>
{
// pointOptions is of type GeoJsonPointOpenApiOptions
})
.LineStringOptions(lineStringOptions =>
{
// lineStringOptions is of type GeoJsonLineStringOpenApiOptions
})
.PolygonOptions(polygonOptions =>
{
// polygonOptions is of type GeoJsonPolygonOpenApiOptions
});
})
.FeatureOptions(options =>
{
// options is of type GeoJsonFeatureOpenApiOptions
options.AddRequiredProperty("foo", new OpenApiSchema { /* stuff */ }); // implies RequireProperties = true
options.AddOptionalProperty("bar", new OpenApiSchema { /* stuff */ });
options.GeometryOptions(geometryOptions =>
{
// geometryOptions is of type GeoJsonFeatureGeometryOpenApiOptions
// GeoJsonFeatureGeometryOpenApiOptions inherits from GeoJsonGeometryOpenApiOptions
geometryOptions.AllowEmpty = true;
geometryOptions.AllowedGeoJsonTypes.Clear();
geometryOptions.AllowedGeoJsonTypes.Add("Polygon");
geometryOptions.PolygonOptions(polygonOptions =>
{
// polygonOptions is of type GeoJsonPolygonOpenApiOptions
});
});
})
.FeatureCollectionOptions(options =>
{
// options is of type GeoJsonFeatureCollectionOpenApiOptions
options.MinFeatureCount = 2;
options.FeatureOptions(featureOptions =>
{
// featureOptions is of type GeoJsonFeatureOpenApiOptions
});
})
.WithExample(somePolygon)
.WithDefault(someOtherPolygon)
.Build(); |
Of course, that API blueprint is something that contains a bunch of stuff, most of which wouldn't be used in a typical caller. More typically, we'd see something more like: var mySchema = new GeoJsonApiSchemaBuilder()
.GeneralOptions(options =>
{
options.AllowedGeoJsonTypes.Clear();
options.AllowedGeoJsonTypes.Add("Polygon");
})
.GeometryOptions(options =>
{
options.AllowEmpty = false;
}
.WithExample(somePolygon)
.WithDefault(someOtherPolygon)
.Build(); Perhaps still too much, since "I just want a non-empty polygon, here's my example and default" seems like a pretty darn straightforward thing to want, for such a not-straightforward way to specify it... |
Any progress on this issue? I'm building a .net 6 web api and the metadata from swagger doesn't match the schema that the api actually returns when I use GeoJSON4STJ. E.g. when an object has a Point the service serializes it like this...
Alternatively, advice on how to configure swagger to use the same serializer so that it presents the correct schema in the openapi metadata would be just as good. Another option is to let the native serializer do its thing. Configuring it as much as I've been able gets me as far as an exception that it's trying to serialize an empty Point, when in fact the only Point is non-empty. E.g. using
|
I am currently developing a project for publishing GeoJSON based on the OGC API Features standard (https://github.com/sam-is/OgcApi.Net). GeoJSON4STJ and .NET 5 are used. To define metadata for geometry and properties, I abandoned the description that Swashbuckle does by default. Now the OpenAPI description is done manually:
Theoretically, the creation of an OpenAPI description of GeoJSON can be separated and changed to support the required functionality. |
I'm starting to think the only problem here is that some NTS classes that inherit from Geometry have properties that throw an exception when their getters are accessed. E.g. a Point has all the properties of a Geometry, but some of them will throw an exception when they are accessed because they just don't apply to a Point. The GeoJSON4STJ library handles this by only serializing the properties of an object that have valid values, but that leaves the openapi metadata incompatible with what the API actually serializes so that a client won't be able to deserialize it. |
Has there been any progress on this on any front? To avoid polluting the openapi spec I ended up stubbing out the response for a specific type of GeoJSON that I know to be a Point with specific properties:
And then using But this is of course not easily generalizable.. |
As a developer of a web API that uses GeoJSON-formatted inputs and outputs, I want a library maintained by the NetTopologySuite organization that I can use to document the GeoJSON parts of my API (e.g., via Swashbuckle.AspNetCore.SwaggerGen) so that I don't have to understand and recreate the details of the GeoJSON format in my OpenAPI schemas.
This can and should be independent of Json.NET vs. System.Text.Json, since (from my understanding) this has more to do with the format of the data rather than the actual code that produces / consumes it.
As one possible idea, if I had an instance of type
NetTopologySuite.Geometries.Polygon
that represents an example input to an API, I would like to give it to something from NTS and get back an instance of typeMicrosoft.OpenApi.Models.OpenApiSchema
that represents a GeoJSON Polygon's schema, and has the.Example
property filled out with the example data that I gave it.The text was updated successfully, but these errors were encountered: