Validation
@Configuration
class SpringDataRestConfiguration : RepositoryRestConfigurer {
override fun configureRepositoryRestConfiguration(
config: RepositoryRestConfiguration, cors: CorsRegistry
) {
config.exposeIdsFor(Template::class.java)
}
override fun configureValidatingRepositoryEventListener(
validatingListener: ValidatingRepositoryEventListener?
) {
validatingListener?
.addValidator("beforeCreate", TemplateValidator())
}
class TemplateValidator : Validator {
override fun supports(clazz: Class<*>): Boolean =
Template::class.java.equals(clazz)
override fun validate(target: Any, errors: Errors) {
val template = target as Template
if (template.name != null && template.name!!.length < 3)
errors.rejectValue("name", "name.too.short")
DocumentBuilderFactory.newInstance().newDocumentBuilder()
.runCatching { parse(template.template.byteInputStream()) }
.onFailure {
errors.rejectValue("name", "incorrect.template")
}
}
}
}
API and model tuning
@Entity
@Table(name = "templates")
class Template {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
var id: Long? = null
@Column(name = "name")
@Size(min = 3) // doesn't work
var name: String? = null
@Column(name = "type")
var type: TemplateType = TemplateType.SVG
@Column(name = "template")
var template: String = ""
@Column(name = "created")
@JsonProperty(value = "created_at",
access = JsonProperty.Access.READ_ONLY)
var created: Date? = null
@Column(name = "updated")
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
var updated: Date? = null
@PrePersist
fun onCreate() {
updated = Date()
created = Date()
}
}
@Configuration
class SpringDataRestConfiguration : RepositoryRestConfigurer {
override fun configureRepositoryRestConfiguration(
config: RepositoryRestConfiguration, cors: CorsRegistry
) {
config.exposeIdsFor(Template::class.java)
}
}
CRUD but nicely
@RestController
@RequestMapping(path = ["/api/new/templates"])
class TemplateController(val templateRepository: SpringTemplateRepository) {
@PostMapping
@Transactional
fun create(
@Valid @RequestBody templateCreateDTO: TemplateCreateDTO
) {
templateRepository.save(
Template.create(
templateCreateDTO.name,
templateCreateDTO.type,
templateCreateDTO.contents
)
)
}
@GetMapping
@Transactional
fun retrieve(
@PageableDefault(size = 50) paging: Pageable,
@PathVariable name: String
): List =
templateRepository
.findAllByNameContaining(name, paging).toList()
@PutMapping(path = ["/{id}"])
@Transactional
fun update(
@PathVariable id: Long,
@Valid @RequestBody templateCreateDTO: TemplateCreateDTO
) {
templateRepository.findById(id)
.orElseThrow { ResourceNotFoundException() }
.apply {
name = templateCreateDTO.name
type = templateCreateDTO.type
template = templateCreateDTO.contents
}.also {
templateRepository.save(it)
}
}
@DeleteMapping(path = ["/{id}"])
@Transactional
fun delete(@PathVariable id: Long) =
templateRepository.findById(id)
.orElseThrow { ResourceNotFoundException() }
.also { templateRepository.delete(it) }
}
data class TemplateCreateDTO(
val name: String,
val type: Template.TemplateType,
@field:ValidXml(message = "SVG file is invalid bruh")
val contents: String
);
But is it a correct CRUD?