Perbaikan terbaru pra-rumah sakit atau "Hei Sombong! Di mana kesalahan saya? "

Pernahkah Anda menyesuaikan selama perbaikan terbaru ke master? Tidak ?! Tetapi saya berhasil!

Cerita ini tentang bagaimana saya lupa memperbarui dokumentasinya. Sebagai hasilnya, saya menulis sebuah plugin untuk Swagger (yang kedua kalinya). Dan bagaimana saya terbawa dengan itu sehingga saya lupa tentang cuti sakit saya dan terus membaik!


Dan sedikit lagi tentang Opsional bukan dari Java 8.

Kami menggunakan Swagger untuk membuat dokumentasi interaktif.

Karena itu, ketika Anda membuat metode di API, maka:

0. Tambahkan anotasi yang diperlukan, seperti @RequestMapping dan sebagainya.

1. Tambahkan @ErrorCodes (anotasi kami sendiri), dan daftarkan kode kesalahan string yang dapat dikembalikan oleh metode ini.

2. Tambahkan @ApiOperation dan duplikat informasi tentang kesalahan ini di bidang catatan.

3. Tambahkan sisa anotasi ...

Itu terlihat seperti ini (dihapus tidak perlu dan disederhanakan):

@ApiOperation( value = "Some description.", notes = "List of possible error codes:" + "<ul>" + " <li>sms.verification.code.fail</li>" + "</ul>") @PostMapping("/security/confirmation/check") @ErrorCodes(values = {"sms.verification.code.fail"}) public ResponseDto check(@ApiParam @RequestBody @Valid RequestDto request) {... } 

Poin 2 adalah sumber kegagalan saya ketika saya menambahkan @ErrorCodes, tetapi lupa untuk menuliskan kode kesalahan string dalam @ApiOperation. Puas dengan diri saya sendiri, tetapi dengan sedikit rasa cemas, saya memberikan Permintaan Tarik ke Peninjauan Kode. Dan di sini mereka memberi tahu saya bahwa saya lupa tentang catatan! Mereka juga menjelaskan bahwa Swagger tidak mengambil informasi dari @ErrorCodes dan itulah sebabnya Anda harus mendaftarkannya secara manual. Malam itu, semuanya berakhir dengan bahagia. Memperbaiki cacatnya dan pergi cuti sakit.

Mungkin akan normal untuk mengambil dan melanjutkan. Beri tanda centang di rak untuk orang lain sama seperti yang mereka katakan, Max, hati-hati, perhatikan itu ...

Tetapi saya tidak berhasil. Sepanjang sore dan pagi berikutnya dihabiskan untuk mengajar Swagger untuk membaca anotasi kami dan secara mandiri menambahkan kode yang sama ini dalam catatan.

Langkah 1. Seseorang ada di sini ...


Dari pencarian sepintas, saya berhasil mengetahui bahwa seseorang telah mencoba membuat teman-teman Swagger dengan penjelasan mereka. Ada juga tautan ke dokumentasi SpringFox yang mengatakan bahwa Anda dapat menulis plugin!

Kebahagiaan yang membahagiakan telah menyelimuti saya sehingga saya bahkan lupa tentang flu biasa dan sakit! Dalam artikel saya di masa depan, "Bagaimana tidak keluar dari perusahaan tiga kali", saya berbagi tiga cerita tentang menyelamatkan orang yang tenggelam. Salah satunya adalah tentang bagaimana saya berhasil menulis plugin untuk Chrome + Firefox, yang dipercepat bekerja dengan Jenkins beberapa kali. Saya sangat senang menulisnya! Bagaimanapun, ini adalah proyek mikro! Startup saya yang sangat, sangat sederhana, tetapi dengan orang-orang nyata yang menggunakannya. Kemudian saya keluar dari rutinitas lagi dan menemukan inspirasi. Burnout hilang. Tapi saya lebih baik membicarakannya di artikel mendatang. Sementara itu, kembali ke plugin untuk Swagger.

Aksi 2. Berhasil!


Menulis sesuatu yang bekerja ternyata mudah. Saya mengambil contoh plugin dari dokumentasi resmi SpringFox, menghapus semua yang tidak perlu dan menambahkan yang benar.

Plugin. Versi 1
 @Component @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1) public class SwaggerErrorCodesConfiguration implements OperationBuilderPlugin { /** * Appends note of operation. Adds error codes to note of operation. * <code> * <h3>List of possible errors:</h3> * <ul> * <li>error.code.1</li> * <li>error.code.2</li> * <li>error.code.3</li> * </ul> * </code> * @param context operation context */ @Override public void apply(OperationContext context) { Method operationMethod = context.getHandlerMethod().getMethod(); // Check method is annotated by @ErrorCodes ErrorCodes errorCodes = findAnnotation(operationMethod, ErrorCodes.class); if (errorCodes == null) { return; } StringBuilder errorCodesNote = new StringBuilder(); errorCodesNote.append("<h3>List of possible errors:</h3>"); errorCodesNote.append("<ul>"); for (String errorCode: errorCodes.values()) { errorCodesNote.append("<li>").append(errorCode).append("</li>"); } errorCodesNote.append("</ul>"); // Write new version of notes. context.operationBuilder().notes(errorCodesNote.toString()).build(); } @Override public boolean supports(DocumentationType delimiter) { return SwaggerPluginSupport.pluginDoesApply(delimiter); } } 


Saya mulai menguji dengan metode yang tidak menentukan nilai untuk catatan di @ApiOperation.

 @ApiOperation(value = "Some description.") @PostMapping("/security/confirmation/check") @ErrorCodes(values = {"sms.verification.code.fail"}) public ResponseDto check(@ApiParam @RequestBody @Valid RequestDto request) { ... } 

Luncurkan dan ... Hasilnya! Hore, itu berhasil! Kode string sms.verification.code.fail muncul di catatan!



Langkah 3. Berhasil, tetapi tidak berhasil.


Lalu saya menambahkan beberapa kata ke catatan dan saya mendapat kode ini:

 @ApiOperation(value = "Some description.", notes = "Some initial note.") @PostMapping("/security/confirmation/check") @ErrorCodes(values = {"sms.verification.code.fail"}) public ResponseDto check(@ApiParam @RequestBody @Valid RequestDto request) { ... } 

Diluncurkan lagi. Hasilnya ... tidak terduga. Plugin SpringFox menimpa nilai catatan saat membuat dokumentasi (O_o)!

Saya melihat bagaimana context.operationBuilder (). Notes (String) berfungsi dan saya melihat yang berikut di sana:

 public OperationBuilder notes(String notes) { this.notes = (String)BuilderDefaults.defaultIfAbsent(notes, this.notes); return this; } 

Um ... Ok, maka kita akan mengambil nilai catatan saat ini dan menambahkan kode kesalahan. Tetap mendapatkan anotasi @ApiOperation, mengambil nilai yang diinginkan dan menambahkan apa yang saya bentuk sendiri.

Jadi, versi final ( tersedia di gist.github.com )

Plugin. Versi 2
 @Component @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1) public class SwaggerErrorCodesConfiguration implements OperationBuilderPlugin { /** * Appends note of operation. Adds error codes to note of operation. * <code> * <h3>List of possible errors:</h3> * <ul> * <li>error.code.1</li> * <li>error.code.2</li> * <li>error.code.3</li> * </ul> * </code> * @param context operation context */ @Override public void apply(OperationContext context) { Method operationMethod = context.getHandlerMethod().getMethod(); // Check method is annotated by @ApiOperation ApiOperation apiOperation = findApiOperationAnnotation(operationMethod).orNull(); if (apiOperation == null) { return; } // Check method is annotated by @ErrorCodes ErrorCodes errorCodes = findAnnotation(operationMethod, ErrorCodes.class); if (errorCodes == null) { return; } // Prepend notes by using current value of notes in @ApiOperation StringBuilder errorCodesNote = new StringBuilder(apiOperation.notes()); errorCodesNote.append("<h3>List of possible errors:</h3>"); errorCodesNote.append("<ul>"); for (String errorCode: errorCodes.values()) { errorCodesNote.append("<li>").append(errorCode).append("</li>"); } errorCodesNote.append("</ul>"); // Write new version of notes. context.operationBuilder().notes(errorCodesNote.toString()).build(); } @Override public boolean supports(DocumentationType delimiter) { return SwaggerPluginSupport.pluginDoesApply(delimiter); } } 


Sekarang ternyata seperti yang seharusnya!



Langkah 4. Bagaimana dengan Opsional bukan dari Java 8?


Pada awal bekerja pada plugin, saya tidak bisa mengerti apa yang salah dengan Opsional, yang dikembalikan saat mencari anotasi. Kelas ini tidak memiliki metode standar yang digunakan untuk bekerja dengan java.util.Optional . Misalnya, tidak ada metode ifPresent , tetapi ada metode orNull .
Ternyata SpringFox menggunakan Opsional dari Guava .

TL; DR


Saya menulis sebuah plugin untuk SpringFox, yang merupakan komponen Spring dan dipanggil pada tahap pembuatan dokumentasi untuk membaca nilai dari penjelasan @ErrorCodes kami.

Kode plugin
 @Component @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1) public class SwaggerErrorCodesConfiguration implements OperationBuilderPlugin { /** * Appends note of operation. Adds error codes to note of operation. * <code> * <h3>List of possible errors:</h3> * <ul> * <li>error.code.1</li> * <li>error.code.2</li> * <li>error.code.3</li> * </ul> * </code> * @param context operation context */ @Override public void apply(OperationContext context) { Method operationMethod = context.getHandlerMethod().getMethod(); // Check method is annotated by @ApiOperation ApiOperation apiOperation = findApiOperationAnnotation(operationMethod).orNull(); if (apiOperation == null) { return; } // Check method is annotated by @ErrorCodes ErrorCodes errorCodes = findAnnotation(operationMethod, ErrorCodes.class); if (errorCodes == null) { return; } // Prepend notes by using current value of notes in @ApiOperation StringBuilder errorCodesNote = new StringBuilder(apiOperation.notes()); errorCodesNote.append("<h3>List of possible errors:</h3>"); errorCodesNote.append("<ul>"); for (String errorCode: errorCodes.values()) { errorCodesNote.append("<li>").append(errorCode).append("</li>"); } errorCodesNote.append("</ul>"); // Write new version of notes. context.operationBuilder().notes(errorCodesNote.toString()).build(); } @Override public boolean supports(DocumentationType delimiter) { return SwaggerPluginSupport.pluginDoesApply(delimiter); } } 

Source: https://habr.com/ru/post/id420841/


All Articles