Code Monkey home page Code Monkey logo

springdoc-openapi's Introduction

Octocat Build Status Quality Gate Known Vulnerabilities Stack Exchange questions

IMPORTANT: springdoc-openapi v1.8.0 is the latest Open Source release supporting Spring Boot 2.x and 1.x.

An extended support for springdoc-openapi v1 project is now available for organizations that need support beyond 2023.

For more details, feel free to reach out: [email protected]

springdoc-openapi is on Open Collective. If you ❤️ this project consider becoming a sponsor.

This project is sponsored by

  

Table of Contents

Introduction

The springdoc-openapi Java library helps automating the generation of API documentation using Spring Boot projects. springdoc-openapi works by examining an application at runtime to infer API semantics based on Spring configurations, class structure and various annotations.

The library automatically generates documentation in JSON/YAML and HTML formatted pages. The generated documentation can be complemented using swagger-api annotations.

This library supports:

  • OpenAPI 3
  • Spring-boot v3 (Java 17 & Jakarta EE 9)
  • JSR-303, specifically for @NotNull, @Min, @Max, and @Size.
  • Swagger-ui
  • OAuth 2
  • GraalVM native images

The following video introduces the Library:

For spring-boot v3 support, make sure you use springdoc-openapi v2

This is a community-based project, not maintained by the Spring Framework Contributors (Pivotal)

Getting Started

Library for springdoc-openapi integration with spring-boot and swagger-ui

  • Automatically deploys swagger-ui to a Spring Boot 3.x application
  • Documentation will be available in HTML format, using the official swagger-ui jars.
  • The Swagger UI page should then be available at http://server: port/context-path/swagger-ui.html and the OpenAPI description will be available at the following url for json format: http://server:port/context-path/v3/api-docs
    • server: The server name or IP
    • port: The server port
    • context-path: The context path of the application
  • Documentation can be available in yaml format as well, on the following path: /v3/api-docs.yaml
  • Add the springdoc-openapi-ui library to the list of your project dependencies (No additional configuration is needed):
   <dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
      <version>last-release-version</version>
   </dependency>
  • This step is optional: For custom path of the swagger documentation in HTML format, add a custom springdoc property, in your spring-boot configuration file:
# swagger-ui custom path
springdoc.swagger-ui.path=/swagger-ui.html

Spring-boot with OpenAPI Demo applications.

Branching

Integration of the library in a Spring Boot 3.x project without the swagger-ui:

  • Documentation will be available at the following url for json format: http://server: port/context-path/v3/api-docs
    • server: The server name or IP
    • port: The server port
    • context-path: The context path of the application
  • Documentation will be available in yaml format as well, on the following path : /v3/api-docs.yaml
  • Add the library to the list of your project dependencies. (No additional configuration is needed)
   <dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
      <version>last-release-version</version>
   </dependency>
  • This step is optional: For custom path of the OpenAPI documentation in Json format, add a custom springdoc property, in your spring-boot configuration file:
# /api-docs endpoint custom path
springdoc.api-docs.path=/api-docs
  • This step is optional: If you want to disable springdoc-openapi endpoints, add a custom springdoc property, in your spring-boot configuration file:
# disable api-docs
springdoc.api-docs.enabled=false

Error Handling for REST using @ControllerAdvice

To generate documentation automatically, make sure all the methods declare the HTTP Code responses using the annotation: @ResponseStatus.

Adding API Information and Security documentation

The library uses spring-boot application auto-configured packages to scan for the following annotations in spring beans: OpenAPIDefinition and Info. These annotations declare, API Information: Title, version, licence, security, servers, tags, security and externalDocs. For better performance of documentation generation, declare @OpenAPIDefinition and @SecurityScheme annotations within a Spring managed bean.

spring-webflux support with Annotated Controllers

  • Documentation can be available in yaml format as well, on the following path : /v3/api-docs.yaml
  • Add the library to the list of your project dependencies (No additional configuration is needed)
   <dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
      <version>last-release-version</version>
   </dependency>
  • This step is optional: For custom path of the swagger documentation in HTML format, add a custom springdoc property, in your spring-boot configuration file:
# swagger-ui custom path
springdoc.swagger-ui.path=/swagger-ui.html

The springdoc-openapi libraries are hosted on maven central repository. The artifacts can be viewed accessed at the following locations:

Releases:

Snapshots:

Acknowledgements

Contributors

springdoc-openapi is relevant and updated regularly due to the valuable contributions from its contributors.

Thanks you all for your support!

Additional Support

  • Spring Team - Thanks for their support by sharing all relevant resources around Spring projects.
  • JetBrains - Thanks a lot for supporting springdoc-openapi project.

JenBrains logo

springdoc-openapi's People

Contributors

bnasslahsen avatar chrisupb avatar devnied avatar e-build avatar eshizhan avatar footaku avatar gibahjoe avatar hisener avatar hismaili avatar ianwallen avatar jgentner1 avatar joaodias14 avatar johnniang avatar jryan128 avatar kaibra avatar kennysoft avatar m-kay avatar mosesonline avatar nathankooij avatar natrem avatar neiser avatar patrykpacewicz avatar ptahchiev avatar pyguy2 avatar quom avatar sawant-abhijeet avatar sokomishalov avatar uc4w6c avatar viktor-berglund-mw avatar zinzoddari avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

springdoc-openapi's Issues

Attempting to add @SecurityScheme to annotation results in a NPE.

Example: @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) @Retention(AnnotationRetention.RUNTIME) @RestController @RequestMapping("/api/v1/pdf") @SecurityScheme(type = SecuritySchemeType.APIKEY, in = SecuritySchemeIn.HEADER, name="Authorization", bearerFormat = "Bearer", description = "A core-auth Bearer token") annotation class V1ApiController( @get:AliasFor(annotation = RestController::class) val value: String = "" )

components.getSecuritySchemes() on line 155 is null.

Caused by: java.lang.NullPointerException at org.springdoc.core.GeneralInfoBuilder.addSecurityScheme(GeneralInfoBuilder.java:155) ~[springdoc-openapi-common-1.1.18.jar:?] at org.springdoc.core.GeneralInfoBuilder.calculateSecuritySchemes(GeneralInfoBuilder.java:124) ~[springdoc-openapi-common-1.1.18.jar:?] at org.springdoc.core.GeneralInfoBuilder.build(GeneralInfoBuilder.java:64) ~[springdoc-openapi-common-1.1.18.jar:?] at org.springdoc.api.AbstractOpenApiResource.getOpenApi(AbstractOpenApiResource.java:62) ~[springdoc-openapi-common-1.1.18.jar:?] at org.springdoc.api.OpenApiResource.openapiJson(OpenApiResource.java:53) ~[springdoc-openapi-core-1.1.18.jar:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?] at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE] ... 52 more

Support beans as parameter in @GetMapping / components empty

It would be great if beans are supported in GET endpoints.

@RestController
public class MyController {
    @GetMapping
    public Object persons(@Valid PersonDto person) {
    }
}

class PersonDto {
   @NotBlank private String name;
   @NotNull private Integer age;
}

In this case, the following error is printed:

Resolver error at paths./my/persons.get.parameters.0.schema.$ref
Could not resolve reference: Could not resolve pointer: /components/schemas/PersonDto does not exist in document

Support for runtime customization (e.g. post-processing) of generated spec

Thanks for providing this library.

It would be very useful to be able to customize the generated OpenAPI spec at runtime, e.g. generating response models dynamically.

For a more specific description of the kinds of hooks I refer to, please consider the ReaderListener and SpecFilter APIs described here: https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Extensions#configuration

I see that #4 already implements support for preprocessing the definition but not for post-processing (or filtering/modification).

Ignored allowableValues in @ApiParam

As I think, annotation
@ApiParam(value = "Фильтр по типу продажи", allowableValues = "Аренда, Продажа") @RequestParam(value = "saleTypes",...
must produce

parameters:
- name: saleTypes
        in: query
        required: false
        description: Фильтр по типу продажи
        schema:
          type: array
          items:
            type: string
            enum:
              - Аренда
              - Продажа

but enum part is ommited.

Nullpointerexception with Spring Security

Hi, I tried to use this with Spring Security and get:

17:03:04.897 ERROR: org.springframework.core.log.CompositeLog.error() - [4eb87eeb/6] 500 Server Error for HTTP GET "/api-docs": java.lang.NullPointerException
at org.springdoc.core.RequestBuilder.build(RequestBuilder.java:36)

It works without Spring Security, so only change...

Can you please take a look? Thanks.

Allow to customize OpenAPI object programmatically

The only way to customize the OpenAPI header values is by declaring a bean having the OpenAPIDefinition annotation. But this way the values can't be built programmatically, e.g. I want to build the security schemas by looking at some properties configured in the external configuration file of my Spring application.

OpenApiResource should not require reactive RequestMappingInfoHandlerMapping

OpenApiResource controller requires org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping from reactive package.

Problem: when the application is deployed to a standalone tomcat server (which is a org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type.SERVLET type), then the application won't start with following error:

[][] 2019-08-05 15:54:46,720 WARN o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'openApiResource': Unsatisfied dependency expressed through field 'requestMappingHandlerMapping'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
[][] 2019-08-05 15:54:46,910 ERROR o.s.b.d.LoggingFailureAnalysisReporter: 

***************************
APPLICATION FAILED TO START
***************************

Description:

Field requestMappingHandlerMapping in org.springdoc.api.OpenApiResource required a bean of type 'org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)

The following candidates were found but could not be injected:
	- Bean method 'cloudFoundryWebFluxEndpointHandlerMapping' in 'ReactiveCloudFoundryActuatorAutoConfiguration' not loaded because not a reactive web application
	- Bean method 'webEndpointReactiveHandlerMapping' in 'WebFluxEndpointManagementContextConfiguration' not loaded because not a reactive web application
	- Bean method 'controllerEndpointHandlerMapping' in 'WebFluxEndpointManagementContextConfiguration' not loaded because not a reactive web application


Action:

Consider revisiting the entries above or defining a bean of type 'org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping' in your configuration.

The question is: why is WebMvcAutoConfiguration.EnableWebMvcConfiguration.requestMappingHandlerAdapter() autowiring the RequestMappingHandlerAdapter correctly in a tomcat standalone environment (eg during dev inside the IDE), but not on a standalone tomcat (9.x)?

Allow to overwrite default API response

In my controller, I'm forced to use a custom serializer for some of my response objects. The implementation looks similar to this example here:

        @RequestMapping(method = RequestMethod.GET)
	@ApiResponse(responseCode = "200", description = "Returns special things.", 
	content = @Content(
			schema = @Schema(
					type = "object",
					implementation = DummyClassForClassWithCustomSerializer.class
			)))
	public ResponseEntity<ClassWithCustomSerializer> doGet() {
        ...
        }

ClassWithCustomSerializer is serialized in a custom way. Springdoc OpenAPI will generate documentation based on the default serialization, which obviously doesn't match. I tried to add a dedicated @ApiResponse including a dummy class DummyClassForClassWithCustomSerializer corresponding to the custom serialization. Unfortunately, Springdoc OpenAPI ignores this annotation.

Would it be possible to allow to overwrite the default response object type by adding a specific @ApiResponse annotation for responseCode 200?

Support the io.swagger.v3.oas.annotations.security.SecurityScheme annotation

Support for this annotation looks implemented in org.springdoc.core.getSecurityScheme() but it is not yet called. I realize this is a new project. I hope filing these issues is helpful or at least not annoying.

It's nice to see a simple clean project for integrating swagger 3 & spring-boot. Keep up the good work. Much appreciated.

@javax.validation.Size specs generation for String incorrect (maximum instead of maxLength)

@SiZe is to validate the minimum and maximum length eg of a String.

Problem: if you try to put an integer value into the field from swagger-ui, the size is interpreted as maximum-digit-value.

Example:

@RestController
@Validated
public class Contr {
   @GetMapping
   public void get(@RequestParam @Size(min=4, max=6) String name) {}
}

This will trigger the following specs creation:

"parameters": [
	"name": "name",
	"schema": {
		"maximum": 6
		"minimum": 6
		"maxItems": 6
		"minItems": 6
		"type": "string"
	}
]

Using maximum and minimum is only correct if type would be an Integer. But for String you have to use minLength and maxLength. See https://swagger.io/docs/specification/data-models/data-types/

So you'd have to detect the parameter type first, and then apply the restrictions accordingly.
Also using maxItems and minItems is wrong here. Those should only be applied in case of type Array.

Input "asd123" works. But input "12345" does not work as it evaluates to "12345 > 6", and thus does not even pass the swagger-ui validation and thus never reaches the endpoint.

Bean configuration does not load components section

Components set in OpenAPI bean config get ignored.
Example with components security scheme:

        @Bean
        public OpenAPI openApi() {
            return new OpenAPI()
                    .components(new Components()
                            .addSecuritySchemes("basicScheme", new SecurityScheme()
                                    .type(SecurityScheme.Type.HTTP)
                                    .scheme("basic")
                            )
                    )
            ;
        }

calculateServerUrl seems to duplicate context root in Webflux

Hi,

I'm finding it very difficult to add a context root when working with springdoc. I've added my example in https://github.com/davidmelia/springdoc-webflux.

In Webflux I'm using the PathMatchConfigurer to prefix all controllers with /dave as the root. I've also added the ability for webjars to be prefixed with /dave as well. So far so good.

Problem is that OpenApiResource.calculateServerUrl calculates the serverBaseUrl as http://localhost:8080/dave
but then in swagger it calls
http://localhost:8080/dave/dave/tweets

Parameter missing if @Parameter is used without @RequestParam

v 1.1.7

The parameter of the first method is shown in swagger-ui, the 2nd method does not have any parameter. Again, the 3rd method shows the parameter.

@RestController
public class PersonServlet {
	@GetMapping(value = "/persons")
	public String persons(@NotBlank String name) {
		return "OK";
	}

	@GetMapping(value = "/persons2")
	public String persons2(@NotBlank @Parameter(description = "persons name") String name) {
		return "OK";
	}

	@GetMapping(value = "/persons3")
	public String persons3(@NotBlank @Parameter(description = "persons name") @RequestParam String name) {
		return "OK";
	}
}

{
   "openapi":"3.0.1",
   "info":{
      "title":"OpenAPI definition",
      "version":"v0"
   },
   "paths":{
      "/persons":{
         "get":{
            "operationId":"persons",
            "parameters":[
               {
                  "name":"name",
                  "in":"query",
                  "required":true,
                  "schema":{
                     "type":"string"
                  }
               }
            ],
            "responses":{
               "200 OK":{
                  "description":"default response",
                  "content":{
                     "*/*":{
                        "schema":{
                           "type":"string"
                        }
                     }
                  }
               }
            }
         }
      },
      "/persons2":{
         "get":{
            "operationId":"persons2",
            "responses":{
               "200 OK":{
                  "description":"default response",
                  "content":{
                     "*/*":{
                        "schema":{
                           "type":"string"
                        }
                     }
                  }
               }
            }
         }
      },
      "/persons3":{
         "get":{
            "operationId":"persons3",
            "parameters":[
               {
                  "name":"name",
                  "in":"query",
                  "description":"persons name",
                  "required":true,
                  "schema":{
                     "type":"string"
                  }
               }
            ],
            "responses":{
               "200 OK":{
                  "description":"default response",
                  "content":{
                     "*/*":{
                        "schema":{
                           "type":"string"
                        }
                     }
                  }
               }
            }
         }
      }
   },
   "components":{

   }
}

Detect context-path on standalone webservers

By default, the paths in the specs are autogenerated as follows:

{"openapi":"3.0.1","info":{"title":"OpenAPI definition","version":"v0"},"paths":{"/the/endpoint"...

This is fine in a standalone app.
But if the application is deployed on a standalone webserver like tomcat, there is a problem deriving the correct context path.

In fact, the specs are still created in the same manner. Thus, swagger ui executes the requests to: localhost:8080/the/endpoint.

But instead, on a standalone webserver, the correct path would be:
localhost:8080/my-app/the/endpoint.

It would be nice if springdoc could detect that context path and append it to the paths or server attribute in the specs, without having to set it manually programmatically.

This could be a starting point:
https://github.com/springfox/springfox/blob/master/springfox-spring-web/src/main/java/springfox/documentation/spring/web/paths/DefaultPathProvider.java

Exception in case of parametrized types inside ReponseEntity

In my controller, I'm using parametrized types as return values:

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<ResultEntity<List<NameRefPairEntity>>> doGet() {
...
}

The controller works fine, but when I try to access /v3/api-docs, Springdoc OpenAPI throws the following exception:

java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class
	at org.springdoc.core.AbstractResponseBuilder.calculateSchema(AbstractResponseBuilder.java:180)
	at org.springdoc.core.AbstractResponseBuilder.calculateSchemaParameterizedType(AbstractResponseBuilder.java:145)
	at org.springdoc.core.ResponseBuilder.buildContent(ResponseBuilder.java:26)
	at org.springdoc.core.AbstractResponseBuilder.buildApiResponses(AbstractResponseBuilder.java:192)
	at org.springdoc.core.AbstractResponseBuilder.computeResponse(AbstractResponseBuilder.java:130)
	at org.springdoc.core.AbstractResponseBuilder.build(AbstractResponseBuilder.java:55)
	at org.springdoc.api.AbstractOpenApiResource.calculatePath(AbstractOpenApiResource.java:117)
	at org.springdoc.api.OpenApiResource.getPaths(OpenApiResource.java:77)
	at org.springdoc.api.AbstractOpenApiResource.getOpenApi(AbstractOpenApiResource.java:71)
	at org.springdoc.api.OpenApiResource.openapiJson(OpenApiResource.java:53)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117)
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)

The only workaround I found, was to declare some kind of wrapper class for this type and use this instead:

private static class ResultListNameRefPairEntity extends ResultEntity<List<NameRefPairEntity>> { }

In case it's difficult to handle parametrized types inside the ResponseEntity, could you please at least catch the exception, ignore the type and continue to generate the rest of the API specification?

After configuring springdoc.swagger-ui.path the initial html page is served from the configured path but other requests are served without the path

If you configure: springdoc.swagger-ui.path=foo then http://localhost:3006/foo/swagger-ui.html works great. The problem is it immediately redirects to http://localhost:3006/webjars/swagger-ui/index.html?url=/foo&validatorUrl=

This greatly complicates things like configuring servlet filters based on path.

Ideally, you can configure a path to serve swagger docs from and every resource is served from that path.

Support hiding of Schema and Example Value

If my webservice returns objects like ResponseEntity, JsonObject, Object or whatever, it would be nice if the "Example Value" and "Schema" node in the generated json specs could be hidden.

For schema, there is property
@Operation(responses = @ApiResponse(content = @Content(schema = @Schema(hidden = true))).
Maybe you could evaluate it and hide it for the specific endpoint?

For example ExampleObject I have no suggestion how to derive the hiding.

Make the api opt-in with @EnableSpringDoc

Would it be possible to make the springdoc library an opt-in feature? Like @EnableScheduling, @EnableCaching does, with would be nice to have a @EnableSpringDoc, so that having the library on classpath does not automatically trigger the swagger endpoint generation.

This would be useful for company-wide commons libraries that define the eg the sprindoc version, common configuration, etc. But should disable the swagger ui in production. Thus opt-in (or out) would be useful.

Resource handler for UI overrides autoconfigured handlers

Hi,
there is an issue with mapping my own static resources from "resources" directory: SwaggerConfig class defines handler for mapping /** to /webjars/, which for some reason overrides default handler that maps /** to classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/ and /. So all my requests to static resources get mapped to /webjars/. At this moment the only thing that helps is manually removing SwaggerConfig bean from context and defining my own bean that implements WebMvcConfigurer with correct mapping.
Possible solution: add stated above default paths to addResourceLocations() method in SwaggerConfig class.

Group support

Hi, can this library split the definition in groups? Maybe based on tags or on explicit definitions. So that we can obtain more than one definition on the same spring boot. Thanks

Support Spring Boot WebFlux Netty

I think one of the biggest features missing from the SpringFox project is the official release of WebFlux Netty support.

It would be great if springdoc support webflux netty. I can see the demo 'springdoc-openapi-test-app3' attempts to do this but 'spring-boot-starter-web' should be removed so that it's a pure webflux project. If you do this you get the error

Description:

Field requestMappingHandlerMapping in org.springdoc.api.OpenApiResource required a bean of type 'org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)

Thanks

Descriptions in classes won't get included

In my api I have defined for example

@ApiOperation(value = "Build Version of the API.", nickname = "getBuildId", notes = "Returns the build version of the product recommendation api.", response = BuildVersion.class, tags = {})

However the notes get lost. Same applies to

@ApiParam(value = "Some description")

Webflux webjars path cannot be prefixed with a context root

Regarding the demo springdoc-openapi-test-app3 (3.1.1-SNAPSHOT) if I set the following

springdoc:
  api-docs:
    path: /dave/v3/api-docs
  swagger-ui:
    path: /dave/swagger-ui.html     

then
http://localhost:8080/dave/swagger-ui.html
redirects to
http://localhost:8080/webjars/swagger-ui/index.html?url=/dave/v3/api-docs&validatorUrl=
but should be
http://localhost:8080/dave/webjars/swagger-ui/index.html?url=/dave/v3/api-docs&validatorUrl=

is this a bug or is it possible to have a parameter to prefix /webjars?

Thanks

@Parameter in @Operation not working

The following example shows No parameters in the ui.
springdoc-openapi-ui-1.1.6

@RestController
public class PersonServlet {
	@GetMapping(value = "/persons")
	@Operation(parameters = {@Parameter(name = "name", in = ParameterIn.QUERY)})
	public void get() {

	}
}

Spring injectable parameters show in documentation

This effort is awesome so far! Thanks for all you are doing to make this so good so quickly!

Currently, we have a simple health check endpoint that requires the HttpServletRequest to do its job. The api is picking this up as a required parameter, but it is not required from the user via the api. How can we exclude parameters being automatically injected by the mvc framework?

Example:

@GetMapping("/health/integrity", produces = [MediaType.APPLICATION_JSON_UTF8_VALUE])
    fun integrity(request: HttpServletRequest): ServiceIntegrity {
        ...
        return ServiceIntegrity(overallStatus, statuses)
    }

Produces:

       "/pdf/health/integrity": {
            "get": {
                "operationId": "integrity",
                "parameters": [
                    {
                        "name": "request",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "object",
                            "properties": {
                                "method": {
                                    "type": "string"
                                },
                                "queryString": {
                                    "type": "string"
                                },
                                "session": {
                                    "type": "object",
                                    "properties": {
                                        "id": {
                                            "type": "string"
                                        },
                                        "servletContext": {
...

We need to ignore that bad boy as it's not part of the API.

Thanks!

authorization header didn't exist in requests

Hi,
I tried to add the bearer token to all my swagger's UI requests in the next way:

@Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI().components(new Components()
                .addSecuritySchemes("BEARER KEY", new SecurityScheme().type(SecurityScheme.Type.HTTP)
                        .scheme("bearer").in(SecurityScheme.In.HEADER)));
    }

Then after my application started I pass the bearer token into an authentication form with swagger UI:

Bearer

Actual result:

curl -X GET "http://localhost:8080/api/v1/contacts/employees?query=name" -H "accept: */*"

Bearer token didn't exist in the request.

Expected result:

curl -X GET "http://localhost:8080/api/v1/contacts/employees?query=name" -H "accept: */*" -H "Authorization: Bearer ***********"

Bearer token exists in the request.

Could you please clarify, what I'm doing wrong?
Thank you!

Support @RequestMapping.param for overloaded endpoints

In spring it is possible to create multiple endpoints on the same path, that only differ by parameters.

@RestController
public class SearchController {
    @GetMapping(path = "/items", params = "name")
    public Object searchItemsByName(String name) {

    }

    @GetMapping(path = "/items", params = "description")
    public Object searchItemsByDescription(String description) {

    }
}

It would be nice if springdoc could render those endpoints as 2 distinct endpoints, so that both are shown individually.

If we'd make the query parameters a bean here, maybe you could detect the overloaded endpoints, and generate parameters.schema.oneOf? But I'm not sure if that would help.

{
 "path": {
   "/items:" {
     "get": {
       "parameters": [
	 {
	    "name": "req",
	    "in": "query",
	    "schema": {
		"oneOf": [
		    {
		        "$ref": "#/components/schemas/FirstFilter"
		    },
		    {
		        "$ref": "#/components/schemas/SecondFilter"
		    }
		]
	    }
	 }
       ]
     }
   }
}

Any @GetMapping parameters should be marked as required, even if @RequestParam missing

The following should mark the argument as *required:

	@GetMapping(value = "/persons")
	public void persons(@Valid @NotBlank String name) {

	}

But in fact this renders to optional.
When adding @RequestParam to the parameter, it is rendered correctly.
But in general the @RequestParam is an optional parameter for spring mvc. By default, any parameters given in the method are assumed to be @RequestParam with required=true by spring. So springdoc should assume the same.

Source code of demo application

Hello :)

Could it be possible to add the examples's source code (Demo application 1 & 2) to this project ?

This would allow to see quickly the annotations that have been used

[Feature-Request] Derive documentation from javadoc

This is a feature request.

IMO writing the documentation via annotations is tedious. I would rather write javadocs and let the plugin convert them into proper documentation.

Can you add support for that?

If annotations are present and the description part is filled, then it should use that description. If the annotation is missing or the description is empty, then it should use the javadocs instead.

A helpful library for the implementation might be https://github.com/dnault/therapi-runtime-javadoc

Parameter.schema is ignored

Hello,

While trying to specify the expected type in the @Parameterwith the scheme attribute, I see that it is ignored in the following code

Why?

I was doing this:

fun list(   @Parameter(name = "trackerId", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string", example = "the-tracker-id"))
            @PathVariable trackerId: String,
            @Parameter(name = "start", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "string", format = "date-time", required = false, example = "1970-01-01T00:00:00.000Z"))
            @RequestParam(value = "start", required = false) startDate: Instant?,
            @Parameter(name = "end", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "string", format = "date-time", required = false, example = "1970-01-01T00:10:00.000Z"))
            @RequestParam(value = "end", required = false) endDate: Instant?): Collection<Result> {
...

And the output in json is

{"name":"start","in":"query","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end","in":"query","required":false,"schema":{"type":"integer","format":"int64"}}

Thank you

Curl call for file upload not working

For my POST service when I use the option "Try it out", upload image and choose Execute my curl call look like

curl -X POST "http://localhost:8080/my-service/api/documents" -H "accept: */*" -H "Content-Type: multipart/form-data" -F "files=[object File]"

And I get response that no files are sent. And the curl call looks like it's missing file location or I'm wrong?

How to configure global security schemes?

Hi, I can't understand how to correctly configure components.securitySchemes part of specification for all my controllers.

Now I use workaround:

@Component
public class SecuritySchemeInjector implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("openAPIBuilder")&&(bean instanceof OpenAPIBuilder)) {
            return injectSecurityScheme((OpenAPIBuilder) bean);
        }
        return bean;
    }

    private OpenAPIBuilder injectSecurityScheme(OpenAPIBuilder bean) {
        bean.getComponents().addSecuritySchemes("bearerAuth", getBearerScheme());
        bean.getComponents().addSecuritySchemes("googleApiKey", getApiKeyScheme());
        return bean;
    }

   ...

}

How to do it correctly?

requestBody description is lost

When I use

requestBody = @RequestBody(description = "smth")

it doesn't appear in the generated spec.
In method org.springdoc.api.AbstractOpenApiResource#calculatePath description is parses correctly on line 79 (org.springdoc.core.OperationBuilder#parse), but is ignored when

// requests
operation = requestBuilder.build(components, handlerMethod, requestMethod, operation, mediaAttributes.getAllConsumes());

on line 83.

oneOf response implementation

Have you got any example for annotation with oneOf implementation in response ?

I tried :
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(array = @ArraySchema(schema = @Schema(oneOf = {A.class, B.class})))),

But it's ignored on v3/api-docs generation :
responses":{"200":{"description":"successful operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEntity"}}}}

Annotations from interfaces

The documentation generator doesn't take into consideration the annotations from superclasses and interfaces.

@RequestMapping("/myapi")
public interface MyApi {
  @GetMapping
  String get(@Parameter(hidden = true, in = ParameterIn.HEADER, name = HttpHeaders.ACCEPT_LANGUAGE) @RequestHeader(value = HttpHeaders.ACCEPT_LANGUAGE, required = false) String language);
}
@RestController
public class MyApiController implements MyApi {
  public String get(String language) {
    return language;
  }
}

In the docs generated from the example above, the parameter language is not hidden, doesn't have its configured name ("Accept-Language") and is shown as query parameter.

Question: differentiation to springfox-project

IMO Springfox (https://github.com/springfox/springfox) is a already established, widley used open source - project which brings OpenAPI - support to Spring (Boot) applications.
Where do you see your strengths / weaknesses compared to Springfox?
From my perspective the biggest issue with Springfox was that it was driven by a single person, which caused issues with adding OpenAPI 3.0 - support. (Springfox currently only supports OpenAPI 2.0.) At this point in time it look´s like this may get better.

Support relative path in @ExampleObject

Having a file in /src/main/resources/static/swagger/example.json. Placed inside /static because spring can expose those to the web.

It should be possible to reference the file relative to the application itself. Eg as follows:

@Operation(responses = @ApiResponse(content = @Content(examples = @ExampleObject(externalValue = "swagger/example.json")))

But even if I can access the resource via locahost:8080/swagger/example.json, when adding the url to @ExampleObject it is still not resolved:

@Operation(responses = @ApiResponse(content = @Content(examples = @ExampleObject(externalValue = "locahost:8080/swagger/example.json")))

Generic (error) responses built from `ControllerAdvice` are nondeterministic

Thank you for providing this library.

Generic (error) responses built from ControllerAdvice exception handlers are built in an undefined order. In cases where multiple exception handler methods declare the same response status, which method’s return type ends up being used as the response schema for that status code is nondeterministic (might change between runs).

I’m speculating the issue is due to the use of the Set data type in iteration:

for (Map.Entry<String, ApiResponse> entry : apiResponses.entrySet()) {

Generated MultipartFile schema in JSON/YAML does not work in UI

Hi,

I have a service defined like :
@PostMapping(path = "/documents") public ResponseEntity<String> uploadDocuments( @RequestParam("doc") List<MultipartFile> multipartFiles, @RequestParam(value = "mode", required = false, defaultValue = edit) String mode)

Generated YAML file contains MultipartFile schema :

schemas: MultipartFile: type: object properties: name: type: string empty: type: boolean bytes: type: array items: type: string format: byte resource: $ref: '#/components/schemas/Resource' size: type: integer format: int64 inputStream: type: object contentType: type: string originalFilename: type: string Resource: type: object properties: open: type: boolean file: type: string format: binary readable: type: boolean description: type: string uri: type: string format: uri filename: type: string url: type: string format: url inputStream: type: object

So the UI doesn't recognize the field as binary so I can't upload images.

SwaggerUI

YAML THAT WORKS
If the schema was :
schemas: MultipartFile: type: string format: binary

SwaggerUISuccess

How can I override this generated MultipartFile? Or there is some other solution I'm missing?

I'm using:
`

  • springdoc-openapi-core, version 1.1.4
  • springdoc-openapi-ui, version 1.1.4

Consider using spring.mvc.static-path-pattern if set

Currently our configuration looks like the following:

app.path=/foo
spring.mvc.static-path-pattern=${app.path}/**
springdoc.swagger-ui.path=${app.path}/swagger-ui.html
springdoc.api-docs.path=${app.path}/api-docs

As a convenience, you may want to use the spring.mvc.static-path-pattern if set to serve the swagger resources. Just a suggestion since the swagger docs could be considered static resources. Anyway, we thought we'd make this suggestion and see what you guys thought.

Schema `{one,any,all}Of` not working when applied to a model property

Thanks for providing this library.

The {one,any,all}Of options of the io.swagger.v3.oas.annotations.media.Schema annotation do not have the expected effect when applied to a model class property.

Example

Given:

public class MyModel {

    @Schema(
        description = "Hello",
        type = "object",
        oneOf = {
            Foo.class,
            Bar.class,
            Baz.class
        }
    )
    private Object thing;

    public void setThing(Object thing) {
        this.thing = thing;
    }

    public Object getThing() {
        return thing;
    }
}

Expected output:

  "MyModel": {
    "properties": {
      "thing": {
        "description": "Hello",
        "type": "object",
        "oneOf": [
          {
            "$ref": "#/components/schemas/Foo"
          },
          {
            "$ref": "#/components/schemas/Bar"
          },
          {
            "$ref": "#/components/schemas/Baz"
          }
        ]
      }
    },
    "type": "object"
  },

Actual output:

  "MyModel": {
    "properties": {
      "thing": {
        "description": "Hello",
        "type": "object"
      }
    },
    "type": "object"
  },

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.