I am trying to use swagger-config.yaml to configure swagger UI as mentioned in the document.
The document mentions parameters like requestInterceptor or responseInterceptor, but they are all defined as a function. I don't think I can really put a function in yaml file per specification, and I have tried to put function in it as string but swagger ui won't pick it up.
My question is can I use requestInterceptor or responseInterceptor in the swagger-config.yaml file or these parameters cannot be used in config file? Thanks.
You are right that the requestInerceptor and responseInterceptor cannot be defined in the swagger-config.yaml file. They can only be defined in JavaScript:
const ui = SwaggerUIBundle({
"dom_id": "#swagger-ui",
deepLinking: true,
...
requestInterceptor: function(req) {
req.headers["MyCustomHeader"] = "value";
return req;
}
})
Related
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.
My controller code is something like this.
#Controller('customer')
export class CustomerController{
constructor(private readonly customerService: CustomerService){}
#Post('lookup')
async someMethod(#Body() body:any){
console.log("BEGIN -- CustomerController.someMethod");
I am expecting to see in Swagger a place where I can input some text as a request body but instead I see this
Add #ApiProperty()
export class User{
#ApiProperty()
name:string
}
So it sounds like there's a few things going on here. The Swagger UI is a helper tool for sending in requests, but to do that it needs to know the shape of the request body. any is not good enough. If you're looking for a tool that allows you to send in anything, curl or postman are you best bets (at least for free).
Nest has a Swagger plugin that will read through your Typescript code and decorate your types and method accordingly, but you have to opt in to enable it. Otherwise, you need to use the decorators from the #nestjs/swagger package to tell Swagger what types are expected in and out of the methods.
So long as the type that corresponds to #Body() has swagger decorators or you enable the swagger plugin and have a valid class, the swagger UI should show up as expected, but with the above and using type any it won't do you any good.
My endpoint accepts unknown key/value data and I was having the same problem (I tried any, unknown, Record<string, any>, object, {}). Finally #Body() data: Map<string, any> worked for me.
try it like this:
#ApiBody({description: "body:any someMethod"})
#Post('lookup')
async someMethod(#Body() body:any){
console.log("BEGIN -- CustomerController.someMethod");
}
I would recommend using dto for body.
Refer to documentation.
Example of a DTO is shown below.
DTO:
import { ApiProperty } from '#nestjs/swagger';
export class CreateCatDto {
#ApiProperty()
name: string;
#ApiProperty()
age: number;
#ApiProperty()
breed: string;
}
Function
#Post()
async create(#Body() createCatDto: CreateCatDto) {
//Do Stuff.
}
#ApiProperty adds properties to swagger request.
It should show something like this:
#Post()
#ApiBody({ type: CreateCatDto })
async create(#Body() createCatDto: CreateCatDto) {
//Do Stuff.
}
The above code is going to give output similar to below where your schema is also going to be documented:
Hope this helps.
Swagger is unable to interpret your code. It is not an issue with your code. If your goal is to test your API for the UI team to use and not a comprehensive swagger documentation, then I found it easiest to just use Postman. Try hitting your API using Postman.
I can customize OpenAPI from code.
Can I do same over openapi.yaml like swagger-petstore
I create simple springboot project with one #RestController.
I create openapi.yaml and copy it to /src/main/resources/.
But I see default values on open swagger-ui page.
This is available from the FAQ page in the spring-doc documentation.
See What is a proper way to set up Swagger UI to use provided spec.yml? and How can use custom json/yml file instead of generated one ? of the same page.
Example from the FAQ page
Turn off auto-generation in the project property file springdoc.api-docs.enabled=false
Put your yaml file in src/main/resources/static such as src/main/resources/static/myApiFile.yaml
Set the swagger-ui url for the file springdoc.swagger-ui.url=/myApiFile.yaml
Enable the minimal beans configuration
import org.springdoc.core.SpringDocConfigProperties;
import org.springdoc.core.SpringDocConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class SpringDocsConfiguration {
#Bean
SpringDocConfiguration springDocConfiguration() {
return new SpringDocConfiguration();
}
#Bean
public SpringDocConfigProperties springDocConfigProperties() {
return new SpringDocConfigProperties();
}
}
The code below is all what we needed to do to use openapi.yaml specification file instead of the default one that is generated from code.
Explanation:
org.springdoc.webflux.api.OpenApiResource is Controller that handles /v3/api-docs and /v3/api-docs.yaml endpoints. Swagger UI is using that endpoint to show swagger ui page - /swagger-ui.html. You can see the configuration when you hit /v3/api-docs/swagger-config endpoint.
org.springdoc.webflux.api.OpenApiResource bean is registered only if missing. You can see it in SpringDocWebFluxConfiguration. The method that creates the bean is annotated with #ConditionalOnMissingBean. So you just need to extend it and adjust OpenApi specification retrieval (see below).
org.springdoc.webflux.api.OpenApiResource is using getOpenApi() method to retrieve OpenAPI specification (by default the specification is generated based on the class annotation from code). So you just need to override getOpenApi() method and provide the specification from yaml file itself (getYamlMapper() method is also provided for you in the parent classes, so it's really that easy how it is in the file below)
You can see OpenApiResource is in webflux package because we use org.springdoc:springdoc-openapi-webflux-ui, Spring WebFlux. It is done similarly in Spring MVC.
Hope this helps :) When you hit /swagger-ui.html you should see the docs directly from .yaml spec. When you hit /v3/api-docs you should see the specs itself in JSON. When you hit /v3/api-docs.yaml you should see the specs itself in YAML. No Spring Configuration code is needed. Just the controller as you see below :)
Just to be clear. Our OpenAPI spec is in src/main/resources/openapi/api.yaml
package com.your.package;
...imports omitted for readability...
import org.springdoc.webflux.api.OpenApiResource;
#RestController
public class OpenApiController extends OpenApiResource {
#Value("classpath:openapi/api.yaml")
private Resource openAPIResource;
private OpenAPI openAPI;
public OpenApiController(ObjectFactory<OpenAPIBuilder> openAPIBuilderObjectFactory, AbstractRequestBuilder requestBuilder, GenericResponseBuilder responseBuilder, OperationBuilder operationParser, RequestMappingInfoHandlerMapping requestMappingHandlerMapping, Optional<List<OperationCustomizer>> operationCustomizers, Optional<List<OpenApiCustomiser>> openApiCustomisers, SpringDocConfigProperties springDocConfigProperties, Optional<ActuatorProvider> actuatorProvider) {
super(openAPIBuilderObjectFactory, requestBuilder, responseBuilder, operationParser, requestMappingHandlerMapping, operationCustomizers, openApiCustomisers, springDocConfigProperties, actuatorProvider);
}
#SneakyThrows
#PostConstruct
public void initOpenAPI() {
openAPI = getYamlMapper().readValue(openAPIResource.getInputStream(), OpenAPI.class);
}
#Override
protected synchronized OpenAPI getOpenApi() {
return openAPI;
}
}
If you need configuration file, you can have a look at the FAQ, documentation:
https://springdoc.org/faq.html#can-i-use-spring-property-with-swagger-annotations
And here is the link for code samples:
https://raw.githubusercontent.com/springdoc/springdoc-openapi/master/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app15/SpringDocApp15Test.java
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)]
The syntax for dependency injection in Angular.js is confusing me.
I have a Rails app that is using Angular. One of the directives needs to use the $cookies service. So I have the main Javascript file where I declare the angular app, and a directives folder with js-files for my directives.
So this is the relevant part of the main js file. I'm trying to inject the ngCookies module into it:
app.js
angular.module('myApp', [
'templates',
'ngCookies'
]);
and here is the file with the directive that needs the $cookies service:
my-directive.js
angular.module('myApp')
.directive("myDirective", ['$cookies', function(){
return {
restrict: 'E'
templateUrl: "my-directive-template.html",
scope: {
article: '=ngModel'
},
link: function(scope, element, attrs){
scope.myFunction = function(){
$cookies.example = "hello world"; // set a cookie
};
}
};
}]);
So I'm trying to inject the ngCookies module into the myApp module and then inject the $cookies service into the directive.
This syntax doesn't work; Firebug gives me an error: "Error: $cookies is undefined".
Could you please help me figure out how to inject dependencies in Angular properly?
Oh my! I guess the only thing I needed was to add the $cookies as an attribute for the function declaration as well so that the line
.directive("myDirective", ['$cookies', function(){
became
.directive("myDirective", ['$cookies', function($cookies){