Nestjs Swagger - Publishing different API docs on separate routes - swagger

I am building an app that has public API and internal one. I would like to publish docs for these to different routes. I thought this would be accomplished by adding only certain tags to document (addTag) but after further reading and experiments it does not do the job.
The docs always contain everything, all documented endpoints from all modules.
Is this even possible? If so, how?
I don't believe code is necessary but FWIW:
const pubOptions = new DocumentBuilder()
.setTitle('Pub API Docs')
.setDescription('Blah blah API documentation')
.setVersion(p.version)
.addBearerAuth()
.addTag('public-app')
.build();
const document = SwaggerModule.createDocument(app, pubOptions);
SwaggerModule.setup('public-api', app, document);
const internalOptions = new DocumentBuilder()
.setTitle('Internal API Docs')
.setDescription('Blah blah API documentation')
.setVersion(p.version)
.addBearerAuth()
.addTag('internal')
.build();
const iDocument = SwaggerModule.createDocument(app, internalOptions);
SwaggerModule.setup('internal-api', app, iDocument);

You need to tell the SwaggerModule.createDocument function what modules to include in the swagger that is to be composed. Here are the related docs. As a third parameter, you can pass in an object with an include property that contains an array of modules. These modules are the ones related to the swagger document that is about to be built.

Related

How to serve video file / stream from ASP Net Core 6 Minimal API

I was trying to achieve this following different tutorials but did not succeed. How do I handle a http range request in minimal API to serve video stream ?
I have this bare minimal setup code for API with a single GET path "/video" mapped. I also made a folder "wwwroot" inside project folder. I placed in there a mp4 video file named "test.mp4". Would it be possible for someone knowledgeable to write a simple example of how to stream this file inside my mapped route ?
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
builder.Logging.AddJsonConsole();
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapGet("/video", () =>
{
});
You can use the Results.Stream() method to return a stream from a minimal api.
string wwwroot = builder.Environment.WebRootPath;
...
app.MapGet("/video", () =>
{
string filePath = Path.Combine(wwwroot, "test.mp4");
return Results.Stream(new FileStream(filePath, FileMode.Open));
});
The stream parameter is disposed after the response is sent.
Results.Stream takes a few other optional parameters such as fileDownloadName, and contentType (which defaults to "application/octet-stream") that might be useful to you. Set enableRangeProcessing: true to enable range requests.
The above could easily be adapted to take a filename as a parameter, if you wish. You would need to consider validation (applies equally to the current code TBH). Tested and working for me.

Proper implementation of TokenCache

I'm integrating the Microsoft Graph API into an MVC 5 web app, as well as using ADAL Open ID Connect according to this article:
https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapp-openidconnect-v2/
I'm wondering, how can I provide an implementation of TokenCache that doesn't rely on Session State? What argument should I supply to AcquireTokenForClientAsync? Right now, I'm just supplying a new instance of the class itself as to satisfy the signature of the method. I'd rather the refresh token get handled automatically, as I've read elsewhere. But if you supply null for the TokenCache argument, token cache does not get handled automatically? Here's an example of how I'm getting a token, and supplying new TokenCache() each time I call it.
ConfidentialClientApplication daemonClient = new ConfidentialClientApplication(
AuthConstants.ClientId,
String.Format("https://login.microsoftonline.com/{0}/v2.0", AuthConstants.TenantId),
AuthConstants.RedirectUri,
new ClientCredential(AuthConstants.ClientSecret),
null,
new TokenCache());
AuthenticationResult authResult = await daemonClient.AcquireTokenForClientAsync(new string[] { "https://graph.microsoft.com/.default" });
return authResult.AccessToken;
You need to provide your own implementation to store the content of the cache in the storage you want (be it a database, a file etc). For this, you will set delegates using the SetBeforeAccess, SetAfterAccess, and SetBeforeWrite extension methods of the TokenCache class.
An example of an implementation writing/reading the content of a cache to file is available (for the case of a .NET WPF application) in https://github.com/Azure-Samples/active-directory-b2c-dotnet-desktop/blob/master/active-directory-b2c-wpf/TokenCacheHelper.cs

A simple ASP .NET MVC API controller using roles

I wrote a web application using ASP .NET MVC and authorization system by default. I configured IdentityRole and input through external providers. Using the current database I have created my data context. Now I want to write a Xamarin.Android app and connect to my database, I want a simple API. But the feature that you want to access this API was only available to user with a certain role. The API is really very simple and therefore do not want to add to the draft WCF or WebAPI project. How to do it best?
First, you don't need a separate project to use Web Api; you can use both MVC and Web Api in the same project. For one off endpoints for things like in-site AJAX requests, just creating MVC actions that return JSON or XML would be fine, but if you're talking about a true API, even if it's fairly simplistic, I'd say go Web Api.
You'd protect your Web Api actions much the same as you would your MVC actions, using the [Authorize] attribute. If you need to restrict by role, you just pass a role(s) to that. However, the big difference here, especially if you're serving a mobile app, is that you'll need pass the authorization along with the request. That's generally accomplished using the Authorization header along with a bearer token. Basically, you would need to set up an endpoint that signs a user in and returns a token. Then, each subsequent request that needs authorization includes that token in the header.
I want to finish and to fully answer this question and close this topic. I've been searching for how to add the ability for a mobile client to connect to an existing site on ASP.NET MVC. In my search, I came across a great article Justin Hyland on March 2, 2014
In principle, everything in this article is well and clearly written, but I want to make a tiny contribution for clarity.
Under Setup WebAPIConfig stated that the need
added in the following code to the WebApiConfig Register method
But if we consider the case ASP.NET MVC we don't have such file. It's all very simple, you just need such a file to create the folder App_Start. The contents of the file can be left exactly as it is in the article.
To get rid of the bugs which will inevitably appear we need to install two nuget package: Microsoft.AspNet.WebApi and Microsoft.AspNet.WebApi.Owin.
Excellent! Now we can turn to the method to obtain the token and then adding the token to the query we can get the needed data closed by the attribute [Authorize].
A small remark. If You need to access a method which is closed for a specific role that to the Authenticate method from the article should add a few lines of code. Immediately after the line:
identity.AddClaim(new Claim(ClaimTypes.Name, user));
add the line:
identity.AddClaim(new Claim(ClaimTypes.Role, role));
where role you can get the following, for example:
var userIdentity = UserManager.FindAsync(user, password).Result;
var role = RoleManager.FindById(userIdentity.Roles.First().RoleId).Name;
User and password you have to send a request.
I also want to give an example of code which will send request and receive response. To not have to look for and immediately start coding.
async Task<string> GetToken(string userName, string password)
{
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>( "user", userName ),
new KeyValuePair<string, string> ( "password", password )
}
);
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.PostAsync(APP_PATH + "/Authenticate", content);
var result = await response.Content.ReadAsStringAsync();
return result;
}
}
async Task<string> GetUserInfo(string token)
{
using (var client = CreateClient(token))
{
var response = await client.GetAsync(APP_PATH + "/ValidateToken");
return await response.Content.ReadAsStringAsync();
}
}
HttpClient CreateClient(string accessToken = "")
{
var client = new HttpClient();
if (!string.IsNullOrWhiteSpace(accessToken))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
}
return client;
}
All have only to call the appropriate methods in the correct order. I hope that is useful to someone.
P.S.
If You create a new project in Visual Studio to get this functionality you just need to tick:

Swagger documentation: Swashbuckle (hide methods/properties)

I am using Swagger Swashbuckle to generate documentation. There are some methods in my controller and some properties in my models that I don't want to document.
Is there any arrtibute or the property to leave or ignore specific methods from documentation?
For the method, you have couple of option:
Use Obsolete attribute. Then, you have to set the action - c.IgnoreObsoleteActions(); within the swagger configuration
Create a custom attribute and a swagger document filter. The document filter should iterate through each method and remove the method documentation if the method is having the custom attribute
For the properties, you can use JsonIgnoreAttribute
In addition to c.IgnoreObsoleteActions(), there is also c.IgnoreObsoleteProperties(), which hides the property from the documentation.
JsonIgnoreAttribute will stop the property deserializing when being received as part of a POST request body, which may not be what you want if you only wish to change the documentation and not the functionality.
In more recent version of Swashbuckle (Core2/3) XmlIgnore/JsonIgnore don't seem to work for properties.
Alternatively you can change the property access modifier to internal. This should prevent serialization and generated documentation.
I'm not sure about hiding whole controllers, you will probably need to add filters in your Swagger setup. I do have an example of hiding certain endpoints (for convenience I have prefixed routes for running locally):
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(config => {
config.SwaggerDoc("v1",
new OpenApiInfo {
Version = "v1",
Title = "Foo API",
Description = "Does foo things.",
Contact = new OpenApiContact {
Name = "nope",
Email = "mail#example.org",
},
});
// Include XML comments in Swagger docs
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
config.IncludeXmlComments(xmlPath);
// Filter out prefixed routes
config.DocInclusionPredicate(
(name, desc) => !desc.RelativePath.ToLower().StartsWith("MyDevPrefix"));
});
}
Just a note since I was also trying to figure out the JsonIgnore for properties not working...
The issue seems to be that newer versions of Swashbuckle for .Net Core do not support NewtonSoft out of the box.
Install from NuGet
Package Manager : Install-Package Swashbuckle.AspNetCore.Newtonsoft -Version 5.6.2
CLI : dotnet add package --version 5.6.2 Swashbuckle.AspNetCore.Newtonsoft
Add code to startup.cs
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});
services.AddSwaggerGenNewtonsoftSupport(); // explicit opt-in - needs to be placed after AddSwaggerGen()
This worked for me, hope this helps someone else.
Here's a bit newer answer:
As other's mentioned - to ignore properties (both docs and real response) use attribute: [JsonIgnore]
To hide controller/actions from docs (the controller/action still exists, it is just hidden from docs) use attribute: [ApiExplorerSettings(IgnoreApi = true)]

Laravel with moneris

Can anyone advice me how can I add Moneris payment metnod with laravel 5.1 ?
I have a merchant account. But I am not sure if laravel supports monaris or not.
Thanks in advance.
Laravel by itself doesn't support Moneris (nor any payment processor). However, you can integrate Moneris (and the Moneris API) into your Laravel application by following the directives listed on their developer portal.
Compared to modern payment solutions, such as Stripe or Braintree, Moneris' API can be pretty tedious to use. If you are only using basic purchase, verify, preauth, capture, and refund operations, I suggest you to check out Keith Silgard's library.
However, if you need to implement other operations, such as adding a card to the Vault, you will have to follow Moneris' examples and adapt them to fit into your Laravel Application. For (a very rough) example:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use mpgClasses;
class PaymentController extends Controller
{
protected function addCardToMonerisVault(Request $request) {
/**************************** Request Variables *******************************/
$store_id=getenv('MONERIS_STORE_ID');
$api_token=getenv('MONERIS_API_KEY');
/************************* Transactional Variables ****************************/
$type='res_add_cc';
$cust_id= Auth::user()->id;
$pan=preg_replace('/\D/', '', $request->input('number'));
$expiry_date=$request->input('expiry_year') . $request->input('expiry_month');
$crypt_type='1';
$avs_street_number = '';
$avs_street_name = '';
$avs_zipcode = '';
/*********************** Transactional Associative Array **********************/
$txnArray=array('type'=>$type,
'cust_id'=>$cust_id,
'pan'=>$pan,
'expdate'=>$expiry_date,
'crypt_type'=>$crypt_type
);
/**************************** Transaction Object *****************************/
$mpgTxn = new \mpgTransaction($txnArray);
/****************************** Request Object *******************************/
$mpgRequest = new \mpgRequest($mpgTxn);
/***************************** HTTPS Post Object *****************************/
$mpgHttpPost =new \mpgHttpsPost($store_id,$api_token,$mpgRequest);
/******************************* Response ************************************/
$response = $mpgHttpPost->response;
return $response;
}
}

Resources