Oxirgi besh yil davomida men kabinetim devorida “hamma narsa g‘oyadan boshlanadi” degan iqtibosni yozib yurganman.
Men fitnes ilovasi uchun API to'plamini ishlab chiqishni boshlaganimdan so'ng, xotinim ushbu mahsulotni Etsy-da topdi. Men bu bayonotni yaxshi ko'raman, chunki u yangi loyihani yaratish bosqichlarida meni iste'mol qiladigan ishtiyoqni qamrab oladi. Bu mening kareramdan o'ttiz yil bo'lsa ham muhandis bo'lishning eng sevimli jihati.
Bu vaqt ichida men o‘rgangan narsam shuki, g‘oya, agar kimdir uni boshdan kechirish imkoniga ega bo‘lsagina muhim ahamiyatga ega. Agar g'oya haqiqatga aylanishi uchun juda ko'p vaqt kerak bo'lsa, siz o'tkazib yuborilgan imkoniyatga ega bo'lasiz, chunki kimdir sizni urib yuboradi. Shu sababli startaplar o'z g'oyalarini imkon qadar tezroq bozorga chiqarish uchun doimo poyga qilishadi.
Keling, g'oyani qanday qilib tezda amalga oshirishimiz mumkinligini ko'rib chiqaylik.
Ushbu maqola uchun biz oddiy narsalarni qilamiz. RESTful API yaratish uchun Java 17 va Spring Boot 3 dan foydalanamiz. Ushbu misolda biz qurilishni avtomatlashtirish uchun Gradle-dan foydalanamiz.
Biz bozorga chiqarishni rejalashtirgan xizmat g'oyasi odatda qat'iylik qatlamidan foydalansa-da, biz buni ushbu misol uchun bir chetga surib qo'yamiz va ma'lumotlarimizni ombor sinfida statik ravishda aniqlaymiz.
Biz ushbu misol uchun hech qanday xavfsizlikni qo'shishdan tashvishlanmaymiz, shunchaki ushbu kontseptsiya isbotiga anonim kirishga ruxsat beramiz.
Faraz qilaylik, bizning g'oyamiz motivatsion tirnoq API. Iloji boricha tezroq poyga qilishimizga ishonch hosil qilish uchun men ChatGPT’dan men uchun OpenAPI spetsifikatsiyasini yaratishni so‘radim.
Bir necha soniya ichida ChatGPT javob berdi:
ChatGPT yaratgan YAML-dagi OpenAPI spetsifikatsiyasi:
openapi: 3.0.0 info: title: Motivational Quotes API description: An API that provides motivational quotes. version: 1.0.0 servers: - url: https://api.example.com description: Production server paths: /quotes: get: summary: Get all motivational quotes operationId: getAllQuotes responses: '200': description: A list of motivational quotes content: application/json: schema: type: array items: $ref: '#/components/schemas/Quote' /quotes/random: get: summary: Get a random motivational quote operationId: getRandomQuote responses: '200': description: A random motivational quote content: application/json: schema: $ref: '#/components/schemas/Quote' /quotes/{id}: get: summary: Get a motivational quote by ID operationId: getQuoteById parameters: - name: id in: path required: true schema: type: integer responses: '200': description: A motivational quote content: application/json: schema: $ref: '#/components/schemas/Quote' '404': description: Quote not found components: schemas: Quote: type: object required: - id - quote properties: id: type: integer quote: type: string
Men faqat bitta qo‘lda yangilashni amalga oshirishim kerak edi — Quote
sxemasi uchun id
va quote
xususiyatlari talab qilinganligiga ishonch hosil qilish. Va bu faqat ChatGPT uchun ushbu cheklovni asl so'rovimda eslatishni unutganim uchun.
Shunday qilib, biz API-First yondashuvidan foydalangan holda yangi xizmatni ishlab chiqishga tayyormiz.
Ushbu misol uchun men yangi loyiha yaratish uchun Spring Boot CLI dan foydalanaman. Homebrew yordamida CLI-ni qanday o'rnatishingiz mumkin:
$ brew tap spring-io/tap $ brew install spring-boot
Biz loyihani quotes
deb nomlaymiz va uni quyidagi buyruq bilan yaratamiz:
$ spring init --dependencies=web quotes
Keling, quotes
papkasining mazmunini ko'rib chiqaylik:
$ cd quotes && ls -la total 72 drwxr-xr-x@ 11 jvester 352 Mar 1 10:57 . drwxrwxrwx@ 90 jvester 2880 Mar 1 10:57 .. -rw-r--r--@ 1 jvester 54 Mar 1 10:57 .gitattributes -rw-r--r--@ 1 jvester 444 Mar 1 10:57 .gitignore -rw-r--r--@ 1 jvester 960 Mar 1 10:57 HELP.md -rw-r--r--@ 1 jvester 545 Mar 1 10:57 build.gradle drwxr-xr-x@ 3 jvester 96 Mar 1 10:57 gradle -rwxr-xr-x@ 1 jvester 8762 Mar 1 10:57 gradlew -rw-r--r--@ 1 jvester 2966 Mar 1 10:57 gradlew.bat -rw-r--r--@ 1 jvester 28 Mar 1 10:57 settings.gradle drwxr-xr-x@ 4 jvester 128 Mar 1 10:57 src
Keyinchalik, API-First yondashuvini qo'llash uchun build.gradle
faylini quyida ko'rsatilganidek tahrirlaymiz.
plugins { id 'java' id 'org.springframework.boot' version '3.4.3' id 'io.spring.dependency-management' version '1.1.7' id 'org.openapi.generator' version '7.12.0' } openApiGenerate { generatorName = "spring" inputSpec = "$rootDir/src/main/resources/static/openapi.yaml" outputDir = "$buildDir/generated" apiPackage = "com.example.api" modelPackage = "com.example.model" configOptions = [ dateLibrary: "java8", interfaceOnly: "true", useSpringBoot3: "true", useBeanValidation: "true", skipDefaultInterface: "true" ] } group = 'com.example' version = '0.0.1-SNAPSHOT' java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.openapitools:jackson-databind-nullable:0.2.6' implementation 'io.swagger.core.v3:swagger-annotations:2.2.20' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } sourceSets { main { java { srcDirs += "$buildDir/generated/src/main/java" } } } compileJava.dependsOn tasks.openApiGenerate tasks.named('test') { useJUnitPlatform() }
Nihoyat, yaratilgan OpenAPI spetsifikatsiyasini openapi.yaml
sifatida resources/static
papkaga joylashtiramiz.
IntelliJ-da loyihani ochganimdan so'ng, men API stublarini va model ob'ektlarini yaratish uchun quyidagi buyruqni bajardim.
./gradlew clean build
Endi biz OpenAPI spetsifikatsiyamizdan yaratilgan api
va model
ob'ektlarini ko'rishimiz mumkin. QuotesAPI.java
fayli:
Asosiy xizmat tayyor va bizning OpenAPI shartnomamizga amal qilgan holda, biz xizmatga ba'zi biznes mantiqlarini qo'shishni boshlaymiz.
Birinchidan, biz xizmatimiz uchun ma'lumotlarni qaytaradigan QuotesRepository
sinfini yaratamiz. Yuqorida ta'kidlab o'tilganidek, bu odatda maxsus qat'iylik qatlamida saqlanadi. Ushbu misol uchun beshta tirnoqli ma'lumotlarni qattiq kodlash juda yaxshi ishlaydi va bu bizni diqqatimizni jamlaydi.
@Repository public class QuotesRepository { public static final List<Quote> QUOTES = List.of( new Quote() .id(1) .quote("The greatest glory in living lies not in never falling, but in rising every time we fall."), new Quote() .id(2) .quote("The way to get started is to quit talking and begin doing."), new Quote() .id(3) .quote("Your time is limited, so don't waste it living someone else's life."), new Quote() .id(4) .quote("If life were predictable it would cease to be life, and be without flavor."), new Quote() .id(5) .quote("If you set your goals ridiculously high and it's a failure, you will fail above everyone else's success.") ); public List<Quote> getAllQuotes() { return QUOTES; } public Optional<Quote> getQuoteById(Integer id) { return Optional.ofNullable(QUOTES.stream().filter(quote -> quote.getId().equals(id)).findFirst().orElse(null)); } }
Keyinchalik, biz QuotesRepository
bilan o'zaro aloqada bo'ladigan QuotesService
yaratamiz. Ushbu yondashuvni qo'llash ma'lumotlarni biznes mantig'idan ajratib turadi.
@RequiredArgsConstructor @Service public class QuotesService { private final QuotesRepository quotesRepository; public List<Quote> getAllQuotes() { return quotesRepository.getAllQuotes(); } public Optional<Quote> getQuoteById(Integer id) { return quotesRepository.getQuoteById(id); } public Quote getRandomQuote() { List<Quote> quotes = quotesRepository.getAllQuotes(); return quotes.get(ThreadLocalRandom.current().nextInt(quotes.size())); } }
Nihoyat, biz API-First yondashuvimiz asosida yaratilgan QuotesApi
amalga oshirishimiz kerak:
@Controller @RequiredArgsConstructor public class QuotesController implements QuotesApi { private final QuotesService quotesService; @Override public ResponseEntity<List<Quote>> getAllQuotes() { return new ResponseEntity<>(quotesService.getAllQuotes(), HttpStatus.OK); } @Override public ResponseEntity<Quote> getQuoteById(Integer id) { return quotesService.getQuoteById(id) .map(quote -> new ResponseEntity<>(quote, HttpStatus.OK)) .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); } @Override public ResponseEntity<Quote> getRandomQuote() { return new ResponseEntity<>(quotesService.getRandomQuote(), HttpStatus.OK); } }
Ayni paytda bizda javoblarning kichik to'plami bilan to'liq ishlaydigan Motivatsion Quotes API mavjud.
Spring Boot bizga springdoc-openapi-starter-webmvc-ui
bog'liqligi orqali veb-asoslangan Swagger Docs foydalanuvchi interfeysi uchun imkoniyat beradi.
dependencies { ... implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.5' ... }
Ramka muhandislarga o'zlarining API-larini tavsiflash uchun oddiy izohlardan foydalanishga imkon bersa-da, biz resources/static
papkada mavjud openapi.yaml
faylimizdan foydalanishimiz mumkin.
Biz ushbu yondashuvni application-properties.yaml
faylida va boshqa bir nechta kichik konfiguratsiya yangilanishlari bilan birga amalga oshirishimiz mumkin:
server: port: ${PORT:8080} spring: application: name: quotes springdoc: swagger-ui: path: /swagger-docs url: openapi.yaml
Shunchaki o‘yin-kulgi uchun keling, xizmat ishga tushganda foydalanish uchun banner.txt
faylini qo‘shamiz. Ushbu faylni resources
papkasiga joylashtiramiz.
${AnsiColor.BLUE} _ __ _ _ _ ___ | |_ ___ ___ / _` | | | |/ _ \| __/ _ \/ __| | (_| | |_| | (_) | || __/\__ \ \__, |\__,_|\___/ \__\___||___/ |_| ${AnsiColor.DEFAULT} :: Running Spring Boot ${AnsiColor.BLUE}${spring-boot.version}${AnsiColor.DEFAULT} :: Port #${AnsiColor.BLUE}${server.port}${AnsiColor.DEFAULT} ::
Endi, biz mahalliy xizmatni ishga tushirganimizda, biz bannerni ko'rishimiz mumkin:
Ishga tushgandan so'ng, biz /swagger-docs
so'nggi nuqtasiga tashrif buyurib, Swagger Docs ishlayotganligini tekshirishimiz mumkin.
Va nihoyat, kelajakdagi o'zgarishlarni kuzatishimiz uchun yangi Git-ga asoslangan omborni yaratamiz:
$ git init $ git add . $ git commit -m "Initial commit for the Motivational Quotes API"
Keling, xizmatimizni qanchalik tez ishga tushirishimiz mumkinligini ko'rib chiqaylik .
Hozirgacha mening yangi g‘oyamni joriy etishda asosiy e’tibor OpenAPI spetsifikatsiyasini yaratish va xizmatim uchun qandaydir biznes mantig‘ini yozish bo‘ldi. Spring Boot men uchun hamma narsani hal qildi.
Xizmatimni ishga tushirish haqida gap ketganda, men Heroku-dan foydalanishni afzal ko'raman, chunki u Spring Boot xizmatlariga juda mos keladi. Men bulutli infratuzilma bilan bog'liq muammolarga duch kelmasdan xizmatlarimni tezda tarqata olaman. Heroku shuningdek , Java-ga asoslangan ilovalarim uchun konfiguratsiya qiymatlarini o'tkazishni osonlashtiradi.
Biz foydalanayotgan Java versiyasiga mos kelish uchun loyihaning ildiz papkasida system.properties
faylini yaratamiz. Faylda bitta qator mavjud:
java.runtime.version = 17
Keyin, joylashtirish xatti-harakatlarini sozlash uchun bir xil joyda Procfile
yarataman. Ushbu faylda bitta qator mavjud:
web: java -jar build/libs/quotes-0.0.1-SNAPSHOT.jar
Joylashtirish vaqti keldi. Heroku CLI bilan men bir nechta oddiy buyruqlar yordamida xizmatni o'rnatishim mumkin. Birinchidan, men CLI-ni autentifikatsiya qilaman va keyin yangi Heroku ilovasini yarataman.
$ heroku login $ heroku create Creating app... done, vast-crag-43256 https://vast-crag-43256-bb5e35ea87de.herokuapp.com/ | https://git.heroku.com/vast-crag-43256.git
Mening Heroku ilovam namunasi vast-crag-43256
deb nomlangan (men belgilangan nomda o‘tishim mumkin edi) va xizmat https://vast-crag-43256-bb5e35ea87de.herokuapp.com/ manzilida ishlaydi.
Qilish kerak bo'lgan oxirgi narsa - kodni Heroku-ga yuborish uchun Git buyrug'i yordamida xizmatni o'rnatish:
$ git push heroku master
Ushbu buyruq tugallangandan so'ng, biz Heroku boshqaruv paneli orqali muvaffaqiyatli joylashtirishni tekshirishimiz mumkin:
Endi biz yangi xizmatimizni sinovdan o'tkazishga tayyormiz!
Heroku-da ishlayotgan Motivatsion tirnoq xizmati bilan biz bir qator curl
buyruqlari yordamida hamma narsa kutilganidek ishlayotganini tekshirishimiz mumkin.
Birinchidan, keling, barcha beshta motivatsion tirnoqning to'liq ro'yxatini olaylik:
$ curl \ --location 'https://vast-crag-43256-bb5e35ea87de.herokuapp.com/quotes'
[ { "id":1, "quote":"The greatest glory in living lies not in never falling, but in rising every time we fall." }, { "id":2, "quote":"The way to get started is to quit talking and begin doing." }, { "id":3, "quote":"Your time is limited, so don't waste it living someone else's life." }, { "id":4, "quote":"If life were predictable it would cease to be life, and be without flavor." }, { "id":5, "quote":"If you set your goals ridiculously high and it's a failure, you will fail above everyone else's success." } ]
Keling, ID bo'yicha bitta motivatsion taklifni olamiz:
$ curl \ --location 'https://vast-crag-43256-bb5e35ea87de.herokuapp.com/quotes/3'
{ "id":3, "quote":"Your time is limited, so don't waste it living someone else's life." }
Keling, tasodifiy motivatsion taklifni olaylik:
$ curl --location \ 'https://vast-crag-43256-bb5e35ea87de.herokuapp.com/quotes/random'
{ "id":5, "quote":"If you set your goals ridiculously high and it's a failure, you will fail above everyone else's success." }
Biz hatto Swagger Docs-ni ham ko'rib chiqishimiz mumkin.
Bozor uchun vaqt har qanday g'oyani yaratishi yoki buzishi mumkin. Shuning uchun startaplar o'z innovatsiyalarini imkon qadar tezroq yetkazib berishga lazerga e'tibor qaratadilar. Marraga yetib borish uchun qancha vaqt kerak bo'lsa, raqibning oldingizga kelishi xavfi shunchalik yuqori bo'ladi.
O'quvchilarim mening shaxsiy vazifam haqidagi bayonotimni eslashlari mumkin, men buni har qanday IT mutaxassisiga qo'llashim mumkin deb hisoblayman:
"Vaqtingizni intellektual mulkingiz qiymatini oshiradigan xususiyatlar/funksionallikni taqdim etishga qarating. Qolgan barcha narsalar uchun ramkalar, mahsulotlar va xizmatlardan foydalaning."
— J. Vester
Ushbu maqolada biz Spring Boot RESTful API-ni amalga oshirish uchun zarur bo'lgan hamma narsani qanday bajarganini ko'rdik. ChatGPT-dan foydalanib, biz hatto xizmatimiz nima bo'lishini xohlayotganimizni inson so'zlari bilan ifodalashga muvaffaq bo'ldik va u bir necha soniya ichida biz uchun OpenAPI spetsifikatsiyasini yaratdi. Bu bizga API-First yondashuvidan foydalanish imkonini berdi. Tayyor bo'lgach, biz bir nechta CLI buyruqlarini berib, Heroku yordamida o'z fikrimizni yetkaza oldik.
Spring Boot, ChatGPT va Heroku men o'z g'oyamni amalga oshirishda lazerga e'tibor qaratishim uchun ramkalar va xizmatlarni taqdim etdi. Natijada men o‘zimning shaxsiy vazifam bayonnomasiga sodiq qoldim va eng muhimi, o‘z g‘oyamni tezda yetkaza oldim. Men qilishim kerak bo'lgan yagona narsa mening g'oyam ortidagi biznes mantig'iga e'tibor qaratish edi - va bu shunday bo'lishi kerak!
Agar siz qiziqsangiz, ushbu maqolaning manba kodini GitLab -da topishingiz mumkin.
Haqiqatan ham ajoyib kun o'tsin!