Salam! Bu gün JavaRush-da bir qrup məqaləyə abunə əlavə edəcəyik. Bu, GitHub-da JRTB-5 məsələsinə uyğundur . İzah edim: JavaRush-un Məqalələr adlı bölməsi var və orada Məqalələr Qrupları var. İdeya teleqram botu vasitəsilə bir və ya bir neçə qrupdan yeni məqalə haqqında bildirişlər almaqdır.
İlk növbədə JavaRush API-ə http sorğuları yaratmaq üçün kitabxana olan Unitrest əlavə etməlisiniz:
mikroskopla mismar vururdum, Unirest vasitəsilə http sorğusundan cavab aldım, onu simə çevirdim və sonra bu simli Cekson vasitəsilə təhlil etdim... Bu, qorxulu, yorucu idi və çoxlu əlavə şeylər tələb edirdi. Bu kitabxanada onun necə göründüyünü görə bilərsiniz. Əllərimə düşən kimi hər şeyi yenidən nəzərdən keçirəcəyəm.
İndi sual budur: kodumuz gözlədiyimiz kimi işləyirmi? Cavab asandır: sadəcə onlar üçün testlər yazmalısınız. Bir dəfədən çox dediyim kimi, tərtibatçılar testlər yazmağı bacarmalıdırlar. Buna görə də, Swagger UI-dən istifadə edərək sorğular göndərəcəyik, cavablara baxacağıq və gözlənilən nəticə kimi onları testlərdə əvəz edəcəyik. Qrupların sayının statik olmadığını və dəyişə biləcəyini dərhal fərq etdiniz. Və haqlısan. Yeganə sual budur ki, bu rəqəm nə qədər tez-tez dəyişir? Çox nadir hallarda, buna görə də bir neçə ay ərzində bu dəyərin statik olacağını deyə bilərik. Və bir şey dəyişərsə, testləri yeniləyəcəyik. Görüşün - JavaRushGroupClientTest:
bəyənin, abunə olun, zəng edin , layihəmizə ulduz verin , şərh yazın və məqaləni qiymətləndirin!
JRTB-5 əlavə edin
Tutaq ki , Uğur Hekayələri qrupunun məqalələri ilə maraqlanıram . Buna görə də bu qrupdan yeniləmələrə abunə olmaq və hər dəfə yeni nəşrə keçid almaq istəyirəm. Bu tapşırığın bir hissəsi olaraq, JavaRush-da qruplarla işləmək üçün açıq API-dən necə istifadə etməyi öyrənməliyik. Elə bu anda belə bir şey gəldi. Açıq API-nin təsvirinə keçid buradadır .Dostlar! Bir layihə və ya yeni məqalə üçün yeni kodun nə vaxt buraxıldığını dərhal bilmək istəyirsiniz? tg kanalıma qoşulun . Orada məqalələrimi, düşüncələrimi və açıq mənbə inkişafımı bir yerdə toplayıram. |
Swagger nədir? İndi bunu anlayaq
Biz hələ səxavət haqqında danışmamışıq. Bilməyənlər üçün qısaca izah edəcəyəm: bu, serverin API-yə açıq şəkildə baxa biləcəyiniz və ona bəzi sorğular verməyə çalışa biləcəyiniz bir yerdir. Tipik olaraq, lovğalanma mümkün sorğuları qruplaşdırır. Bizim vəziyyətimizdə üç qrup var: forum-sual , qrup , yazı . Hər qrupda bu sorğunun qurulması üçün bütün lazımi məlumatları göstərən bir və ya bir neçə sorğu olacaq (yəni, hansı əlavə parametrləri ötürmək olar, onlarla nə etmək olar, hansı http metodu və s.). Bu mövzuda daha çox oxumağı və izləməyi məsləhət görürəm, çünki bu, demək olar ki, hər birinizin qarşılaşacağı inkişafın bir hissəsidir. Bunu anlamaq üçün JavaRush-da neçə qrup olduğunu öyrənək. Bunu etmək üçün qrup nəzarətçi qrupunu genişləndirin və Sorğunu alın /api/1.0/rest/groups/count seçin . Bu bizə JavaRush-da qrupların sayını qaytaracaq. Baxaq: Şəkil bu sorğunun bir neçə parametri (sorğu, tip, filtr) dəstəklədiyini göstərir. Bu sorğunu sınamaq üçün Sınaq düyməsini tapmalısınız , bundan sonra bu parametrlər konfiqurasiya edilə bilər: Siz həmçinin orada növü, filtri və sorğunu konfiqurasiya edə bilərsiniz (burada əslində maraqlıdır: bu, mətn axtarışı olacaq. qrup). Ancaq indi onu heç bir məhdudiyyət olmadan işə salaq və JavaRush-da neçə qrup olduğunu görək. Bunu etmək üçün İcra et üzərinə klikləyin. Aşağıda bu sorğuya cavab (Server Cavab bölməsində) olacaq: Görürük ki, cəmi 30 qrup var , bu sorğu 95 ms-də tamamlandı və cavabda bəzi başlıqlar dəsti var. Sonra bəzi parametrləri konfiqurasiya etməyə çalışaq. ŞİRKƏT dəyərinə bərabər tip parametrini seçək və nəticənin necə dəyişdiyini görək: Onlardan 4-ü var.Bunu necə yoxlamaq olar? Asandır: vebsayta daxil ola, məqalə bölməsini tapa, bütün qrupları seçib ora uyğun filtri əlavə edə bilərsiniz ( https://javarush.com/groups/all?type=COMPANY ). Və bəli, həqiqətən, onlardan yalnız 4-ü var.Hərçənd əslində üçü var :D İndiyə qədər uyğun gəlir. Yeri gəlmişkən, universitetləri yoxlasaq, hələ ki, yoxdur. Sadəcə əylənmək üçün Javarush-a daxil olduğunuz və daxil olmadığınız brauzerdə filter = MY təyin etsəniz nə baş verdiyinə baxın. Swagger haqqında daha çox - Habré-dəki bu məqalədə .Qruplar üçün Javarush API üçün müştərinin yazılması
İndi açıq API əsasında biz sorğu verə bilən, cavab ala bilən və hansı obyektlərin gələcəyini dəqiq bilən Java müştərisi yazacağıq. Biz, həmçinin "Modellər" bölməsindən (səhifənin ən aşağı hissəsində) obyektləri alacağıq . Gəlin yeni paket yaradaq və onu xidmətin, deponun yanında javarushclient adlandıraq. Gələcəkdə biz bunu Javarush İcması təşkilatı daxilində ayrıca kitabxanaya köçürəcəyik və ondan yalnız asılılıq kimi istifadə edəcəyik.<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>${unirest.version}</version>
</dependency>
Və versiyanı xüsusiyyətlər blokuna qoyun:
<unirest.version>3.11.01</unirest.version>
Bir asılılığımız olduqda, kodu əlavə etməyə başlaya bilərik. Gəlin JavaRushGroupClient qrupları üçün müştəri və JavaRushGroupClientImpl sinfində tətbiq yaradaq. Ancaq əvvəlcə DTO-lar (məlumat ötürmə obyektləri) - yəni obyektləri müştəri üçün lazım olan bütün məlumatları daşıyacaq siniflər yaratmalısınız. Bütün modellərə səliqə ilə baxmaq olar.Ən aşağı hissədə Modellər bölməsi var , onları saya bilərsiniz. GroupDiscussionInfo-nun zəlzələdə belə görünür: javarushclient paketində biz dto paketi yaradacağıq ki, bu paketə zəlzələdən gələn məlumatlar əsasında aşağıdakı sinifləri əlavə edəcəyik:
-
MeGroupInfoStatus :
package com.github.javarushcommunity.jrtb.javarushclient.dto; /** * Member group status. */ public enum MeGroupInfoStatus { UNKNOWN, CANDIDATE, INVITEE, MEMBER, EDITOR, MODERATOR, ADMINISTRATOR, BANNED }
-
MeGroupInfo :
package com.github.javarushcommunity.jrtb.javarushclient.dto; import lombok.Data; /** * Group information related to authorized user. If there is no user - will be null. */ @Data public class MeGroupInfo { private MeGroupInfoStatus status; private Integer userGroupId; }
-
GroupInfoType :
package com.github.javarushcommunity.jrtb.javarushclient.dto; /** * Group Info type; */ public enum GroupInfoType { UNKNOWN, CITY, COMPANY, COLLEGE, TECH, SPECIAL, COUNTRY }
-
UserDiscussionInfo :
package com.github.javarushcommunity.jrtb.javarushclient.dto; import lombok.Data; /** * DTO for User discussion info. */ @Data public class UserDiscussionInfo { private Boolean isBookmarked; private Integer lastTime; private Integer newCommentsCount; }
-
GroupGörünürlük vəziyyəti :
package com.github.javarushcommunity.jrtb.javarushclient.dto; /** * Group Visibility status. */ public enum GroupVisibilityStatus { UNKNOWN, RESTRICTED, PUBLIC, PROTECTED, PRIVATE, DISABLED, DELETED }
-
Sonra - GroupInfo :
package com.github.javarushcommunity.jrtb.javarushclient.dto; import lombok.Data; import lombok.ToString; /** * Group Info DTO class. */ @Data @ToString public class GroupInfo { private Integer id; private String avatarUrl; private String createTime; private String description; private String key; private Integer levelToEditor; private MeGroupInfo meGroupInfo; private String pictureUrl; private String title; private GroupInfoType type; private Integer userCount; private GroupVisibilityStatus visibilityStatus; }
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* Group discussion info class.
*/
@EqualsAndHashCode(callSuper = true)
@Data
@ToString(callSuper = true)
public class GroupDiscussionInfo extends GroupInfo {
private UserDiscussionInfo userDiscussionInfo;
private Integer commentsCount;
}
Bizə həmçinin GroupFilter sorğusu üçün filtr lazım olacaq :
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* Filters for group requests.
*/
public enum GroupFilter {
UNKNOWN, MY, ALL
}
ID ilə əldə etmək sorğusunda o, GroupDiscussionInfo-nu qaytarır və qruplar toplusu sorğusunda siz həm GroupInfo, həm də GroupDiscussionInfo əldə edə bilərsiniz. Sorğularda növ, sorğu, filtr, ofset və limit ola biləcəyi üçün gəlin ayrıca GroupRequestArgs sinfi yaradaq və onu qurucu sinifinə çevirək (qurucu nümunəsinin nə olduğunu oxuyun):
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.*;
import java.util.HashMap;
import java.util.Map;
import static java.util.Objects.nonNull;
/**
* Request arguments for group requests.
*/
@Builder
@Getter
public class GroupRequestArgs {
private final String query;
private final GroupInfoType type;
private final GroupFilter filter;
/**
* specified where to start getting groups
*/
private final Integer offset;
/**
* Limited number of groups.
*/
private final Integer limit;
public Map populateQueries() {
Map queries = new HashMap<>();
if(nonNull(query)) {
queries.put("query", query);
}
if(nonNull(type)) {
queries.put("type", type);
}
if(nonNull(filter)) {
queries.put("filter", filter);
}
if(nonNull(offset)) {
queries.put("offset", offset);
}
if(nonNull(limit)) {
queries.put("limit", limit);
}
return queries;
}
}
Qrupların sayını axtarmaq üçün bir qədər fərqlidir. Yalnız sorğu, növ və filtr var. Və deyəsən kodu dublikat etmək istəmirsiniz. Eyni zamanda, onları birləşdirməyə başlasanız, inşaatçılarla işləyərkən çirkin çıxır. Ona görə də onları ayırıb kodu təkrarlamaq qərarına gəldim. GroupCountRequestArgs belə görünür :
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Builder;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
import static java.util.Objects.nonNull;
/**
* Request arguments for group count requests.
*/
@Builder
@Getter
public class GroupsCountRequestArgs {
private final String query;
private final GroupInfoType type;
private final GroupFilter filter;
public Map populateQueries() {
Map queries = new HashMap<>();
if (nonNull(query)) {
queries.put("query", query);
}
if (nonNull(type)) {
queries.put("type", type);
}
if (nonNull(filter)) {
queries.put("filter", filter);
}
return queries;
}
}
Bəli, mən qeyd etməmişəm ki, son iki sinifdə sorğu yaratmaq üçün xəritə hazırlayacaq populateQueries metodu var (bunu sonra görəcəksiniz). Yuxarıda təsvir olunan siniflərə əsaslanaraq JavaRushGroupClient üçün interfeys yaradaq :
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupsCountRequestArgs;
import java.util.List;
/**
* Client for Javarush Open API corresponds to Groups.
*/
public interface JavaRushGroupClient {
/**
* Get all the {@link GroupInfo} filtered by provided {@link GroupRequestArgs}.
*
* @param requestArgs provided {@link GroupRequestArgs}.
* @return the collection of the {@link GroupInfo} objects.
*/
List<GroupInfo> getGroupList(GroupRequestArgs requestArgs);
/**
* Get all the {@link GroupDiscussionInfo} filtered by provided {@link GroupRequestArgs}.
*
* @param requestArgs provided {@link GroupRequestArgs}
* @return the collection of the {@link GroupDiscussionInfo} objects.
*/
List<GroupDiscussionInfo> getGroupDiscussionList(GroupRequestArgs requestArgs);
/**
* Get count of groups filtered by provided {@link GroupRequestArgs}.
*
* @param countRequestArgs provided {@link GroupsCountRequestArgs}.
* @return the count of the groups.
*/
Integer getGroupCount(GroupsCountRequestArgs countRequestArgs);
/**
* Get {@link GroupDiscussionInfo} by provided ID.
*
* @param id provided ID.
* @return {@link GroupDiscussionInfo} object.
*/
GroupDiscussionInfo getGroupById(Integer id);
}
GroupInfo və ya GroupDiscussionInfo məlumatını əldə etmək istədiyimiz halda iki fərqli sorğu əlavə edilib. Əks halda, bu sorğular eynidir və yeganə fərq onda olacaq ki, birində "includeDiscussion" işarəsi doğru, digərində isə yalan olacaq. Buna görə də üç deyil, 4 üsul var idi. İndi həyata keçirməyə başlayaq:
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupsCountRequestArgs;
import kong.unirest.GenericType;
import kong.unirest.Unirest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Implementation of the {@link JavaRushGroupClient} interface.
*/
@Component
public class JavaRushGroupClientImpl implements JavaRushGroupClient {
private final String javarushApiGroupPath;
public JavaRushGroupClientImpl(@Value("${javarush.api.path}") String javarushApi) {
this.javarushApiGroupPath = javarushApi + "/groups";
}
@Override
public List<GroupInfo> getGroupList(GroupRequestArgs requestArgs) {
return Unirest.get(javarushApiGroupPath)
.queryString(requestArgs.populateQueries())
.asObject(new GenericType<list<GroupInfo>>() {
})
.getBody();
}
@Override
public List<GroupDiscussionInfo> getGroupDiscussionList(GroupRequestArgs requestArgs) {
return Unirest.get(javarushApiGroupPath)
.queryString(requestArgs.populateQueries())
.asObject(new GenericType<list<GroupDiscussionInfo>>() {
})
.getBody();
}
@Override
public Integer getGroupCount(GroupsCountRequestArgs countRequestArgs) {
return Integer.valueOf(
Unirest.get(String.format("%s/count", javarushApiGroupPath))
.queryString(countRequestArgs.populateQueries())
.asString()
.getBody()
);
}
@Override
public GroupDiscussionInfo getGroupById(Integer id) {
return Unirest.get(String.format("%s/group%s", javarushApiGroupPath, id.toString()))
.asObject(GroupDiscussionInfo.class)
.getBody();
}
}
Artıq tanış olan Dəyər annotasiyasından istifadə edərək konstruktorda API yolunu əlavə edirəm. Annotasiya daxilindəki dəyərin xassələr faylındakı sahəyə uyğun olduğunu nəzərdə tutur. Buna görə də application.properties-ə yeni sətir əlavə edək:
javarush.api.path=https://javarush.com/api/1.0/rest
Bu dəyər indi bütün API müştəriləri üçün bir yerdə olacaq və API yolu dəyişərsə, biz onu tez bir zamanda yeniləyəcəyik. Əvvəllər Bu kitabxananı yeniləməyə - yalnız unirest kitabxanasının alətlərindən istifadə edərək qəbuledici obyektləri əlavə etməyə cəhd etmək istəyən hər kəs şəxsi mesajda və ya kitabxananın özündə yeni buraxılış kimi yazın. Bu, sizin üçün əsl iş təcrübəsi olacaq, amma buna qarşı deyiləm. Mən tam kodu nəzərdən keçirəcəyəm və lazım gələrsə kömək edəcəm. |
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupsCountRequestArgs;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfoType.TECH;
@DisplayName("Integration-level testing for JavaRushGroupClientImplTest")
class JavaRushGroupClientTest {
private final JavaRushGroupClient groupClient = new JavaRushGroupClientImpl("https://javarush.com/api/1.0/rest");
@Test
public void shouldProperlyGetGroupsWithEmptyArgs() {
//given
GroupRequestArgs args = GroupRequestArgs.builder().build();
//when
List<GroupInfo> groupList = groupClient.getGroupList(args);
//then
Assertions.assertNotNull(groupList);
Assertions.assertFalse(groupList.isEmpty());
}
@Test
public void shouldProperlyGetWithOffSetAndLimit() {
//given
GroupRequestArgs args = GroupRequestArgs.builder()
.offset(1)
.limit(3)
.build();
//when
List<GroupInfo> groupList = groupClient.getGroupList(args);
//then
Assertions.assertNotNull(groupList);
Assertions.assertEquals(3, groupList.size());
}
@Test
public void shouldProperlyGetGroupsDiscWithEmptyArgs() {
//given
GroupRequestArgs args = GroupRequestArgs.builder().build();
//when
List<GroupDiscussionInfo> groupList = groupClient.getGroupDiscussionList(args);
//then
Assertions.assertNotNull(groupList);
Assertions.assertFalse(groupList.isEmpty());
}
@Test
public void shouldProperlyGetGroupDiscWithOffSetAndLimit() {
//given
GroupRequestArgs args = GroupRequestArgs.builder()
.offset(1)
.limit(3)
.build();
//when
List<GroupDiscussionInfo> groupList = groupClient.getGroupDiscussionList(args);
//then
Assertions.assertNotNull(groupList);
Assertions.assertEquals(3, groupList.size());
}
@Test
public void shouldProperlyGetGroupCount() {
//given
GroupsCountRequestArgs args = GroupsCountRequestArgs.builder().build();
//when
Integer groupCount = groupClient.getGroupCount(args);
//then
Assertions.assertEquals(30, groupCount);
}
@Test
public void shouldProperlyGetGroupTECHCount() {
//given
GroupsCountRequestArgs args = GroupsCountRequestArgs.builder()
.type(TECH)
.build();
//when
Integer groupCount = groupClient.getGroupCount(args);
//then
Assertions.assertEquals(7, groupCount);
}
@Test
public void shouldProperlyGetGroupById() {
//given
Integer androidGroupId = 16;
//when
GroupDiscussionInfo groupById = groupClient.getGroupById(androidGroupId);
//then
Assertions.assertNotNull(groupById);
Assertions.assertEquals(16, groupById.getId());
Assertions.assertEquals(TECH, groupById.getType());
Assertions.assertEquals("android", groupById.getKey());
}
}
Testlər əvvəlki üslubda yazılır. Hər sorğu üçün bir neçə test var. Hər şeyi sınamağın mənası yoxdur, çünki bu API-nin artıq ən yaxşı şəkildə sınaqdan keçirildiyini düşünürəm.
Nəticə
Bu məqalənin bir hissəsi olaraq biz JavaRush API-yə qruplar üçün Java müştəri əlavə etdik. Necə deyərlər, yaşa və öyrən. Bu müştərini yazarkən mən onların sənədlərindən istifadə etdim və onların təqdim etdiyi obyektlərlə işdən rahat istifadə etdim. Təklif etdiyim tapşırığa diqqətinizi cəlb edirəm. Kim maraqlanırsa, mənə şəxsi mesaj yaz, çox maraqlı təcrübə olacağına əminəm. Bu birinci hissə idi. İkincisi, biz birbaşa əlavə əmrini yerinə yetirəcəyik və (əgər onu bir məqaləyə uyğunlaşdırsaq) istifadəçinin abunə olduğu qrupların siyahısını əldə edəcəyik. Sonra, bot üçün mətnlər yazmaq arzusu və istedadı olan hər kəs mənə PM-də yazsın. Mən bu məsələdə mütəxəssis deyiləm və hər hansı bir kömək çox faydalı olardı. Bütün bunları açıq mənbə inkişafı kimi rəsmiləşdirək, maraqlı olacaq! Yaxşı, həmişəki kimi -faydalı bağlantılar |
---|
|
GO TO FULL VERSION