Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export api documentation #201

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ repositories {
}

dependencies {
compileOnly("io.micronaut.openapi:micronaut-openapi-annotations")
jooqGenerator("org.jooq:jooq-meta-extensions:$jooqVersion")

ksp("io.micronaut.serde:micronaut-serde-processor")
ksp("io.micronaut.openapi:micronaut-openapi")

implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
Expand Down Expand Up @@ -78,7 +80,7 @@ node {
}

application {
mainClass.set("de.w3is.recipes.ApplicationKt")
mainClass.set("de.w3is.recipes.Application")
}

tasks {
Expand Down
29 changes: 24 additions & 5 deletions src/main/kotlin/de/w3is/recipes/Application.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
package de.w3is.recipes

import io.micronaut.runtime.Micronaut.build
import io.swagger.v3.oas.annotations.OpenAPIDefinition
import io.swagger.v3.oas.annotations.info.Info
import io.swagger.v3.oas.annotations.info.License

fun main(args: Array<String>) {
build()
.args(*args)
.packages("de.w3is.recipes")
.start()
@OpenAPIDefinition(
info = Info(
title = "Salt and Pepper",
version = "1.0.0",
description = "Salt and Pepper Rest API",
license = License(
name = "GPL-3.0",
url = "https://www.gnu.org/licenses/gpl-3.0.en.html",
),
),
)
class Application {
companion object {
@JvmStatic
fun main(args: Array<String>) {
build()
.args(*args)
.packages("de.w3is.recipes")
.start()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,23 @@ import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.PathVariable
import io.micronaut.security.annotation.Secured
import io.micronaut.security.rules.SecurityRule
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag

@Controller("/api/images")
@Secured(SecurityRule.IS_ANONYMOUS)
class ImagesController(private val imageRepository: ImageRepository) {

@Get("/{id}", produces = [MediaType.IMAGE_PNG])
fun getImage(@PathVariable id: String): HttpResponse<ByteArray> =
@Operation(summary = "Get image by id", operationId = "getImage")
@Tag(name = "images")
fun getImage(@PathVariable("id") id: String): HttpResponse<ByteArray> =
HttpResponse.ok(imageRepository.get(ImageId(id)).readAllBytes()).cacheControl(31536000)

@Get("/{id}/thumbnail", produces = [MediaType.IMAGE_PNG])
fun getThumbnail(@PathVariable id: String): HttpResponse<ByteArray> =
@Operation(summary = "Get thumbnail by id", operationId = "getThumbnail")
@Tag(name = "images")
fun getThumbnail(@PathVariable("id") id: String): HttpResponse<ByteArray> =
HttpResponse.ok(imageRepository.getThumbnail(ImageId(id)).readAllBytes()).cacheControl(31536000)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import io.micronaut.http.multipart.StreamingFileUpload
import io.micronaut.security.annotation.Secured
import io.micronaut.security.authentication.Authentication
import io.micronaut.security.rules.SecurityRule
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import reactor.core.publisher.Mono
import reactor.core.scheduler.Schedulers
import java.io.File
Expand All @@ -23,6 +25,8 @@ class ImportController(
private val importService: ImportService,
) {
@Post("/gourmet", consumes = [MediaType.MULTIPART_FORM_DATA])
@Operation(summary = "Import XML files, exported by gourmet", operationId = "importGourmetXml")
@Tag(name = "import")
fun importGourmetXml(
file: StreamingFileUpload,
authentication: Authentication,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import io.micronaut.http.multipart.StreamingFileUpload
import io.micronaut.security.annotation.Secured
import io.micronaut.security.authentication.Authentication
import io.micronaut.security.rules.SecurityRule
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import reactor.core.publisher.Mono
import reactor.core.scheduler.Schedulers
import java.io.File
Expand All @@ -36,6 +38,8 @@ class RecipeController(
) {

@Post("/")
@Operation(summary = "Store new recipe", operationId = "storeRecipe")
@Tag(name = "recipes")
fun storeRecipe(@Body request: NewRecipeRequest, authentication: Authentication): NewRecipeResponse {
val user = with(userService) { authentication.getUser() }
val recipe = recipeService.createNewRecipe(
Expand All @@ -56,17 +60,23 @@ class RecipeController(
}

@Get("/{id}")
@Operation(summary = "Get recipe by id", operationId = "getRecipe")
@Tag(name = "recipes")
fun getRecipe(@PathVariable("id") recipeId: String): RecipeViewModel {
return recipeService.get(RecipeId(recipeId)).toModel()
}

@Delete("/{id}")
@Operation(summary = "Delete recipe by id", operationId = "deleteRecipe")
@Tag(name = "recipes")
fun deleteRecipe(@PathVariable("id") recipeId: String, authentication: Authentication) {
val user = with(userService) { authentication.getUser() }
recipeService.deleteRecipe(RecipeId(recipeId), user)
}

@Put("/{id}")
@Operation(summary = "Update recipe", operationId = "updateRecipe")
@Tag(name = "recipes")
fun updateRecipe(
@PathVariable("id") recipeId: String,
@Body request: RecipeViewModel,
Expand All @@ -87,6 +97,8 @@ class RecipeController(
}

@Post("/{id}/images", consumes = [MediaType.MULTIPART_FORM_DATA])
@Operation(summary = "Add image to recipe", operationId = "addImageToRecipe")
@Tag(name = "recipes")
fun addImageToRecipe(
@PathVariable("id") recipeId: String,
file: StreamingFileUpload,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.security.annotation.Secured
import io.micronaut.security.rules.SecurityRule
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag

@Controller("/api/recipe/search")
@Secured(SecurityRule.IS_AUTHENTICATED)
Expand All @@ -21,6 +23,8 @@ class RecipeSearchController(
) {

@Post
@Operation(summary = "Search recipes", operationId = "searchRecipes")
@Tag(name = "recipes")
fun search(@Body searchRequestViewModel: SearchRequestViewModel): SearchResponseViewModel {
val searchResponse = recipeRepository.search(searchRequestViewModel.toSearchRequest())
val possibleFilter = searchResponse.possibleFilter.toViewModel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import io.micronaut.http.annotation.Put
import io.micronaut.security.annotation.Secured
import io.micronaut.security.authentication.Authentication
import io.micronaut.security.rules.SecurityRule
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.inject.Singleton

@Singleton
Expand All @@ -25,6 +27,8 @@ class InvitationController(

@Get
@Secured(SecurityRule.IS_AUTHENTICATED)
@Operation(summary = "Get own invite code if any", operationId = "getExistingInviteCode")
@Tag(name = "invitations")
fun getExistingInviteCode(
authentication: Authentication,
): HttpResponse<InvitationCodeResponse> {
Expand All @@ -40,6 +44,8 @@ class InvitationController(

@Post
@Secured(SecurityRule.IS_AUTHENTICATED)
@Operation(summary = "Create new invite link", operationId = "createInviteLink")
@Tag(name = "invitations")
fun createInviteLink(
authentication: Authentication,
): InvitationCodeResponse {
Expand All @@ -51,6 +57,8 @@ class InvitationController(

@Get("/{code}")
@Secured(SecurityRule.IS_ANONYMOUS)
@Operation(summary = "Get invite information by code", operationId = "getInvitationInfo")
@Tag(name = "invitations")
fun getInvitationInfo(@PathVariable("code") inviteCode: String): InvitationInfoResponse {
val invite = invitationService.getInviteByCode(inviteCode)
val invitingUser = userService.getUser(invite.creator)
Expand All @@ -61,6 +69,8 @@ class InvitationController(

@Put("/{code}")
@Secured(SecurityRule.IS_ANONYMOUS)
@Operation(summary = "Create new user by invitation code", operationId = "useInvitation")
@Tag(name = "invitations")
fun useInvitation(
@PathVariable("code") inviteCode: String,
@Body invitationRequest: InvitationRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import io.micronaut.http.annotation.Patch
import io.micronaut.security.annotation.Secured
import io.micronaut.security.authentication.Authentication
import io.micronaut.security.rules.SecurityRule
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.inject.Singleton

@Singleton
Expand All @@ -26,6 +28,8 @@ class ProfileController(
) {

@Get
@Operation(summary = "Get own profile", operationId = "getProfile")
@Tag(name = "profile")
fun getProfile(authentication: Authentication): Profile {
val user = with(userService) { authentication.getUser() }

Expand All @@ -40,6 +44,8 @@ class ProfileController(
}

@Patch("/password")
@Operation(summary = "Change own password", operationId = "changePassword")
@Tag(name = "profile")
fun changePassword(@Body request: ChangePasswordRequest, authentication: Authentication): HttpResponse<Unit> {
val user = with(userService) { authentication.getUser() }

Expand Down
6 changes: 6 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ micronaut:
index:
paths: "classpath:/public/index.html"
mapping: "/"
swagger:
paths: "classpath:META-INF/swagger"
mapping: "/swagger/**"
default:
paths: "classpath:public"
mapping: "/**"
Expand Down Expand Up @@ -58,6 +61,9 @@ micronaut:
http-method: GET
access:
- isAnonymous()
- pattern: /swagger/**
access:
- isAnonymous()
reject-not-found: true


Expand Down