Giter Site home page Giter Site logo

javalin / javalin-openapi Goto Github PK

View Code? Open in Web Editor NEW
40.0 6.0 16.0 736 KB

Annotation processor for compile-time OpenAPI & JsonSchema, with out-of-the-box support for Javalin 5.x, Swagger & ReDoc

Home Page: https://github.com/javalin/javalin-openapi/wiki

License: Apache License 2.0

Kotlin 98.66% Groovy 1.34%
javalin openapi javalin-openapi annotation-processor swagger-ui swagger openapi3 redoc javalin-plugin hacktoberfest

javalin-openapi's Introduction

Logo

A simple web framework for Java and Kotlin


Static Badge Stable Version Snapshot Version Discord Link

Javalin is a very lightweight web framework for Kotlin and Java which supports WebSockets, HTTP2 and async requests. Javalin’s main goals are simplicity, a great developer experience, and first class interoperability between Kotlin and Java.

Javalin is more of a library than a framework. Some key points:

  • You don't need to extend anything
  • There are no @Annotations
  • There is no reflection
  • There is no other magic; just code.

General information

Community

We have a very active Discord server where you can get help quickly. We also have a (much less active) Slack if you prefer that.

Contributions are very welcome, you can read more about contributing in our guide: CONTRIBUTING

Please consider ❤️ Sponsoring or starring Javalin if you want to support the project.

Quickstart

Add dependency

Maven

<dependency>
    <groupId>io.javalin</groupId>
    <artifactId>javalin</artifactId>
    <version>6.1.3</version>
</dependency>

Gradle

implementation("io.javalin:javalin:6.1.3")

Start programming (Java)

import io.javalin.Javalin;

public class HelloWorld {
    public static void main(String[] args) {
        var app = Javalin.create(/*config*/)
            .get("/", ctx -> ctx.result("Hello World"))
            .start(7070);
    }
}

Start programming (Kotlin)

import io.javalin.Javalin

fun main() {
    val app = Javalin.create(/*config*/)
        .get("/") { it.result("Hello World") }
        .start(7070)
}

Examples

This section contains a few examples, mostly just extracted from the docs. All examples are in Kotlin, but you can find them in Java in the documentation (it's just syntax changes).

You can find more examples in the javalin-samples repository.

Api structure and server config

import io.javalin.Javalin
import io.javalin.apibuilder.ApiBuilder.*

fun main() {
    val app = Javalin.create { config ->
        config.useVirtualThreads = true
        config.http.asyncTimeout = 10_000L
        config.staticFiles.add("/public")
        config.staticFiles.enableWebjars()
        config.router.apiBuilder {
            path("/users") {
                get(UserController::getAll)
                post(UserController::create)
                path("/{userId}") {
                    get(UserController::getOne)
                    patch(UserController::update)
                    delete(UserController::delete)
                }
                ws("/events", userController::webSocketEvents)
            }
        }
    }.start(7070)
}

WebSockets

app.ws("/websocket/{path}") { ws ->
    ws.onConnect { ctx -> println("Connected") }
    ws.onMessage { ctx ->
        val user = ctx.message<User>() // convert from json string to object
        ctx.send(user) //  convert to json string and send back
    }
    ws.onClose { ctx -> println("Closed") }
    ws.onError { ctx -> println("Errored") }
}

Filters and Mappers

app.before("/some-path/*") { ctx -> ... } // runs before requests to /some-path/*
app.before { ctx -> ... } // runs before all requests
app.after { ctx -> ... } // runs after all requests
app.exception(Exception.class) { e, ctx -> ... } // runs if uncaught Exception
app.error(404) { ctx -> ... } // runs if status is 404 (after all other handlers)

app.wsBefore("/some-path/*") { ws -> ... } // runs before ws events on /some-path/*
app.wsBefore { ws -> ... } // runs before all ws events
app.wsAfter { ws -> ... } // runs after all ws events
app.wsException(Exception.class) { e, ctx -> ... } // runs if uncaught Exception in ws handler

JSON-mapping

var todos = arrayOf(...)
app.get("/todos") { ctx -> // map array of Todos to json-string
    ctx.json(todos)
}
app.put("/todos") { ctx -> // map request-body (json) to array of Todos
    todos = ctx.body<Array<Todo>>()
    ctx.status(204)
}

File uploads

app.post("/upload") { ctx ->
    ctx.uploadedFiles("files").forEach { uploadedFile ->
        FileUtil.streamToFile(uploadedFile.content(), "upload/${uploadedFile.filename()}")
    }
}

Plugins

Javalin has a plugin system that allows you to add functionality to the core library. You can find a list of plugins here.

Installing a plugin is as easy as adding a dependency to your project and registering it with Javalin:

Javalin.create { config ->
    config.registerPlugin(MyPlugin())
}

Some of the most popular plugins are:

OpenAPI Plugin

The Javalin OpenAPI plugin allows you to generate an OpenAPI 3.0 specification for your API at compile time.

Annotate your routes with @OpenApi to generate the specification:

@OpenApi(
    summary = "Get all users",
    operationId = "getAllUsers",
    tags = ["User"],
    responses = [OpenApiResponse("200", [OpenApiContent(Array<User>::class)])],
    path = "/users",
    methods = [HttpMethod.GET]
)
fun getAll(ctx: Context) {
    ctx.json(UserService.getAll())
}

Swagger UI and ReDoc UI implementations for viewing the generated specification in your browser are also available.

For more information, see the Javalin OpenAPI Wiki.

SSL Plugin

The Javalin SSL plugin allows you to easily configure SSL for your Javalin server, supporting a variety of formats such as PEM, PKCS12, DER, P7B, and JKS.

Enabling SSL on the 443 port is as easy as:

val plugin = SSLPlugin { conf ->
    conf.pemFromPath("/path/to/cert.pem", "/path/to/key.pem")
}

Javalin.create { javalinConfig ->
    javalinConfig.plugins.register(plugin)
}.start()

Sponsors

Special thanks

javalin-openapi's People

Contributors

28smiles avatar aldotele avatar dzikoysk avatar elwin013 avatar f1qwase avatar juv avatar macabrus avatar medeah avatar peterskeide avatar playacem avatar sauterl avatar tipsy avatar zrdzn 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

javalin-openapi's Issues

Package structure does not match group id

Group Id: io.javalin.community.openapi
package structure: io.javalin.openapi.plugin

This confused me while updating the javalin 5 openapi example, especially as the ssl-plugin has a matching package structure to group id: io.javalin.community.ssl

Adding to the confusion: OpenApiConfiguration#setTitle as described in the example in the readme does not exist.

Byte array is mapped to an OpenAPI integer array instead of binary string

Endpoint:

@OpenApi(
    methods = [HttpMethod.POST],
    path = "/my/post/endpoint",
    summary = "Post something",
    tags = ["config"],
    requestBody = OpenApiRequestBody(
        content = [OpenApiContent(ByteArray::class)]
    ),
    responses = [
        OpenApiResponse("200"), OpenApiResponse("415")
    ]
)
fun myPostEndpoint(ctx: Context) {
}

Expected output:

{
  "application/octet-stream": {
    "schema": {
      "type": "string",
      "format": "binary"
    }
  }
}

Actual Output:

{
  "application/json": {
    "schema": {
      "type": "array",
      "items": {
        "type": "integer",
        "format": "int32"
      }
    }
  }
}

Mark non-nullable fields as required properties

I would expect non-nullable attributes on data classes to be marked as requiredProperties on the generated openApi spec.

For example:

data class Person(
    val name: String,
    val age: Int
)

Generates:

     "Person" : {
        "type" : "object",
        "properties" : {
          "name" : {
            "type" : "string",
            "format" : ""
          },
          "age" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },

However, I would expect it to have required properties for name and age

formParams and fileUploads doesn't have any effect

I have the following definition:

@OpenApi(
            path = "/api/v1.0/sendImage",
            methods = HttpMethod.POST,
            summary = "Sends an image to MQTT",
            security = @OpenApiSecurity(name = "basicAuth"),
            formParams = {
                    @OpenApiFormParam(name = "topic", required = true),
            },
            fileUploads = {
                    @OpenApiFileUpload(name = "image")
            }
    )
    public void sendImageToMyTopic(@NotNull Context ctx) throws Exception {
      ...
    }

but openApi JSON doesn't include any fields and I can't invoke my endpoint via swagger UI.
This is the JSON I get for this endpoint:

...
  "/api/v1.0/sendImage": {
    "post": {
      "tags": [],
      "summary": "Sends an image to MQTT",
      "parameters": [],
      "responses": {},
      "deprecated": false,
      "security": [
        {
          "basicAuth": []
        }
      ]
    }
}

Default values for configs?

It's currently not possible to create a SwaggerPlugin or ReDocPlugin without passing a configuration. This could be a default argument (with @jvmoverloads).

Edit: Same goes for OpenApiPlugin.

Missing `securityScheme` type in OAuth2 documentation

thx for your efforts to rework the old plugin.

I figured out one bug when using your example java code.

The generated json is missing one important field when using OAuth2 as security scheme.
the generated json looks like:

"securitySchemes" : {
     
      "OAuth2" : {
        "description" : "This API uses OAuth 2 with the implicit grant flow.",
        "flows" : [ {
          "authorizationUrl" : "https://api.example.com/oauth2/authorize",
          "scopes" : {
            "write_pets" : "modify pets in your account",
            "read_pets" : "read your pets"
          }
        }
    }
  }

according to the documentation https://swagger.io/docs/specification/authentication/oauth2/ it has to be like this

  "securityDefinitions": {
    "api_key": {
      "type": "apiKey",
      "name": "api_key",
      "in": "header"
    },
    "petstore_auth": {
      "type": "oauth2",
      "authorizationUrl": "https://petstore.swagger.io/oauth/authorize",
      "flow": "implicit",
      "scopes": {
        "read:pets": "read your pets",
        "write:pets": "modify pets in your account"
      }
    }
  },

this json is stolen from https://petstore.swagger.io/

without adding the flow type the authorization window will look like this
Bildschirmfoto vom 2022-10-14 15-51-16
but it should be like this
Bildschirmfoto vom 2022-10-14 15-58-12
as you can see instead of (OAuth,0) and Flow: 0 it is written (OAuth2, flowtype) and Flow: implicit the input for client_id is also missing.
Because of this all OAuth flows (authorizationCode, implicit, password or clientCredentials) will not work from the swaggerui.

Kind regards.

After adding an annotation processor to java project lombok annotations stopped working

After a added:

        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.10.1</version>
                    <configuration>
                        <annotationProcessorPaths>
                            <annotationProcessorPath>
                                <groupId>io.javalin</groupId>
                                <artifactId>openapi-annotation-processor</artifactId>
                                <version>${javalin.version}</version>
                            </annotationProcessorPath>
                        </annotationProcessorPaths>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>

I'm getting compilation errors

java: cannot find symbol
  symbol:   variable log

I have also this dependency in my project:

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>provided</scope>
        </dependency>

Version 4.6.0 throws an error on Java 15

java.util.concurrent.CompletionException: java.lang.NoClassDefFoundError: kotlin/jvm/JvmInline

is thrown on Java 15 for version 4.6.0 of this plugin. However, 4.3.0 version works just fine.

Generate default documentation for registered routes

The old plugin had support for default responses:

    OpenApiOptions().apply {
        defaultDocumentation { doc ->
            doc.json("500", ErrorResponse::class.java)
            doc.json("503", ErrorResponse::class.java)
        }
    }

These are responses which could occur on any endpoint.

RouteRoles configuration support

Looking into the code:

class SwaggerPlugin(private val configuration: SwaggerConfiguration) : Plugin, PluginLifecycleInit {

    override fun init(app: Javalin) {
    }

    private fun readResource(path: String): String? =
        SwaggerPlugin::class.java.getResource(path)?.readText()

    override fun apply(app: Javalin) {
        app
            .get(configuration.uiPath, SwaggerHandler(configuration.title, configuration.documentationPath, configuration.version))
            .get("${configuration.webJarPath}/*", SwaggerWebJarHandler(configuration.webJarPath))
    }

}

it's not possible to set RouteRole for the Swagger endpoints.
If I have an accessManager in my app, I can not access those resources

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.