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

Create a proper Example system #48

Open
Wicpar opened this issue May 15, 2020 · 9 comments
Open

Create a proper Example system #48

Wicpar opened this issue May 15, 2020 · 9 comments

Comments

@Wicpar
Copy link
Collaborator

Wicpar commented May 15, 2020

A system needs to be created that allows to provide one or more examples with their metadata without adding bulk to the minimal configuration.

@y9san9
Copy link

y9san9 commented May 15, 2020

I am really waiting for this feature to show all possible errors in my api
image

@y9san9
Copy link

y9san9 commented Jun 9, 2020

Oh, I'm still waiting... I hope you'll make it as soon as you can...

@JavierPAYTEF
Copy link

JavierPAYTEF commented Jul 28, 2020

Hi @Wicpar, I implemented an @Example annotation for the fields and wanted to run it by you in case you think it's useful and want me to add a PR.

Let me know if you prefer me to open a different issue for this, I thought the subjects were somewhat connected.

The rationale behind the change is that I'm using Rapidoc instead of Swagger UI, and Rapidoc ignores the examples entirely and uses only the "example" attribute each field.

The annotation is used like this:

data class Result(
    @Description("Hexadecimal UID of the card")
    @Example("04D3AC7A124A80")
    var cardUID: String = "",
    @Description("Card type: A, B o M")
    @Example("M")
    var cardType: String = "",
    @Example(intValue = 200)
    var someIntField: Int = 0
)

This is the implementation:

@Target(AnnotationTarget.TYPE, AnnotationTarget.PROPERTY)
@SchemaProcessorAnnotation(ExampleValueProcessor::class)
annotation class Example(
    val stringValue: String = "",
    val intValue: Int = 0,
    val longValue: Long = 0,
    val doubleValue: Double = 0.0,
    val boolValue: Boolean = false,
    val isNull: Boolean = false
)

The processor is the only thing that's a little ugly, but probably can be improved:

object ExampleValueProcessor: SchemaProcessor<Example> {
    @Suppress("UNCHECKED_CAST")
    override fun process(model: SchemaModel<*>, type: KType, annotation: Example): SchemaModel<*> {
        when (model) {
            is SchemaModel.SchemaModelLitteral<*> -> {
                (model as SchemaModel.SchemaModelLitteral<Any?>).apply {
                    when(model.type) {
                        DataType.integer, DataType.number -> {
                            example = when {
                                annotation.intValue != 0 -> annotation.intValue
                                annotation.longValue != 0L -> annotation.longValue
                                annotation.doubleValue != 0.0 -> annotation.doubleValue
                                annotation.stringValue.isNotBlank() -> BigDecimal(annotation.stringValue)
                                else -> 0
                            }
                        }
                        DataType.boolean -> {
                            example = annotation.boolValue
                        }
                        DataType.`object`, DataType.array -> {
                            throw Exception("Type ${model.type} not supported for examples")
                        }
                        else -> { /* string */
                            example = annotation.stringValue
                        }
                    }
                }
            }
            is SchemaModel.SchemaModelEnum<*> -> {
                (model as SchemaModel.SchemaModelEnum<Any?>).apply {
                    example = annotation.stringValue
                }
            }
            else -> {
                throw Exception("${annotation::class} can't be applied to $model")
            }
        }
        return model
    }
}

@Wicpar
Copy link
Collaborator Author

Wicpar commented Jul 28, 2020

The approach I would have taken is to just take a string and convert it based on type, this would allow for objects as json examples without additional effort.

@Wicpar
Copy link
Collaborator Author

Wicpar commented Jul 28, 2020

@JavierPAYTEF What do you think about that, but a purely string based annotation that parses the content as json (or other based on a secondary optional property) ?

@JavierPAYTEF
Copy link

@Wicpar Hi, sorry, I've had a lot of work this past few weeks, I couldn't work on this.
Regarding your approach, could you explain a little more?
The advantage with your approach would be that we could use non-native types, like arrays for example, but the examples would still need to be simple, and not objects, since this tag is for field examples. Probably another approach would be needed for full object examples.
Do you maybe have anything you think would be useful as a guide to implement this? If you saw my code it's not exhaustive with the types at all.

@Wicpar
Copy link
Collaborator Author

Wicpar commented Aug 16, 2020

There is no way to handle multiple types of primitives in annotations in a cleaner way than you did.
The cleanest is really to use a string with intellij @Language injection for json. But if you want to keep it with primitives the way you went with is the way to go. Maybe have a way to allow 0 values by selecting the annotation value based on KType.

@JavierPAYTEF
Copy link

Do you maybe have an example or somewhere I can read some documentation? I tried researching on my own but my knowledge of annotations is not the best, so I will follow your lead since you probably know more than me in that regard.
Let me know a little more about how you would go about implementing it and I'll try to follow your lead.

@Wicpar
Copy link
Collaborator Author

Wicpar commented Aug 19, 2020

I don't know if an exhaustive guide about annotations exist, i just learned how to use them by fiddling around with them, and looking at annotation-heavy projects like spring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants