DocsField
restdocs에서 사용하는 FieldDescriptorClass를 상속하여,
직접 custom 할 수 있는 형태로 가공하고 infix function을 사용하여, builder pattern과 같은 형태로 사용 가능함.
| parameter | description |
|---|---|
| type | 타입 ex) String, Number… |
| means | 설명 |
| example | 예시 |
| defaultValue | 기본 값 |
| formattedAs | 포멧 (날짜 등) |
| isOptional | 필수 여부 |
위의 parameter를 조합하여, 하나의 field를 생성함.
ex) "createdAt" type STRING means "회원 생성일자" formattedAs DocsFormatter.DATETIME defaultValue datetimeNowToString()
package com.example.kotlinapiserverguide.restDocs.constant
import org.springframework.restdocs.payload.FieldDescriptor
open class DocsField : FieldDescriptor {
constructor(path: String?) : super(path) {
this.attributes(DocsAttributeKeys.DEPTH.set(this.depth, this.path))
}
constructor(path: String, docsField: DocsField) : super(path) {
this.type(docsField.type)
this.description(docsField.description)
this.depth = docsField.depth
this.format = docsField.format
this.default = docsField.default
this.example = docsField.example
if (docsField.isIgnored) this.ignored()
if (docsField.isOptional) this.optional()
}
var depth: Int = 1
protected open var default: String?
get() = this.attributes.getOrDefault(DocsAttributeKeys.DEFAULT.code, " ") as String
set(value) {
this.attributes(DocsAttributeKeys.DEFAULT.set(value))
}
protected open var format: String?
get() = this.attributes.getOrDefault(DocsAttributeKeys.FORMAT.code, " ") as String
set(value) {
this.attributes(DocsAttributeKeys.FORMAT.set(value))
}
protected open var example: String?
get() = this.attributes.getOrDefault(DocsAttributeKeys.EXAMPLE.code, " ") as String
set(value) {
this.attributes(DocsAttributeKeys.EXAMPLE.set(value))
}
open infix fun means(value: String): DocsField {
this.description(value)
return this
}
open infix fun defaultValue(value: String): DocsField {
this.default = value
return this
}
open infix fun formattedAs(value: String): DocsField {
this.format = value
return this
}
open infix fun example(value: String): DocsField {
this.example = value
return this
}
open infix fun isOptional(value: Boolean): DocsField {
if (value) this.optional()
return this
}
open infix fun isIgnored(value: Boolean): DocsField {
if (value) this.ignored()
return this
}
// is Last
open infix fun fields(fields: Array<DocsField>): Array<DocsField> {
val parentsDepth = this.depth
val childFieldDepth = this.depth + 1
val childFields: Array<DocsField> = fields
.map { DocsField("${this.path}.${it.path}", it) }
.toTypedArray()
childFields.forEach {
it.depth = childFieldDepth
(1..parentsDepth).forEach { depth -> it.attributes(DocsAttributeKeys.DEPTH.set(depth, " ")) }
it.attributes(DocsAttributeKeys.DEPTH.set(childFieldDepth, it.path.split(".").last()))
}
return arrayOf(this, *childFields)
}
}RestDocsFieldInfix
시작점을 구분하기 위해서 String.typeinfix fuction을 정의하여, type을 맨 처음 정의하도록 강제하고 field 정의 방식을 확립.
package com.example.kotlinapiserverguide.restDocs.infix
import com.example.kotlinapiserverguide.restDocs.constant.DocsField
import com.example.kotlinapiserverguide.restDocs.constant.DocsFieldType
import org.springframework.restdocs.payload.JsonFieldType
private fun createField(value: String, type: JsonFieldType, optional: Boolean = false): DocsField {
val docsField = DocsField(value)
docsField.type(type)
docsField.description("")
if (optional) docsField.optional()
return docsField
}
infix fun String.type(docsFieldType: DocsFieldType): DocsField {
return createField(this, docsFieldType.type)
}RestDocsPathParameterInfix
pathParameter의 경우에는 기존의 DocsField Class를 사용하지 않고 타입을 지정할 필요가 없기 때문에 type이 아닌 바로 means(설명 또는 의미)로 시작할 수 있는 infix function을 따로 정의.
package com.example.kotlinapiserverguide.restDocs.infix
import org.springframework.restdocs.request.ParameterDescriptor
import org.springframework.restdocs.request.RequestDocumentation
private fun createField(name: String, description: String): ParameterDescriptor {
return RequestDocumentation.parameterWithName(name)
.description(description)
}
infix fun String.means(description: String): ParameterDescriptor {
return createField(this, description)
}