a fork of iceshrimp.net but a tweaked frontend to my personal liking. waow
fediverse social-media social iceshrimp fedi
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[backend] Refactor to use MSOpenAPI 2.x during document generation

+45 -51
+1 -1
Iceshrimp.Backend/Core/Extensions/ServiceExtensions.cs
··· 23 23 using Microsoft.Extensions.DependencyInjection.Extensions; 24 24 using Microsoft.Extensions.Logging.Abstractions; 25 25 using Microsoft.Extensions.Options; 26 - using Microsoft.OpenApi.Models; 26 + using Microsoft.OpenApi; 27 27 28 28 namespace Iceshrimp.Backend.Core.Extensions; 29 29
+44 -50
Iceshrimp.Backend/Core/Extensions/SwaggerGenOptionsExtensions.cs
··· 8 8 using Iceshrimp.Shared.Schemas.Web; 9 9 using Microsoft.AspNetCore.Mvc.ApiExplorer; 10 10 using Microsoft.AspNetCore.WebUtilities; 11 - using Microsoft.OpenApi.Any; 12 - using Microsoft.OpenApi.Models; 11 + using Microsoft.OpenApi; 13 12 using Swashbuckle.AspNetCore.SwaggerGen; 14 13 15 14 namespace Iceshrimp.Backend.Core.Extensions; ··· 57 56 Justification = "SwaggerGenOptions.SchemaFilter<T> instantiates this class at runtime")] 58 57 private class RequireNonNullablePropertiesSchemaFilter : ISchemaFilter 59 58 { 60 - public void Apply(OpenApiSchema model, SchemaFilterContext context) 59 + public void Apply(IOpenApiSchema model, SchemaFilterContext context) 61 60 { 62 61 var additionalRequiredProps = model.Properties 63 - .Where(x => !x.Value.Nullable && !model.Required.Contains(x.Key)) 62 + ?.Where(x => x.Value.Type?.HasFlag(JsonSchemaType.Null) != true 63 + && model.Required?.Contains(x.Key) != true) 64 64 .Select(x => x.Key); 65 + 66 + if (additionalRequiredProps is null) return; 67 + 65 68 foreach (var propKey in additionalRequiredProps) 66 - { 67 - model.Required.Add(propKey); 68 - } 69 + model.Required?.Add(propKey); 69 70 } 70 71 } 71 72 ··· 73 74 Justification = "SwaggerGenOptions.SchemaFilter<T> instantiates this class at runtime")] 74 75 private class SwaggerBodyExampleSchemaFilter : ISchemaFilter 75 76 { 76 - public void Apply(OpenApiSchema schema, SchemaFilterContext context) 77 + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) 77 78 { 78 79 var att = context.ParameterInfo?.GetCustomAttribute<SwaggerBodyExampleAttribute>(); 79 - if (att != null) 80 - schema.Example = new OpenApiString(att.Value); 80 + if (att == null) return; 81 + schema.Examples?.Clear(); 82 + schema.Examples?.Add(att.Value); 81 83 } 82 84 } 83 85 ··· 117 119 } 118 120 """; 119 121 120 - private static readonly OpenApiString MastoExample401 = new(Masto401); 121 - private static readonly OpenApiString MastoExample403 = new(Masto403); 122 - private static readonly OpenApiString WebExample401 = new(Web401); 123 - private static readonly OpenApiString WebExample403 = new(Web403); 124 - 125 - private static readonly OpenApiReference Ref401 = 126 - new() { Type = ReferenceType.Response, Id = "error-401" }; 127 - 128 - private static readonly OpenApiReference Ref403 = 129 - new() { Type = ReferenceType.Response, Id = "error-403" }; 122 + private static readonly OpenApiResponseReference Ref401 = new("error-401"); 123 + private static readonly OpenApiResponseReference Ref403 = new("error-403"); 130 124 131 125 private static readonly OpenApiResponse MastoRes401 = new() 132 126 { 133 - Reference = Ref401, 134 127 Description = "Unauthorized", 135 - Content = { ["application/json"] = new OpenApiMediaType { Example = MastoExample401 } } 128 + Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new() { Example = Masto401 } } 136 129 }; 137 130 138 131 private static readonly OpenApiResponse MastoRes403 = new() 139 132 { 140 - Reference = Ref403, 141 133 Description = "Forbidden", 142 - Content = { ["application/json"] = new OpenApiMediaType { Example = MastoExample403 } } 134 + Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new() { Example = Masto403 } } 143 135 }; 144 136 145 137 private static readonly OpenApiResponse WebRes401 = new() 146 138 { 147 - Reference = Ref401, 148 139 Description = "Unauthorized", 149 - Content = { ["application/json"] = new OpenApiMediaType { Example = WebExample401 } } 140 + Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new() { Example = Web401 } } 150 141 }; 151 142 152 143 private static readonly OpenApiResponse WebRes403 = new() 153 144 { 154 - Reference = Ref403, 155 145 Description = "Forbidden", 156 - Content = { ["application/json"] = new OpenApiMediaType { Example = WebExample403 } } 146 + Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new() { Example = Web403 } } 157 147 }; 158 148 159 149 public void Apply(OpenApiOperation operation, OperationFilterContext context) ··· 181 171 .OfType<AuthorizeAttribute>() 182 172 .FirstOrDefault(); 183 173 184 - var schema = new OpenApiSecurityScheme 185 - { 186 - Reference = new OpenApiReference 187 - { 188 - Type = ReferenceType.SecurityScheme, Id = isMastodonController ? "mastodon" : "iceshrimp" 189 - } 190 - }; 191 - 192 - operation.Security = new List<OpenApiSecurityRequirement> { new() { [schema] = Array.Empty<string>() } }; 174 + var securitySchemaName = isMastodonController ? "mastodon" : "iceshrimp"; 175 + var schema = new OpenApiSecuritySchemeReference(securitySchemaName, context.Document); 176 + operation.Security = new List<OpenApiSecurityRequirement> { new() { [schema] = [] } }; 193 177 194 178 if (authorizeAttribute == null) return; 195 179 196 - operation.Responses.Remove("401"); 197 - operation.Responses.Add("401", new OpenApiResponse { Reference = Ref401 }); 180 + operation.Responses?.Remove("401"); 181 + operation.Responses ??= []; 182 + operation.Responses.Add("401", Ref401); 198 183 199 184 if (authorizeAttribute is { AdminRole: false, ModeratorRole: false, Scopes.Length: 0 } && 200 185 authenticateAttribute is { AdminRole: false, ModeratorRole: false, Scopes.Length: 0 }) 201 186 return; 202 187 203 - operation.Responses.Remove("403"); 204 - operation.Responses.Add("403", new OpenApiResponse { Reference = Ref403 }); 188 + operation.Responses?.Remove("403"); 189 + operation.Responses ??= []; 190 + operation.Responses.Add("403", Ref403); 205 191 } 206 192 207 193 public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) 208 194 { 195 + swaggerDoc.Components ??= new OpenApiComponents(); 196 + swaggerDoc.Components.Responses ??= new OpenApiResponses(); 197 + 209 198 if (swaggerDoc.Info.Title == "Mastodon") 210 199 { 211 - swaggerDoc.Components.Responses.Add(Ref401.Id, MastoRes401); 212 - swaggerDoc.Components.Responses.Add(Ref403.Id, MastoRes403); 200 + swaggerDoc.Components.Responses.Add(Ref401.Reference.Id!, MastoRes401); 201 + swaggerDoc.Components.Responses.Add(Ref403.Reference.Id!, MastoRes403); 213 202 } 214 203 else 215 204 { 216 - swaggerDoc.Components.Responses.Add(Ref401.Id, WebRes401); 217 - swaggerDoc.Components.Responses.Add(Ref403.Id, WebRes403); 205 + swaggerDoc.Components.Responses.Add(Ref401.Reference.Id!, WebRes401); 206 + swaggerDoc.Components.Responses.Add(Ref403.Reference.Id!, WebRes403); 218 207 } 219 208 } 220 209 } ··· 249 238 var res = new OpenApiResponse 250 239 { 251 240 Description = ReasonPhrases.GetReasonPhrase((int)status), 252 - Content = { ["application/json"] = new OpenApiMediaType { Schema = schema } } 241 + Content = new Dictionary<string, OpenApiMediaType> 242 + { 243 + ["application/json"] = new() { Schema = schema } 244 + } 253 245 }; 254 246 255 - operation.Responses.Remove(((int)status).ToString()); 247 + operation.Responses?.Remove(((int)status).ToString()); 248 + operation.Responses ??= []; 256 249 operation.Responses.Add(((int)status).ToString(), res); 257 250 } 258 251 } ··· 306 299 Description = ReasonPhrases.GetReasonPhrase((int)status), Content = content 307 300 }; 308 301 309 - operation.Responses.Remove(((int)status).ToString()); 302 + operation.Responses?.Remove(((int)status).ToString()); 303 + operation.Responses ??= []; 310 304 operation.Responses.Add(((int)status).ToString(), res); 311 305 } 312 306 } ··· 323 317 324 318 operation.RequestBody = 325 319 GenerateRequestBody(context.ApiDescription, context.SchemaRepository, context.SchemaGenerator); 326 - operation.Parameters.Clear(); 320 + operation.Parameters?.Clear(); 327 321 } 328 322 329 323 private static OpenApiRequestBody? GenerateRequestBody( ··· 371 365 }; 372 366 } 373 367 374 - private static OpenApiSchema GenerateSchema( 368 + private static IOpenApiSchema GenerateSchema( 375 369 Type type, 376 370 SchemaRepository schemaRepository, 377 371 ISchemaGenerator schemaGenerator,