Skip to content

Commit

Permalink
Process review feedback, fixed culture issue in test
Browse files Browse the repository at this point in the history
  • Loading branch information
maurei committed Nov 26, 2021
1 parent 6160ad0 commit 796f104
Show file tree
Hide file tree
Showing 18 changed files with 300 additions and 263 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents
{
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class NullableSecondaryResourceResponseDocument<TResource> : NullableSingleData<ResourceResponseObject<TResource>>
internal sealed class NullableSecondaryResourceResponseDocument<TResource> : NullableSingleData<ResourceObjectInResponse<TResource>>
where TResource : IIdentifiable
{
public IDictionary<string, object> Meta { get; set; } = null!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents
// Types in the current namespace are never touched by ASP.NET ModelState validation, therefore using a non-nullable reference type for a property does not
// imply this property is required. Instead, we use [Required] explicitly, because this is how Swashbuckle is instructed to mark properties as required.
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class PrimaryResourceResponseDocument<TResource> : SingleData<ResourceResponseObject<TResource>>
internal sealed class PrimaryResourceResponseDocument<TResource> : SingleData<ResourceObjectInResponse<TResource>>
where TResource : IIdentifiable
{
public IDictionary<string, object> Meta { get; set; } = null!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents
{
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class ResourceCollectionResponseDocument<TResource> : ManyData<ResourceResponseObject<TResource>>
internal sealed class ResourceCollectionResponseDocument<TResource> : ManyData<ResourceObjectInResponse<TResource>>
where TResource : IIdentifiable
{
public IDictionary<string, object> Meta { get; set; } = null!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents
{
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class ResourcePatchRequestDocument<TResource> : SingleData<ResourcePatchRequestObject<TResource>>
internal sealed class ResourcePatchRequestDocument<TResource> : SingleData<ResourceObjectInPatchRequest<TResource>>
where TResource : IIdentifiable
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents
{
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class ResourcePostRequestDocument<TResource> : SingleData<ResourcePostRequestObject<TResource>>
internal sealed class ResourcePostRequestDocument<TResource> : SingleData<ResourceObjectInPostRequest<TResource>>
where TResource : IIdentifiable
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents
{
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class SecondaryResourceResponseDocument<TResource> : SingleData<ResourceResponseObject<TResource>>
internal sealed class SecondaryResourceResponseDocument<TResource> : SingleData<ResourceObjectInResponse<TResource>>
where TResource : IIdentifiable
{
public IDictionary<string, object> Meta { get; set; } = null!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects
{
internal sealed class ResourcePostRequestObject<TResource> : ResourceObject<TResource>
internal sealed class ResourceObjectInPatchRequest<TResource> : ResourceObject<TResource>
where TResource : IIdentifiable
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects
{
internal sealed class ResourcePatchRequestObject<TResource> : ResourceObject<TResource>
internal sealed class ResourceObjectInPostRequest<TResource> : ResourceObject<TResource>
where TResource : IIdentifiable
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects
{
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class ResourceResponseObject<TResource> : ResourceObject<TResource>
internal sealed class ResourceObjectInResponse<TResource> : ResourceObject<TResource>
where TResource : IIdentifiable
{
[Required]
Expand Down
45 changes: 36 additions & 9 deletions src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,32 @@ internal sealed class JsonApiSchemaIdSelector
{
[typeof(ResourcePostRequestDocument<>)] = "###-post-request-document",
[typeof(ResourcePatchRequestDocument<>)] = "###-patch-request-document",
[typeof(ResourcePostRequestObject<>)] = "###-data-in-post-request",
[typeof(ResourcePatchRequestObject<>)] = "###-data-in-patch-request",
[typeof(ToOneRelationshipInRequest<>)] = "to-one-###-data-in-request",
[typeof(NullableToOneRelationshipInRequest<>)] = "nullable-to-one-###-data-in-request",
[typeof(ToManyRelationshipInRequest<>)] = "to-many-###-data-in-request",
[typeof(ResourceObjectInPostRequest<>)] = "###-in-post-request",
[typeof(ResourceObjectInPatchRequest<>)] = "###-in-patch-request",
[typeof(ToOneRelationshipInRequest<>)] = "to-one-###-in-request",
[typeof(NullableToOneRelationshipInRequest<>)] = "nullable-to-one-###-in-request",
[typeof(ToManyRelationshipInRequest<>)] = "to-many-###-in-request",
[typeof(PrimaryResourceResponseDocument<>)] = "###-primary-response-document",
[typeof(SecondaryResourceResponseDocument<>)] = "###-secondary-response-document",
[typeof(NullableSecondaryResourceResponseDocument<>)] = "nullable-###-secondary-response-document",
[typeof(ResourceCollectionResponseDocument<>)] = "###-collection-response-document",
[typeof(ResourceIdentifierResponseDocument<>)] = "###-identifier-response-document",
[typeof(NullableResourceIdentifierResponseDocument<>)] = "nullable-###-identifier-response-document",
[typeof(ResourceIdentifierCollectionResponseDocument<>)] = "###-identifier-collection-response-document",
[typeof(ToOneRelationshipInResponse<>)] = "to-one-###-data-in-response",
[typeof(NullableToOneRelationshipInResponse<>)] = "nullable-to-one-###-data-in-response",
[typeof(ToManyRelationshipInResponse<>)] = "to-many-###-data-in-response",
[typeof(ResourceResponseObject<>)] = "###-data-in-response",
[typeof(ToOneRelationshipInResponse<>)] = "to-one-###-in-response",
[typeof(NullableToOneRelationshipInResponse<>)] = "nullable-to-one-###-in-response",
[typeof(ToManyRelationshipInResponse<>)] = "to-many-###-in-response",
[typeof(ResourceObjectInResponse<>)] = "###-in-response",
[typeof(ResourceIdentifierObject<>)] = "###-identifier"
};

private readonly Type[] _resourceObjectOpenTypes =
{
typeof(ResourceObjectInPostRequest<>),
typeof(ResourceObjectInPatchRequest<>),
typeof(ResourceObjectInResponse<>)
};

private readonly ResourceNameFormatter _formatter;
private readonly IResourceGraph _resourceGraph;

Expand Down Expand Up @@ -69,5 +76,25 @@ public string GetSchemaId(Type type)
// Used for a fixed set of types, such as jsonapi-object, links-in-many-resource-document etc.
return _formatter.FormatResourceName(type).Singularize();
}

public string GetSchemaId(Type resourceObjectOpenType, ResourceObjectFieldType fieldType)
{
ArgumentGuard.NotNull(resourceObjectOpenType, nameof(resourceObjectOpenType));

if (!resourceObjectOpenType.IsConstructedGenericType || !_resourceObjectOpenTypes.Contains(resourceObjectOpenType.GetGenericTypeDefinition()))
{
throw new InvalidOperationException($"Type '{resourceObjectOpenType.Name}' must be an open type representing a resource object.");
}

Type resourceClrType = resourceObjectOpenType.GetGenericArguments().First();
string resourceName = _formatter.FormatResourceName(resourceClrType).Singularize();
string template = OpenTypeToSchemaTemplateMap[resourceObjectOpenType.GetGenericTypeDefinition()];

string fieldObjectName = fieldType == ResourceObjectFieldType.Attributes
? JsonApiObjectPropertyName.AttributesObject
: JsonApiObjectPropertyName.RelationshipsObject;

return template.Replace("###", $"{resourceName}-{fieldObjectName}");
}
}
}
8 changes: 8 additions & 0 deletions src/JsonApiDotNetCore.OpenApi/ResourceObjectFieldType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace JsonApiDotNetCore.OpenApi
{
internal enum ResourceObjectFieldType
{
Attributes,
Relationships
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
Expand Down Expand Up @@ -26,7 +28,14 @@ public OpenApiDocument GetSwagger(string documentName, string? host = null, stri

string cacheKey = $"{documentName}#{host}#{basePath}";

return _openApiDocumentCache.GetOrAdd(cacheKey, _ => _defaultSwaggerGenerator.GetSwagger(documentName, host, basePath));
return _openApiDocumentCache.GetOrAdd(cacheKey, _ =>
{
OpenApiDocument document = _defaultSwaggerGenerator.GetSwagger(documentName, host, basePath);

// Remove once https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2283 is addressed.
document.Components.Schemas = new SortedDictionary<string, OpenApiSchema>(document.Components.Schemas, StringComparer.Ordinal);
return document;
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ private IDictionary<string, OpenApiSchema> GetFieldSchemas()

fullSchemaForAttributesObject.AdditionalPropertiesAllowed = false;

return GetReferenceSchemaForFieldObject(fullSchemaForAttributesObject, JsonApiObjectPropertyName.AttributesObject);
string fieldObjectSchemaId = _jsonApiSchemaIdSelector.GetSchemaId(_resourceTypeInfo.ResourceObjectType, ResourceObjectFieldType.Attributes);
return _schemaRepositoryAccessor.Current.AddDefinition(fieldObjectSchemaId, fullSchemaForAttributesObject);
}

private void SetMembersOfAttributesObject(OpenApiSchema fullSchemaForAttributesObject)
Expand All @@ -103,9 +104,9 @@ private void SetMembersOfAttributesObject(OpenApiSchema fullSchemaForAttributesO

private static AttrCapabilities GetRequiredCapabilityForAttributes(Type resourceObjectOpenType)
{
return resourceObjectOpenType == typeof(ResourceResponseObject<>) ? AttrCapabilities.AllowView :
resourceObjectOpenType == typeof(ResourcePostRequestObject<>) ? AttrCapabilities.AllowCreate :
resourceObjectOpenType == typeof(ResourcePatchRequestObject<>) ? AttrCapabilities.AllowChange : throw new UnreachableCodeException();
return resourceObjectOpenType == typeof(ResourceObjectInResponse<>) ? AttrCapabilities.AllowView :
resourceObjectOpenType == typeof(ResourceObjectInPostRequest<>) ? AttrCapabilities.AllowCreate :
resourceObjectOpenType == typeof(ResourceObjectInPatchRequest<>) ? AttrCapabilities.AllowChange : throw new UnreachableCodeException();
}

private void AddAttributeSchemaToResourceObject(AttrAttribute attribute, OpenApiSchema attributesObjectSchema, OpenApiSchema resourceAttributeSchema)
Expand All @@ -127,7 +128,7 @@ private void ExposeSchema(OpenApiReference openApiReference, Type typeRepresente

private bool IsFieldRequired(ResourceFieldAttribute field)
{
if (field is HasManyAttribute || _resourceTypeInfo.ResourceObjectOpenType != typeof(ResourcePostRequestObject<>))
if (field is HasManyAttribute || _resourceTypeInfo.ResourceObjectOpenType != typeof(ResourceObjectInPostRequest<>))
{
return false;
}
Expand All @@ -144,15 +145,6 @@ private bool IsFieldRequired(ResourceFieldAttribute field)
};
}

private OpenApiSchema GetReferenceSchemaForFieldObject(OpenApiSchema fullSchema, string fieldObjectName)
{
// NSwag does not have proper support for using an inline schema for the attributes and relationships object in a resource object, see https://github.com/RicoSuter/NSwag/issues/3474. Once this issue has been resolved, we can remove this.
string resourceObjectSchemaId = _jsonApiSchemaIdSelector.GetSchemaId(_resourceTypeInfo.ResourceObjectType);
string fieldObjectSchemaId = resourceObjectSchemaId.Replace(JsonApiObjectPropertyName.Data, fieldObjectName);

return _schemaRepositoryAccessor.Current.AddDefinition(fieldObjectSchemaId, fullSchema);
}

public OpenApiSchema? BuildRelationshipsObject(OpenApiSchema fullSchemaForResourceObject)
{
ArgumentGuard.NotNull(fullSchemaForResourceObject, nameof(fullSchemaForResourceObject));
Expand All @@ -168,7 +160,8 @@ private OpenApiSchema GetReferenceSchemaForFieldObject(OpenApiSchema fullSchema,

fullSchemaForRelationshipsObject.AdditionalPropertiesAllowed = false;

return GetReferenceSchemaForFieldObject(fullSchemaForRelationshipsObject, JsonApiObjectPropertyName.RelationshipsObject);
string fieldObjectSchemaId = _jsonApiSchemaIdSelector.GetSchemaId(_resourceTypeInfo.ResourceObjectType, ResourceObjectFieldType.Relationships);
return _schemaRepositoryAccessor.Current.AddDefinition(fieldObjectSchemaId, fullSchemaForRelationshipsObject);
}

private void SetMembersOfRelationshipsObject(OpenApiSchema fullSchemaForRelationshipsObject)
Expand Down Expand Up @@ -228,7 +221,7 @@ private void AddRelationshipSchemaToResourceObject(RelationshipAttribute relatio

private static Type GetRelationshipSchemaType(RelationshipAttribute relationship, Type resourceObjectType)
{
return resourceObjectType.GetGenericTypeDefinition().IsAssignableTo(typeof(ResourceResponseObject<>))
return resourceObjectType.GetGenericTypeDefinition().IsAssignableTo(typeof(ResourceObjectInResponse<>))
? RelationshipTypeFactory.Instance.GetForResponse(relationship)
: RelationshipTypeFactory.Instance.GetForRequest(relationship);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public OpenApiSchema GenerateSchema(Type resourceObjectType)

private void RemoveResourceIdIfPostResourceObject(Type resourceObjectOpenType, OpenApiSchema fullSchemaForResourceObject)
{
if (resourceObjectOpenType == typeof(ResourcePostRequestObject<>) && !_allowClientGeneratedIds)
if (resourceObjectOpenType == typeof(ResourceObjectInPostRequest<>) && !_allowClientGeneratedIds)
{
fullSchemaForResourceObject.Required.Remove(JsonApiObjectPropertyName.Id);
fullSchemaForResourceObject.Properties.Remove(JsonApiObjectPropertyName.Id);
Expand Down
Loading

0 comments on commit 796f104

Please sign in to comment.