I am trying to get the hang of swagger in minimal API. I have the following code:
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(setup => setup.SwaggerDoc("v1", new OpenApiInfo()
{
Description = "An api that will change your life for ever",
Title = "Alert Api",
Version = "v1",
Contact = new OpenApiContact()
{
Name = "Grundfos",
Url = new Uri("https://grundfos.com")
}
}));
WebApplication app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
//Map endpoints
app.MapGet("/alerts", async () => Results.Ok());
app.MapGet("/profiles", async () => Results.Ok());
this gives a swagger UI looking like this:
My question is: How do you sort the endpoints to be under a headline called "alerts" and "profiles"?
I think what you are after is something called Tags in swagger.
You can add WithTags at the end of your mapping, like so:
//Map endpoints
app.MapGet("/alerts", async () => Results.Ok()).WithTags("Alerts");
app.MapGet("/profiles", async () => Results.Ok()).WithTags("Profiles");
The result looks like this:
Alternatively you can also take another approach by configuring the AddSwaggerGen method.
In there you can take the first segment of the URL endpoint and use that as the tag name.
For example, the endpoints alerts and alerts/delete will both be placed in a section called alerts.
builder.Services.AddSwaggerGen(c =>
{
c.TagActionsBy(d =>
{
var rootSegment = d.RelativePath?
.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
.FirstOrDefault() ?? "Home";
return new List<string> { rootSegment! };
});
})
//Map endpoints without 'WithTags`
app.MapGet("/alerts", async () => Results.Ok());
app.MapGet("/alerts/delete", async () => Results.Ok());
app.MapGet("/profiles", async () => Results.Ok());
If you have a bunch of related endpoints and you want to group them in one tag SomethingEndpoints, you can do it by creating a static class named SomethingEndpoints and defining an extension method MapSomethingEndpoints() as follows.
Notes:
The automatically added tags are only available when passing method Job.
Passing (int y) => Job(y) or (int z) => z does not. You need to attach WithTags() manually in this case.
I don't know whether it is a feature by design or a bug!
SomethingEndpoints.cs
static class SomethingEndpoints
{
public static void MapSomethingEndpoints(this IEndpointRouteBuilder routes)
{
var group = routes.MapGroup("/api/v1/job");
group.MapGet("/{x:int}", Job);// no need WithTags!
group.MapGet("/{y:int}", (int y) => Job(y)).WithTags(nameof(SomethingEndpoints));
group.MapGet("/{z:int}", (int z) => z).WithTags(nameof(SomethingEndpoints));
}
static int Job(int x) => x;
}
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapSomethingEndpoints();
app.Run();
i am using Angular for front end. i am using the API request to bring languages and phrases. return data is pushed into declared array variable.
```public data = [];
constructor(private http: HttpClient) {
this.getMyLang();
}
async getMyLang() {
const headers = {
headers: new HttpHeaders({
'X-API-KEY': 'xxxxxx',
})
};
const param = new FormData();
param.append('language', 'en');
await this.http.post('api url', param, headers).subscribe((data1) => {
this.data.push(data1);
});
}```
when i call this method it pushes the data. after console this variable into component am getting following results.
console Screenshot enter code here
I have a simple electron app that wraps around a web app. The web app prompts for user name but electron doesn't show the prompt and directly goes to the 401 Authorization Required page. Is there a setting I need to change to make the prompt show? I can't seem to find it in the documentation. Any help is appreciated.
const { app, BrowserWindow } = require('electron');
function createWindow() {
browserWindow = new BrowserWindow({});
browserWindow.loadURL('https://domain')
}
app.on('ready', createWindow);
Listen to this "login" event.
Create your own prompt. For example, create a browser window which loads an HTML form and when the user fills the username and password fields pass the credentials back via ipc calls to the callback.
app.on("login", (event, webContents, request, authInfo, callback) => {
event.preventDefault();
createAuthPrompt().then(credentials => {
callback(credentials.username, credentials.password);
});
});
function createAuthPrompt() {
const authPromptWin = new BrowserWindow();
authPromptWin.loadFile("auth-form.html"); // load your html form
return new Promise((resolve, reject) => {
ipcMain.once("form-submission", (event, username, password) => {
authPromptWin.close();
const credentials = {
username,
password
};
resolve(credentials);
});
});
}
I'm working on a Rails/React/Redux app using Devise for user authentication. There's something fishy going on somewhere in between my login function and my receiveCurrentUser action where the currentUser becomes changed to an HTML string of the entire document. Here's what happens:
I first dispatch this login function:
export const login = (user) => (dispatch) => {
debugger
return SessionAPIUtil.login(user)
.then(currentUser => {
dispatch(receiveCurrentUser(currentUser));
return currentUser;
},
errors => {
dispatch(receiveSessionErrors(errors.responseJSON));
return errors;
});
};
Putting in a debugger I saw that my user was what it should be:
{username: "test_user", password: "password123"}
A debugger in my login util function (ajax call) still has user as what it should be.
export const login = user => {
debugger
return $.ajax({
method: 'POST',
url: '/users/sign_in',
data: { user }
});
};
However, when it returns from the ajax call to the ".then(..." of the first login function and we enter the receiveCurrentUser:
export const receiveCurrentUser = (currentUser) => {
debugger
return {
type: RECEIVE_CURRENT_USER,
currentUser
};
};
a debugger reveals that currentUser is an HTML string of the document:
Any insight or advice would be greatly appreciated!
I am using asp.net mvc 4 razor and I have a main view that has some checkboxes and a submit button. Those checkboxes indicates the tasks to be performed. User selects the tasks to be performed through the checkboxes and then he launch the process by clicking on the submit button.
Once the submit button is clicked, a the controller associated to this view is called. Within the controller I want to do the following:
1) Open another different view which has a textarea.
2) While controller is performing the tasks selected by the user, I want to update the textarea of the new view just opened (step 1).
3) When controller finishes the tasks I want to stay in the new view just opened (step 1) to wait user action through buttons (return to the previous main view).
Note: The update of the textarea is synchronous.
For example:
Controller:
public ActionResult PerformTasks(ViewModel model)
{
// model contains the values of the checkboxes. With this I know which tasks to perform.
UpdateTextArea("Beginning tasks...");
// ##### Do first task
UpdateTextArea("Doing task #1...");
// Do some stuff for task #1
// ##### Do second task
UpdateTextArea("Doing task #2...");
// Do some stuff for task #2
(...)
// ##### Doing last task
UpdateTextArea("Doing task #N...");
// Do some stuff for task #N
UpdateTextArea("Tasks completed.");
// At the end of the process, new view just opened with contains the textarea
// must remain to user action.
return ¿?
}
The Output in the textarea for the new view just opened would be:
- Textarea content at the end of the process -
Beginning tasks...
Doing task #1...
Doing task #2...
Doing task #3...
...
Doing task #N...
Tasks completed.
How can I do this in an easy way? I do not want to use any third-party frameworks as this web app is very little.
To make it easier, the textarea could be in the same main view rather than in another different new view.
FIRST ATTEMPT (AminSaghi solution):
The main view has the following aspect now (simplified to 2 tasks):
(see at the end my issues when trying to implement it)
#using (Html.BeginForm(
"PerformTasks", "Tests", FormMethod.Post,
htmlAttributes: new { id = "frm" }))
{
(...)
#Html.CheckBoxFor(m => m.task01)<span>Task 1</span><br />
#Html.CheckBoxFor(m => m.task02)<span>Task 2</span><br />
(...)
<input type="submit" value="Do Tasks" />
<div id="divStatus">
</div>
}
<script type="text/javascript">
// First ajax script
$("#frm").submit(function (event) {
$("#frm").validate();
if ($("#frm").valid()) {
$.ajax({
url: "/Tests/PerformTasks/",
type: 'POST',
data: $("#frm").serialize(),
success: function() {
perFormTask1();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig tasks...<br/>');
}
});
event.preventDefault();
}
});
// second ajax script
function performTask1() {
$.ajax({
url: "/Tests/Task1/",
type: 'POST',
data: $("#frm").serialize(),
success: function() {
$("#divStatus").append('Task1 completed.<br/>');
perFormTask2();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig task 1...<br/>');
}
});
};
function performTask2() {
$.ajax({
url: "/Tests/Task2/",
type: 'POST',
data: $("#frm").serialize(),
success: function() {
$("#divStatus").append('Task2 completed.<br/>');
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig task 2...<br/>');
}
});
};
</script>
Controller (TestsController.cs under \Controllers):
public class TestsController : Controller
{
[HttpPost]
public ActionResult PerformTasks(ViewModel model)
{
// Nothing to do here, tasks are done individually in the methods below.
// To stay in the same page after submit button is clicked
return Redirect(this.Request.UrlReferrer.AbsolutePath);
}
[HttpPost]
public ActionResult Task1(ViewModel model)
{
// Task 1 should be done if checkbox in the main view is checked, otherwise not.
bool doTask1 = model.task01;
if (doTask1 )
{
// Do some stuff
}
// To stay in the same page after submit button is clicked
return Redirect(this.Request.UrlReferrer.AbsolutePath);
}
[HttpPost]
public ActionResult Task2(ViewModel model)
{
// Task 2 should be done if checkbox in the main view is checked, otherwise not.
bool doTask2 = model.task02;
if (doTask2)
{
// Do some stuff
}
// To stay in the same page after submit button is clicked
return Redirect(this.Request.UrlReferrer.AbsolutePath);
}
}
The model:
public class ViewModel
{
public bool task01{ get; set; }
public bool task02{ get; set; }
}
Things I do not understand and I do not kwnow how to do:
1.- Once submit button is clicked, how to launch first ajax script in order to start the tasks sequence?
2.- Action PerformTasks as I understand should be leave empty, only return to the same page line should be put, am I right, because it
only launches the others in the ajax script.
3.- What is #frm in the ajax script? should i replace with something?
4.-I think for the last task, in this case task 2, is not necessary to do another ajax script as this is the last, Am I right?
5.-If some task fails, for example task 1, below tasks should be done, in this case task 2. How to do this?
6.-For each task I should pass some data, the status of all checkboxes and the within each action in the controller check if
this task has been checked to be done. If so, task is performed, if
not, task is not performed. How to pass this data to tasks, 1 and 2?
through data element in ajax?
One way is to brick your action method into separate task:
public ActionResult PerformTasks(ViewModel model)
{
//
}
public ActionResult Task1(string param1, string param2, ...)
{
//
}
public ActionResult Task2((string param1, string param2, ...)
{
//
}
// and so on...
Then, in your view, put each of them into the ajax success option of its previous task ajax request:
$.ajax({
url: "/Controller/PerformTasks/",
type: 'POST',
data: $("#frm").serialize(),
success: function() {
perFormTask1();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig tasks...<br/>');
}
});
And function performTask1 can be like the following:
$.ajax({
url: "/Controller/Task1/",
type: 'POST',
data: ... // here or by query string,
success: function() {
$("#divStatus").append('Task1 completed.<br/>');
perFormTask2();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig task 1...<br/>');
}
});
And so on for other tasks...
So, the semi-complete how-to is like the following:
1) Change your Html.BeginForm() like this:
#using(Html.BeginForm(
"action", "controller", FormMethod.Post,
htmlAttributes: new { id = "frm"}))
{
// in fact, in our situation,
// there is no matter to put correct values in action and controller parameters
// because we'll override them and do our job through ajax...
}
2) Add the following script into your view:
<script>
$("#frm").submit(function (event) {
$("#frm").validate();
if ($("#frm").valid()) {
$.ajax({
url: "/Controller/PerformTasks/",
type: 'POST',
data: $("#frm").serialize(),
success: function () {
perFormTask1();
},
beforeSend: function () {
$("#divStatus").append('<br/>Begginig tasks...<br/>');
}
});
event.preventDefault();
}
});
function performTask1() {
$.ajax({
url: "/Controller/Task1?param1=data1¶m2=data2 ...",
type: 'POST',
success: function() {
$("#divStatus").append('Task1 completed.<br/>');
perFormTask2();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig task 1...<br/>');
}
});
}
// and also for other task, add similar performTask functions...
</script>