الإصلاح العاجل قبل دخول المستشفى أو "Hey Swagger! أين أخطائي؟ "

هل سبق لك أن قمت بتعديل أثناء الإصلاح إلى سيد؟ لا ؟! ولكن نجحت!

تدور هذه القصة حول كيف نسيت تحديث الوثائق. ونتيجة لذلك ، كتبت ملحقًا لـ Swagger (المرة الثانية). وكيف ابتعدت معها حتى نسيت إجازتي المرضية وذهبت في الإصلاح!


وأكثر قليلا عن اختياري ليس من جافا 8.

نستخدم Swagger لإنشاء وثائق تفاعلية.

لذلك ، عند إنشاء طريقة في API ، ثم:

0. أضف التعليقات التوضيحية الضرورية ، مثلRequestMapping وما إلى ذلك.

1. أضف رموز الخطأ (التعليق التوضيحي الخاص بنا) ، وقم بإدراج رموز خطأ السلسلة التي قد ترجعها هذه الطريقة في الاستجابة.

2. قم بإضافةApiOperation ومعلومات مكررة حول هذه الأخطاء في حقل الملاحظات.

3. إضافة بقية التعليقات التوضيحية ...

بدا الأمر مثل هذا (تمت إزالته وتبسيطه):

@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) {... } 

كانت النقطة 2 مصدر فشلي عندما أضفت رموز الخطأ ، ولكن نسيت سرد رموز خطأ السلسلة فيApiOperation. كنت راضيًا عن نفسي ، ولكن مع شعور طفيف بالقلق ، أعطيت طلب السحب لمراجعة الشفرة. وهنا أبلغوني أنني نسيت الملاحظات! كما أوضحوا أن Swagger لا تلتقط المعلومات منErrorCodes ولهذا السبب يجب عليك تسجيلها يدويًا. في ذلك المساء ، انتهى كل شيء بسعادة. صحح عيبه وذهب في إجازة مرضية.

ربما سيكون من الطبيعي أن نتحرك ونمضي قدما. ضع علامة الاختيار على الرف للآخرين كما يقولون ، ماكس ، كن حذرا ، انتبه إليه ...

لكني لم أنجح. تم قضاء كل مساء وصباح اليوم التالي على تعليم Swagger لقراءة التعليق التوضيحي وإضافة هذه الرموز نفسها بشكل مستقل في الملاحظات.

الخطوة 1. شخص ما كان هنا ...


من خلال البحث السريع ، تمكنت من معرفة أن شخصًا ما قد حاول بالفعل تكوين صداقات Swagger مع تعليقه التوضيحي. كان هناك أيضًا رابط لوثائق SpringFox التي تقول أنه يمكنك كتابة مكون إضافي!

لقد غطتني السعادة السعيدة لدرجة أنني نسيت حتى إجازة البرد والمرض الشائعة! في مقالتي المستقبلية ، "كيف لا تغادر الشركة ثلاث مرات" ، أشارك ثلاث قصص عن إنقاذ الغرق. أحدها يتعلق بكيفية تمكنت من كتابة مكون إضافي لمتصفح Chrome + Firefox ، والذي سرع العمل مع Jenkins عدة مرات. كنت ممتعا جدا لكتابته! بعد كل شيء ، هذا مشروع صغير! شركتي البسيطة للغاية ، ولكن مع أناس حقيقيين يستخدمونها. ثم خرجت من الروتين مرة أخرى ووجدت الإلهام. ذهب الإرهاق. لكن من الأفضل التحدث عن هذا في مقال لاحق. في غضون ذلك ، عد إلى المكون الإضافي لـ Swagger.

العمل 2. إنه يعمل!


اتضح أن كتابة شيء ما عمل أمر سهل. أخذت مثالاً على مكون إضافي من وثائق SpringFox الرسمية ، وأزلت كل شيء غير ضروري وأضفت البرنامج المناسب.

البرنامج المساعد. الإصدار 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); } } 


لقد بدأت الاختبار باستخدام طريقة لا تحدد قيمة للملاحظات فيApiOperation.

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

إطلاق و ... النتيجة! مرحى ، إنها تعمل! ظهر رمز سلسلة sms.verification.code.fail في الملاحظات!



الخطوة 3. تعمل ، لكنها لا تعمل.


ثم أضفت بضع كلمات إلى الملاحظات وحصلت على هذا الرمز:

 @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) { ... } 

تم إطلاقه مرة أخرى. كانت النتيجة ... غير متوقعة. المكون الإضافي SpringFox يستبدل قيمة الملاحظات عند إنشاء الوثائق (O_o)!

ألقي نظرة على كيفية عمل context.operationBuilder (). الملاحظات (سلسلة) وأرى ما يلي هناك:

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

أم ... حسنًا ، سنأخذ القيمة الحالية للملاحظات ونضيف رموز الخطأ. يبقى الحصول على التعليق التوضيحيApiOperation ، والحصول على القيمة المطلوبة وإضافة ما أقوم بتشكيله بنفسي.

لذا ، فإن النسخة النهائية ( متوفرة على gist.github.com )

البرنامج المساعد. الإصدار 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); } } 


الآن اتضح كما يجب!



الخطوة 4. ماذا عن اختياري ليس من Java 8؟


في بداية العمل على المكون الإضافي ، لم أتمكن من فهم ما هو الخطأ في الاختياري ، والذي يتم إرجاعه عند البحث عن التعليقات التوضيحية. لم يكن لهذه الفئة الطرق القياسية المستخدمة في العمل مع java.util.Optional . على سبيل المثال ، لا توجد طريقة ifPresent ، ولكن هناك طريقة orNull .
اتضح أن SpringFox يستخدم اختياري من الجوافة .

TL ؛ د


لقد كتبت مكونًا إضافيًا لـ SpringFox ، وهو أحد مكونات Spring ويتم استدعاؤه في مرحلة إنشاء الوثائق لقراءة القيم من التعليق التوضيحي لـErrorCodes.

كود البرنامج المساعد
 @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/ar420841/


All Articles