smiley4 / ktor-swagger-ui Goto Github PK
View Code? Open in Web Editor NEWKotlin Ktor plugin to generate OpenAPI and provide Swagger UI
License: Apache License 2.0
Kotlin Ktor plugin to generate OpenAPI and provide Swagger UI
License: Apache License 2.0
Need for implement authorization and etc.
Suggestion:
// add abstract RouteSelector
abstract class TransparentRouteSelector : RouteSelector()
private fun getPath(route: Route): String {
return when (route.selector) {
is TrailingSlashRouteSelector -> "/"
is RootRouteSelector -> ""
is DocumentedRouteSelector -> route.parent?.let { getPath(it) } ?: ""
is HttpMethodRouteSelector -> route.parent?.let { getPath(it) } ?: ""
is AuthenticationRouteSelector -> route.parent?.let { getPath(it) } ?: ""
is TransparentRouteSelector -> route.parent?.let { getPath(it) } ?: "" // this is new abstract class
else -> (route.parent?.let { getPath(it) } ?: "") + "/" + route.selector.toString()
}
}
Are there any plans to support routes defined using ktor Resources?
https://ktor.io/docs/type-safe-routing.html
https://github.com/ktorio/ktor-documentation/blob/2.3.2/codeSnippets/snippets/resource-routing/src/main/kotlin/resourcerouting/Application.kt
When we have a data class eg:
data class MyClass(val x: Map<String, String>)
This gets generated as:
"x": {
"type": "object"
},
Additional properties should be added. Otherwise the client generated by this open api json treats the field as String and not a map.
Something like this:
"x": {
"type": "object",
"additionalProperties": { "type": "string" }
},
Would be a nice to have to support externalDocs
property
Hey,
what about the following:
request {
body(GetItemParams::class)
}
response {
HttpStatusCode.OK to {
body(GetItemResponse::class)
}
}
replaced by this:
request {
body<GetItemParams>()
}
response {
HttpStatusCode.OK to {
body<GetItemResponse>()
}
}
It is less to write and you can use generics:
request {
body<GetItemParams>()
}
response {
HttpStatusCode.OK to {
body<GetItemResponse<FirstItem>>()
}
}
Hi! Now there is a functional of declaring an example for a swager through the creation of an object. But it adds a lot of template code to the routes.
Can we add our own @example annotation above the DTO fields? Or support swagger @content annotation, but I'm not sure if the json-schema generator supports it. It seems to me that it looks more appropriate there and doesn't overloads routes.
data class Person(
@Example("Jack")
val name: String,
)
Right now sealed classes returned by the documentation are just {}
. Ideally, it would clearly document sealed classes for return types (most important), and also inputs.
I would like to configure my service endpoint hidden from Swagger UI.
I would prefer to have same behavior as @ApiOperation(hidden=true)
swagger annotation:
route("health",
{ hidden = true } // <- desired property
) {
get("ready") { call.respond(HttpStatusCode.OK) }
}
Hi @SMILEY4 , thanks for that great extension.
Have next issue with exporting tracing data to Jaeger and see next endpoint there:
demo-project: /io.github.smiley4.ktorswaggerui.dsl.DocumentedRouteSelector@454d7e70/hello
While expect to see
demo-project: /hello
I use minimal demo configuration with OpenTelemetry and instrument with https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/ktor/ktor-2.0/library
Issue affect all endpoints defined with io.github.smiley4.ktorswaggerui.dsl.*
Thanks a lot for providing this library! We love it!
Are there any plans to publish this library also to Maven Central? We would like to use it in some projects where we're (unfortunately) restricted to Maven Central.
At the moment i am working on a small REST project.
When I try to prepare some routes to retrieve list and single items from a database table
GET /item
GET /item/XYZ
I want the first one to return a List of "Item", while the second one to return just "Item"
When I am using body<List<Item>>
it automatically creates a component with full canonical name: Result in api.json
"responses" : {
"200" : {
"description" : "successful operation",
"headers" : { },
"content" : {
"application/json" : {
"schema" : {
"type" : "array",
"xml" : { },
"items" : {
"$ref" : "#/components/schemas/com.example.ktor.Item"
}
}
}
}
}
}
When I try to create the body manually providing a custom schema for my Item:
body {
mediaType(ContentType.Application.Json)
ArraySchema().apply {
items = ObjectSchema().apply {
`$ref` = "Item"
}
}
}
The created api.json response is just empty
"responses" : {
"200" : {
"description" : "successful operation",
"headers" : { },
"content" : {
"application/json" : { }
}
}
}
Do you have any idea how to get it working?
It would be nice to be able to disable logging for swagger ui.
Maybe it is already possible but I cannot find it in the docs.
Hello,
I'm facing the problem, that my referenced Schema is dropped from the generated swagger-ui components (missing in api.json file as well).
After providing some openapi schemas, they are only added to the final swagger components when they referenced a request or response as a body.
schemasInComponentSection = true
In the resulting Swagger-UI Schema.B is missing as a component and in the response body description of previously defined route.
Is that an issue, or what can I do?
Hi, I would like to use this library for my backend. I have a problem because I'm using the route dsl to define the route father.
This causes the dsl doesn't have the appropriate functions or work poorly. Is there any intention to give support for this function?
route("/users") {
/* Registration: POST /api/users */
post() {
either<DomainError, UserWrapper<User>> {
val (username, email, password) = receiveCatching<UserWrapper<NewUser>>().bind().user
val token = userService.register(RegisterUser(username, email, password)).bind().value
UserWrapper(User(email, token, username, "", ""))
}.respond(HttpStatusCode.Created)
}
post("/login") {
either<DomainError, UserWrapper<User>> {
val (email, password) = receiveCatching<UserWrapper<LoginUser>>().bind().user
val (token, info) = userService.login(Login(email, password)).bind()
UserWrapper(User(email, token.value, info.username, info.bio, info.image))
}.respond(HttpStatusCode.OK)
}
}
Thanks.
Here is the rate limiter: https://ktor.io/docs/rate-limit.html
I tried it below
routing { rateLimit { get("/something", { summary = "something Endpoint." response { ....
URL paths are affected by the rateLimit function.
Are there any plans to support the rate limiter?
DSL allow to expose OpenAPI contract when application is being executed following "code first" approach.
However, I would like to build pipelines based on source code where "contract first" approach quite well, but in DSL case I don't have contract available.
One of scenarios I may want to implement is to create gradle task to extract openapi.json
file into local file and run pipelines against that file (for example, can trigger vaildation and publish new openapi contract as artifact if only changes in contract detected).
Is there any way to achieve it?
PS: as one of improvements in that direction it is possible to create ktor-swagger-ui-gradle-plugin
to extract openapi spec from ktor project/module and place it into resources
folder during compilation instead of doing it in runtime. It will allow to avoid having extra dependencies in runtime.
Hi.
I'm using this library to build a template in Ktor, I'm having a problem defining a multipart body.
I can't find any information apart from the media types.
Can you help me?
Thanks.
Was this supposed to be a var
?
Hi, I don't think the latest version has been published to maven central. The previous one, 2.2.0, seems to be the latest available.
Nonetheless, great work, thank you for the library. It feels much cleaner compared to other approaches.
It would be nice to have functionality for disabling the default swagger validation that's visible on the landing page. Since in our case we are running all services in a Kubernetes cluster behind a VPN the callback validation always fails and give us an orange box in the right corner that says: INVALID.
Good day! Tell me if there is an opportunity to add websocket support?
And how can I turn off generation for static, file, resources
Thank you!
Ktor framework dsl methods marked with @KtorDsl
annotation. Is there any profit to add that annotation to ktor-swagger-ui dsl methods?
I don't know actual benefits of having that, but only noticed Idea highlight dsl marked methods. Asking for comments.
When Using the Ktor Rate Limit Plugin, the routes are documented incorrectly, and show up with a prefix: / (RateLimit <rate limit name)/<your endpoint here>
.
install(RateLimit) {
register(apiTokenRateLimit) {
rateLimiter(limit = 100, refillPeriod = 60.seconds)
requestKey { call ->
// We've already checked and confirmed that the API Token exists.
call.request.headers[ApiTokenValidator.API_TOKEN_HEADER]!!.trim()
}
}
}
routing {
rateLimit(apiTokenRateLimit) {
myRoutes()
}
}
What is wrong?
Using singlePageApplication route to serve Vue application, but looks wrong that route is present in OpenAPI documentation.
Version: 1.0.1
Source code
fun Application.configureRouting() {
routing {
singlePageApplication {
vue("ktor-playground-vue/dist")
}
route("api") {
articleRoutes()
}
}
}
Actual result
2023-01-15 19:01:32.921 DEBUG --- [ main] i.g.s.k.specbuilder.OApiPathsBuilder : Configure path: GET //{...}
Temporary fix
fun Application.configureSwagger() {
install(SwaggerUI) {
pathFilter = { _, url -> url.firstOrNull() == "api" }
}
}
First of all, it is a great library thanks for your effort. But when I check the READ.me I didn't find any documentation for header parameter. There is a headerParameter in request block but I can not add any sample value to it. Can you also add sample to READ.me for headerParameter usage?
Hey! Loving the library, but running into a a problem.
One of my backend's return types can be a list containing one of 3 different parameterized types (List<Wrap<A>>, List<Wrap<B>>, ...
). From my understanding the final OpenAPI type would be something like:
"ResponseObjectName": {
"oneOf": [
{ "type": "array", "$ref": "#/components/schemas/Wrap(A)" },
{ "type": "array", "$ref": "#/components/schemas/Wrap(B)" },
{ "type": "array", "$ref": "#/components/schemas/Wrap(C)" }
]
}
I'm having trouble defining that reasonably with the library.
I've tried a bunch of stuff, but right now I'm trying to define using the CustomSchemas
config. I'm self-creating the list as a OpenAPI Schema
object fine, and I can set the reference. But I can't figure out how to establish the definitions for Wrap<T>
. That object isn't used anywhere else, so it doesn't get auto-populated by the generator. If I add the definitions to the CustomSchemas
config, they're not directly referenced by a request/response so it seems like they don't get populated because it's assumed that custom schemas are self-contained.
Here's roughly what I'm doing now:
// This tries to use the builtin SchemaBuilder to build the objects and register them as CustomSchemas.
val oneOfSchemaTypeNames =
listOf(
getSchemaType<Wrap<A>>(),
getSchemaType<Wrap<B>>(),
getSchemaType<Wrap<C>>()
).map { schemaType ->
Pair(schemaType.getSimpleTypeName(), schemaBuilder.create(schemaType))
}.map { (schemaName, schema) ->
val root = schema.root as Schema<Any>
schema.definitions.map {
openApi(it.key) { it.value as Schema<Any> }
}
// From debugging, this seems to register the custom type, but it never gets written because it's not used in a route def.
openApi(schemaName) { root }
schemaName
}
// Create the list of oneOf possible return types.
// This is the part that is actually working.
openApi("oneOfResponse") {
Schema<Any>().apply {
oneOfSchemaTypeNames.map { schemaName ->
addOneOfItem(
ArraySchema().apply {
items(
Schema<Any>().apply {
`$ref`(schemaName)
},
)
},
)
}
}
}
The output I get. There are no entries in #/components/schemas
for any Wrap
objects.
"oneOfResponse" : {
"oneOf" : [ {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/Wrap(A)"
}
}, {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/Wrap(B)"
}
}, {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/Wrap(C)"
}
} ]
}
Am I going about this all wrong? I don't see any way to force schemas to be instantiated, and I don't really want to have to build the whole type in the CustomSchema def or create dummy endpoints to have the objects recognized. Having the refs to the smaller objects is nice.
Also, I just noticed that body types generate different component paths depending on if they are in a list:
body<List<com.foo.Outer<com.bar.Inner>() -> #/components/schemas/Outer(Inner)
body<com.foo.Outer<com.bar.Inner>() -> #/components/schemas/com.foo.Outer<com.bar.Inner>
Maybe due to the underlying Library?
https://github.com/SMILEY4/ktor-swagger-ui/wiki/Request-and-Response-Bodies-Basics
I followed the example in the linked wiki above, However, it is displayed as shown in the picture below.
The function I want is like the picture below. How do I fix it?
Here is the code.
import java.io.File
...
post({
request {
multipartBody {
required = true
description = "profile image"
mediaType(ContentType.MultiPart.FormData)
part<File>("profileImage") {
mediaTypes = setOf(
ContentType.Image.PNG,
ContentType.Image.JPEG,
ContentType.Image.GIF
)
}
part<Metadata>("myMetadata")
}
}
}) {
...
}
build.gradle.kts
...
dependencies {
implementation("io.ktor:ktor-server-swagger-jvm:2.3.2")
implementation("io.ktor:ktor-server-openapi:2.3.2")
implementation("io.github.smiley4:ktor-swagger-ui:2.2.0")
...
}
If you start a property name with 'is' and use a capital letter directly following, the property schema fails to generate.
Examples:
data class Irrelevant(
val isNamed: String,
val isIrrelevent: String
)
Hi
I have the following problem when I call to a methods using Swagger UI
Curl
curl -X 'GET'
'http://localhost:6969/*'
-H 'accept: /'
Request URL
http://localhost:6969/*
Undocumented | Failed to fetch.Possible Reasons:
CORS
Network FailureURL scheme must be "http" or "https" for CORS request.
I don't have CORS configuration
I have the same problem with all endpoints an routes, this example is with a String
Here it is my conf
install(SwaggerUI) {
swagger {
swaggerUrl = "swagger-ui"
forwardRoot = true
}
info {
title = "Ktor Tenistas API REST"
version = "latest"
description = "Ejemplo de una API Rest usando Ktor y tecnologías Kotlin."
contact {
name = "Jose Luis González Sánchez"
url = "https://github.com/joseluisgs"
}
license {
name = "Creative Commons Attribution-ShareAlike 4.0 International License"
url = "https://joseluisgs.dev/docs/license/"
}
}
server {
url = environment.config.property("server.baseUrl").getString()
description = "Servidor de la API Rest usando Ktor y tecnologías Kotlin."
}
schemasInComponentSection = true
examplesInComponentSection = true
automaticTagGenerator = { url -> url.firstOrNull() }
}
Could you help me?
Can annotations be used to express interfaces and interface parameters? The current form feels too intrusive, and it is highly complex to use, and the second phase looks unclear. It is suggested to refer to the form of Java,js,python, and these swagger are written in the form of similar annotations.
I'm unable to get authentication to work using the oauth2 authorizationCode
flow.
In Insomnia I'm configuring the authorization with the following parameters:
In my application, I tried to configure the Swagger UI like this for a local KeyCloak:
install(SwaggerUI) {
defaultSecuritySchemeName = "token"
defaultUnauthorizedResponse {
description = "Token is invalid."
}
securityScheme("token") {
type = AuthType.OAUTH2
flows {
authorizationCode {
authorizationUrl = "http://localhost:8081/realms/master/protocol/openid-connect/auth"
tokenUrl = "http://localhost:8081/realms/master/protocol/openid-connect/token"
}
}
}
}
The routing is configured like this:
routing {
route("api/v1") {
authenticate("token") {
get("hello") { // From io.github.smiley4.ktorswaggerui.dsl.get
call.respond("Hello Auth.")
}
}
}
}
The SwaggerUI shows the endpoint correctly as authenticated.
However, sending the request in SwaggerUI, does not open an authentication window, and results in 401
.
I tried your Authentication example from here which was working, but for my application I do require Oauth2 authentication.
Can you give me a hint what I'm doing wrong?
Is there any way to use a kotlinx.serialization or gson annotation on the fields of a data class in the version 1.6.1?
For example, I'm using the code below, but the generated example response is picking the data class field name and ignoring the annotation:
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class Pet(
@SerialName("first_name")
val firstName: String
)
get("pet", {
response {
HttpStatusCode.Ok to {
body<Pet>() {
mediaType(ContentType.Application.Json)
example(
name = "get pet name",
value = Pet("Max")
)
}
}
}
}) {
// handle request...
}
But the generated example give me:
{
"firstName": "Max"
}
instead
{
"first_name": "Max"
}
I saw that in the 2.0.0 version will be possible to set a custom example encoding
It seems that the securitySchemeName
on a specific route is only applied when the route is authenticated in Ktor. However, in our context the Ktor application itself is unauthenticated, but is behind a gateway which performs the authentication (this may even be route-specific, so some routes may be authenticated, others may be unauthenticated).
I see that you're also using RouteMeta.isProtected
for deciding whether to add the defaultUnauthorizedResponse
-- that might be a similarly problematic case.
Maybe it would be possible to give a hint, that the route is protected externally?
I'm open to implement it myself and create a PR, but I'm not sure where the preferred place would be to put that information.
The OpenApiRoute
might be a good place, but so far it only contains stuff which is really OpenAPI-specific and does not have such "meta-information".
I have some routes that aren't API endpoints; some are pages that generate HTML etc; I don't want them to be a part of the swagger docs. Is there a way to mark a particular route as hidden so it doesn't show up in the UI?
I could also see this as something that would be useful for endpoints that aren't yet public.
Hi! I wanted to see something like
data class Person(
@Desctription("name of person)
val name: String,
)
Thank you for providing this library! It's very clean.
How would I describe a Body parameter, and what the acceptable values are for it?
body<ExampleRequest> {
required = true
}
Lets say that ExampleRequest has a parameter limit
that has a max value of 100
. Or if I wanted to document the acceptable formats for a Date String that was sent. Is that possible currently?
I just figured out that since 2.0.0, when I annotate my fields in data classes with @field:Schema(nullable = true)
, the api.json will be generated with only an empty JSON object {}
. Same applies to that example in SchemaAnnotationExample.kt.
Edit: correct link reference
Right now if I use https://github.com/Kotlin/kotlinx-datetime Instant
, it shows up in swagger as {}
. I don't see any way to change this.
Is there a way that I can define a type somewhere globally, and use that definition everywhere the type is used? This would be very useful for Date types, and I'm sure others as well.
bump swagger parser to 2.1.13 (currently used version has a CVE)
I have an endpoint which expects this body:
{
"name": "entity name",
"description": "entity description"
}
In the application, this is deserialized into
@Serializable
data class UpdateOrganization(
val name: OptionalValue<String> = OptionalValue.Absent,
val description: OptionalValue<String?> = OptionalValue.Absent
)
By using this custom serializer for kotlinx.serialization
:
class OptionalValueSerializer<T>(private val valueSerializer: KSerializer<T>) : KSerializer<OptionalValue<T>> {
override val descriptor: SerialDescriptor = valueSerializer.descriptor
override fun deserialize(decoder: Decoder): OptionalValue<T> {
val value = valueSerializer.deserialize(decoder)
return OptionalValue.Present(value)
}
override fun serialize(encoder: Encoder, value: OptionalValue<T>) {
when (value) {
is OptionalValue.Absent -> {}
is OptionalValue.Present -> valueSerializer.serialize(encoder, value.value)
}
}
}
The generated spec is displayed like this in the Swagger UI:
{
"name": {
"value": "entity name"
},
"description": {
"value": "entity description"
}
}
Is there a way to change the serialization for this object when generating the OpenApi spec?
I have tried multiple config options in the schema builder, but am not able to configure "All Schema in definitions". The spec being generated has the main schema in components, but the internal models are coming inline. This is leading to very long class names, as it is concatenating the main class name with the field name and putting "inner" in the name as well.
I think this should be the correct config for what I want, but if I try this then the schema does not get generated:
install(SwaggerUI) {
//...
schemasInComponentSection = true
examplesInComponentSection = true
schemaGeneratorConfigBuilder.with(Option.DEFINITIONS_FOR_ALL_OBJECTS)
.with(Option.DEFINITION_FOR_MAIN_SCHEMA)
.without(Option.INLINE_ALL_SCHEMAS)
//...
}
What I want is to generate the spec where for this class:
data class Y(val a: String)
data class X(val y: Y)
The generated schema should be:
"X": {
"type": "object",
"properties": {
"y": {
"$ref": "#/components/schemas/Y"
}
},
"xml": {
"name": "X"
}
},
"Y": {
"type": "object",
"properties": {
"a": {
"type": "string"
}
}
}
What I being generated currently:
"X": {
"type": "object",
"properties": {
"y": {
"type": "object",
"properties": {
"a": {
"type": "string"
}
}
}
},
"xml": {
"name": "X"
}
}
My server hostet on some domain and some path
For example http://<some_domain>/<some_path>
I setup rootHostPath parameter as "/<some_path>"
Swager UI oppends up correctly on URL http://<some_domain>/<some_path>/swagger/index.html
But when I try to send some request URL do not contains rootHostPath in request
For example if I have routing get /health
Full correct path is http://<some_domain>/<some_path>/health
But if I "try it out" in Swager UI
full path is http://<some_domain>/health without rootHostPath parameter
when trying to go to the swagger documentation the index.html is not found in the webjar.
Used version of the liberary: 1.1.0
2023-01-31 09:22:20.132 [main] INFO Application - Responding at http://127.0.0.1:8080
2023-01-31 10:03:35.677 [eventLoopGroupProxy-4-2] TRACE io.ktor.server.sessions.Sessions - Sessions found for /swagger-ui/index.html: Session
2023-01-31 10:03:35.686 [eventLoopGroupProxy-4-2] TRACE io.ktor.routing.Routing - Trace for [swagger-ui, index.html]
/, segment:0 -> SUCCESS @ /
/swagger-ui, segment:1 -> SUCCESS @ /swagger-ui
/swagger-ui/(method:GET), segment:1 -> FAILURE "Not all segments matched" @ /swagger-ui/(method:GET)
/swagger-ui/api.json, segment:1 -> FAILURE "Selector didn't match" @ /swagger-ui/api.json
/swagger-ui/{filename}, segment:2 -> SUCCESS; Parameters [filename=[index.html]] @ /swagger-ui/{filename}
/swagger-ui/{filename}/(method:GET), segment:2 -> SUCCESS @ /swagger-ui/{filename}/(method:GET)
/api, segment:0 -> FAILURE "Selector didn't match" @ /api
/{...}, segment:0 -> FAILURE "Better match was already found" @ /{...}
Matched routes:
"" -> "swagger-ui" -> "{filename}" -> "(method:GET)"
Route resolve result:
SUCCESS; Parameters [filename=[index.html]] @ /swagger-ui/{filename}/(method:GET)
2023-01-31 10:03:35.690 [eventLoopGroupProxy-4-2] TRACE io.ktor.server.sessions.Sessions - Sending session data for /swagger-ui/index.html: Session
2023-01-31 10:03:35.691 [eventLoopGroupProxy-4-2] TRACE i.k.s.p.c.ContentNegotiation - Skipping because the type is ignored.
2023-01-31 10:03:35.697 [eventLoopGroupProxy-4-2] TRACE i.k.s.p.compression.Compression - Skip compression because no suitable encoder found.
2023-01-31 10:03:35.698 [eventLoopGroupProxy-4-2] TRACE i.k.s.p.statuspages.StatusPages - No handler found for status code 404 Not Found for call: /swagger-ui/index.html
2023-01-31 10:03:35.832 [eventLoopGroupProxy-4-2] TRACE Application - 404 Not Found: GET - /swagger-ui/index.html
My configuration:
install(SwaggerUI){
pathFilter = { _, url -> url.firstOrNull() == "api" }
swagger {
forwardRoot = false
swaggerUrl = "swagger-ui"
onlineSpecValidator()
displayOperationId = true
showTagFilterInput = true
syntaxHighlight = SwaggerUiSyntaxHighlight.MONOKAI
}
info {
title = "Ktor swagger"
version = "latest"
description = "Ktor swagger api documentation"
contact {
name = "Mike Dirven"
url = "http://www.icsvertex.nl"
email = "[email protected]"
}
}
}
Hi! I may not have found the secret sauce for this if it exists ...
I was unable to specify a custom schema item by id in the schemas
section of the plugin config and then use that for a response body that was a collection of that item, i.e. the equivalent of body<List<ABC>>()
or something similar.
I was able to do it by defining a second schema that wrapped the first as an array item but that ended up replicating the base schema into the components section of the api.json
with a simple array specifier.
Am I missing something? Or is this a limitation of the DSL for now?
TIA.
OAS3 allows combining security requirements with logical operators (OR and AND). More details can be found in the documentation under Using Multiple Authentication Types, but the basic logic for documenting security of a route is as follow:
security: # A OR B
- A
- B
security: # A AND B
- A
B
security: # (A AND B) OR (C AND D)
- A
B
- C
D
From my observation of this library, this should be doable by changing the OpenApiRoute.securitySchemeName
(link) from a String?
to something like a Collection<Collection<String>>
(or just Collection<String>
for start, to support the OR logical operator) and supporting the following change here.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.