From cd28845d7bad7da2c015829c5af46a89213a3758 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Mon, 8 Oct 2018 00:09:30 +0200 Subject: [PATCH] Add annotations to swagger + more ASF API breaking changes that @Aareksio is ready for --- ArchiSteamFarm/ArchiSteamFarm.csproj | 1 + .../IPC/Controllers/Api/ASFController.cs | 10 ++++++ .../IPC/Controllers/Api/BotController.cs | 33 ++++++++++++++----- .../IPC/Controllers/Api/CommandController.cs | 5 +++ .../IPC/Controllers/Api/NLogController.cs | 6 ++++ .../Controllers/Api/StructureController.cs | 5 +++ .../IPC/Controllers/Api/TypeController.cs | 5 +++ .../IPC/Controllers/Api/WWWController.cs | 29 ++++++++++------ ArchiSteamFarm/IPC/Startup.cs | 1 + 9 files changed, 77 insertions(+), 18 deletions(-) diff --git a/ArchiSteamFarm/ArchiSteamFarm.csproj b/ArchiSteamFarm/ArchiSteamFarm.csproj index 77470f06a..1d4275f03 100644 --- a/ArchiSteamFarm/ArchiSteamFarm.csproj +++ b/ArchiSteamFarm/ArchiSteamFarm.csproj @@ -56,6 +56,7 @@ + diff --git a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs index a1fe2c457..0ef09f52d 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs @@ -27,16 +27,21 @@ using ArchiSteamFarm.IPC.Requests; using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.Localization; using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; namespace ArchiSteamFarm.IPC.Controllers.Api { [ApiController] [Produces("application/json")] [Route("Api/ASF")] + [SwaggerResponse(400, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))] + [SwaggerResponse(401, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] + [SwaggerResponse(403, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] public sealed class ASFController : ControllerBase { /// /// Fetches common info related to ASF as a whole. /// [HttpGet] + [SwaggerResponse(200, type: typeof(GenericResponse))] public ActionResult> ASFGet() { uint memoryUsage = (uint) GC.GetTotalMemory(false) / 1024; @@ -53,7 +58,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// /// Updates ASF's global config. /// + [Consumes("application/json")] [HttpPost] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task> ASFPost([FromBody] ASFRequest request) { if (request == null) { ASF.ArchiLogger.LogNullError(nameof(request)); @@ -81,6 +88,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Makes ASF shutdown itself. /// [HttpPost("Exit")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public ActionResult ExitPost() { (bool success, string output) = Actions.Exit(); return Ok(new GenericResponse(success, output)); @@ -90,6 +98,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Makes ASF restart itself. /// [HttpPost("Restart")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public ActionResult RestartPost() { (bool success, string output) = Actions.Restart(); return Ok(new GenericResponse(success, output)); @@ -99,6 +108,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Makes ASF update itself. /// [HttpPost("Update")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task>> UpdatePost() { (bool success, Version version) = await Actions.Update().ConfigureAwait(false); return Ok(new GenericResponse(success, version)); diff --git a/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs b/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs index 7c750bbb5..825717cc6 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs @@ -29,16 +29,21 @@ using ArchiSteamFarm.IPC.Requests; using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.Localization; using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; namespace ArchiSteamFarm.IPC.Controllers.Api { [ApiController] [Produces("application/json")] [Route("Api/Bot")] + [SwaggerResponse(400, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))] + [SwaggerResponse(401, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] + [SwaggerResponse(403, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] public sealed class BotController : ControllerBase { /// /// Deletes all files related to given bots. /// [HttpDelete("{botNames:required}")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task> BotDelete(string botNames) { if (string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(botNames)); @@ -58,24 +63,27 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Fetches common info related to given bots. /// [HttpGet("{botNames:required}")] - public ActionResult>> BotGet(string botNames) { + [SwaggerResponse(200, type: typeof(GenericResponse>))] + public ActionResult>> BotGet(string botNames) { if (string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(botNames)); - return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); } HashSet bots = Bot.GetBots(botNames); if (bots == null) { - return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsInvalid, nameof(bots)))); + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsInvalid, nameof(bots)))); } - return Ok(new GenericResponse>(bots)); + return Ok(new GenericResponse>(bots.ToDictionary(bot => bot.BotName, bot => bot))); } /// /// Updates bot config of given bot. /// + [Consumes("application/json")] [HttpPost("{botName:required}")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task> BotPost(string botName, [FromBody] BotRequest request) { if (string.IsNullOrEmpty(botName) || (request == null)) { ASF.ArchiLogger.LogNullError(nameof(botName) + " || " + nameof(request)); @@ -113,6 +121,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Removes BGR output files of given bots. /// [HttpDelete("{botNames:required}/GamesToRedeemInBackground")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task> GamesToRedeemInBackgroundDelete(string botNames) { if (string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(botNames)); @@ -132,15 +141,16 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Fetches BGR output files of given bots. /// [HttpGet("{botNames:required}/GamesToRedeemInBackground")] - public async Task>>> GamesToRedeemInBackgroundGet(string botNames) { + [SwaggerResponse(200, type: typeof(GenericResponse>))] + public async Task>>> GamesToRedeemInBackgroundGet(string botNames) { if (string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(botNames)); - return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); } HashSet bots = Bot.GetBots(botNames); if ((bots == null) || (bots.Count == 0)) { - return BadRequest(new GenericResponse>(false, string.Format(Strings.BotNotFound, botNames))); + return BadRequest(new GenericResponse>(false, string.Format(Strings.BotNotFound, botNames))); } IList<(Dictionary UnusedKeys, Dictionary UsedKeys)> results = await Utilities.InParallel(bots.Select(bot => bot.GetUsedAndUnusedKeys())).ConfigureAwait(false); @@ -152,13 +162,15 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { result[bot.BotName] = new GamesToRedeemInBackgroundResponse(unusedKeys, usedKeys); } - return Ok(new GenericResponse>(result)); + return Ok(new GenericResponse>(result)); } /// /// Adds keys to redeem using BGR to given bot. /// + [Consumes("application/json")] [HttpPost("{botName:required}/GamesToRedeemInBackground")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task>> GamesToRedeemInBackgroundPost(string botName, [FromBody] GamesToRedeemInBackgroundRequest request) { if (string.IsNullOrEmpty(botName) || (request == null)) { ASF.ArchiLogger.LogNullError(nameof(botName) + " || " + nameof(request)); @@ -180,7 +192,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// /// Pauses given bots. /// + [Consumes("application/json")] [HttpPost("{botNames:required}/Pause")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task> PausePost(string botNames, [FromBody] BotPauseRequest request) { if (string.IsNullOrEmpty(botNames) || (request == null)) { ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request)); @@ -200,6 +214,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Resumes given bots. /// [HttpPost("{botNames:required}/Resume")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task> ResumePost(string botNames) { if (string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(botNames)); @@ -219,6 +234,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Starts given bots. /// [HttpPost("{botNames:required}/Start")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task> StartPost(string botNames) { if (string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(botNames)); @@ -238,6 +254,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Stops given bots. /// [HttpPost("{botNames:required}/Stop")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task> StopPost(string botNames) { if (string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(botNames)); diff --git a/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs b/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs index e2c1915da..273423c5a 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs @@ -25,11 +25,15 @@ using System.Threading.Tasks; using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.Localization; using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; namespace ArchiSteamFarm.IPC.Controllers.Api { [ApiController] [Produces("application/json")] [Route("Api/Command")] + [SwaggerResponse(400, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))] + [SwaggerResponse(401, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] + [SwaggerResponse(403, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] public sealed class CommandController : ControllerBase { /// /// Executes a command. @@ -39,6 +43,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// You should use "given bot" commands when executing this endpoint, omitting targets of the command will cause the command to be executed on first defined bot /// [HttpPost("{command:required}")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task>> CommandPost(string command) { if (string.IsNullOrEmpty(command)) { ASF.ArchiLogger.LogNullError(nameof(command)); diff --git a/ArchiSteamFarm/IPC/Controllers/Api/NLogController.cs b/ArchiSteamFarm/IPC/Controllers/Api/NLogController.cs index a564c9184..64c5f877d 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/NLogController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/NLogController.cs @@ -20,6 +20,7 @@ // limitations under the License. using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Net.WebSockets; using System.Text; @@ -30,11 +31,15 @@ using ArchiSteamFarm.Localization; using ArchiSteamFarm.NLog; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; +using Swashbuckle.AspNetCore.Annotations; namespace ArchiSteamFarm.IPC.Controllers.Api { [ApiController] [Produces("application/json")] [Route("Api/NLog")] + [SwaggerResponse(400, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))] + [SwaggerResponse(401, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] + [SwaggerResponse(403, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] public sealed class NLogController : ControllerBase { private static readonly ConcurrentDictionary ActiveLogWebSockets = new ConcurrentDictionary(); @@ -45,6 +50,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// This API endpoint requires a websocket connection. /// [HttpGet] + [SwaggerResponse(200, type: typeof(IEnumerable>))] public async Task NLogGet() { if (!HttpContext.WebSockets.IsWebSocketRequest) { return BadRequest(new GenericResponse(false, string.Format(Strings.WarningFailedWithError, nameof(HttpContext.WebSockets.IsWebSocketRequest) + ": " + HttpContext.WebSockets.IsWebSocketRequest))); diff --git a/ArchiSteamFarm/IPC/Controllers/Api/StructureController.cs b/ArchiSteamFarm/IPC/Controllers/Api/StructureController.cs index 1665d9038..2e335df6c 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/StructureController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/StructureController.cs @@ -23,11 +23,15 @@ using System; using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.Localization; using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; namespace ArchiSteamFarm.IPC.Controllers.Api { [ApiController] [Produces("application/json")] [Route("Api/Structure")] + [SwaggerResponse(400, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))] + [SwaggerResponse(401, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] + [SwaggerResponse(403, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] public sealed class StructureController : ControllerBase { /// /// Fetches structure of given type. @@ -36,6 +40,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Structure is defined as a representation of given object in its default state. /// [HttpGet("{structure:required}")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public ActionResult> StructureGet(string structure) { if (string.IsNullOrEmpty(structure)) { ASF.ArchiLogger.LogNullError(nameof(structure)); diff --git a/ArchiSteamFarm/IPC/Controllers/Api/TypeController.cs b/ArchiSteamFarm/IPC/Controllers/Api/TypeController.cs index f9baf89c4..52101c879 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/TypeController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/TypeController.cs @@ -27,11 +27,15 @@ using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.Localization; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; +using Swashbuckle.AspNetCore.Annotations; namespace ArchiSteamFarm.IPC.Controllers.Api { [ApiController] [Produces("application/json")] [Route("Api/Type")] + [SwaggerResponse(400, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))] + [SwaggerResponse(401, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] + [SwaggerResponse(403, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] public sealed class TypeController : ControllerBase { /// /// Fetches type info of given type. @@ -40,6 +44,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// Type info is defined as a representation of given object with its fields and properties being assigned to a string value that defines their type. /// [HttpGet("{type:required}")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public ActionResult> TypeGet(string type) { if (string.IsNullOrEmpty(type)) { ASF.ArchiLogger.LogNullError(nameof(type)); diff --git a/ArchiSteamFarm/IPC/Controllers/Api/WWWController.cs b/ArchiSteamFarm/IPC/Controllers/Api/WWWController.cs index 40f309330..a6a71c724 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/WWWController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/WWWController.cs @@ -28,11 +28,15 @@ using ArchiSteamFarm.IPC.Requests; using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.Localization; using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; namespace ArchiSteamFarm.IPC.Controllers.Api { [ApiController] [Produces("application/json")] [Route("Api/WWW")] + [SwaggerResponse(400, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))] + [SwaggerResponse(401, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] + [SwaggerResponse(403, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + "https://github.com/" + SharedInfo.GithubRepo + "/wiki/IPC#authentication.")] public sealed class WWWController : ControllerBase { /// /// Fetches files in given directory relative to WWW root. @@ -41,15 +45,16 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW as they can disappear and change anytime. /// [HttpGet("Directory/{directory:required}")] - public ActionResult>> DirectoryGet(string directory) { + [SwaggerResponse(200, type: typeof(GenericResponse>))] + public ActionResult>> DirectoryGet(string directory) { if (string.IsNullOrEmpty(directory)) { ASF.ArchiLogger.LogNullError(nameof(directory)); - return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(directory)))); + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(directory)))); } string directoryPath = Path.Combine(ArchiKestrel.WebsiteDirectory, directory); if (!Directory.Exists(directoryPath)) { - return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsInvalid, directory))); + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsInvalid, directory))); } string[] files; @@ -57,11 +62,11 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { try { files = Directory.GetFiles(directoryPath); } catch (Exception e) { - return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorParsingObject, nameof(files)) + Environment.NewLine + e)); + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorParsingObject, nameof(files)) + Environment.NewLine + e)); } HashSet result = files.Select(Path.GetFileName).ToHashSet(); - return Ok(new GenericResponse>(result)); + return Ok(new GenericResponse>(result)); } /// @@ -71,18 +76,19 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW as they can disappear and change anytime. /// [HttpGet("GitHub/Releases")] - public async Task>>> GitHubReleasesGet([FromQuery] byte count = 10) { + [SwaggerResponse(200, type: typeof(GenericResponse>))] + public async Task>>> GitHubReleasesGet([FromQuery] byte count = 10) { if (count == 0) { - return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(count)))); + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(count)))); } List response = await GitHub.GetReleases(count).ConfigureAwait(false); if ((response == null) || (response.Count == 0)) { - return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries))); + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries))); } - IEnumerable result = response.Select(singleResponse => new GitHubReleaseResponse(singleResponse)); - return Ok(new GenericResponse>(result)); + List result = response.Select(singleResponse => new GitHubReleaseResponse(singleResponse)).ToList(); + return Ok(new GenericResponse>(result)); } /// @@ -92,6 +98,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW as they can disappear and change anytime. /// [HttpGet("GitHub/Releases/{version:required}")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task>> GitHubReleasesGet(string version) { if (string.IsNullOrEmpty(version)) { return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(version)))); @@ -111,7 +118,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { /// /// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW as they can disappear and change anytime. /// + [Consumes("application/json")] [HttpPost("Send")] + [SwaggerResponse(200, type: typeof(GenericResponse))] public async Task>> SendPost([FromBody] WWWSendRequest request) { if (request == null) { ASF.ArchiLogger.LogNullError(nameof(request)); diff --git a/ArchiSteamFarm/IPC/Startup.cs b/ArchiSteamFarm/IPC/Startup.cs index 733f18c4f..424af687a 100644 --- a/ArchiSteamFarm/IPC/Startup.cs +++ b/ArchiSteamFarm/IPC/Startup.cs @@ -95,6 +95,7 @@ namespace ArchiSteamFarm.IPC { services.AddSwaggerGen( c => { c.DescribeAllEnumsAsStrings(); + c.EnableAnnotations(); c.SwaggerDoc("ASF", new Info { Title = "ASF API" }); string xmlDocumentationFile = Path.Combine(AppContext.BaseDirectory, SharedInfo.AssemblyDocumentation);