paint-brush
Jak rychle zavést nové API pomocí Spring Boot a Gradlepodle@johnjvester
Nová historie

Jak rychle zavést nové API pomocí Spring Boot a Gradle

podle John Vester14m2025/03/24
Read on Terminal Reader

Příliš dlouho; Číst

Čas uvedení na trh může vytvořit nebo zlomit jakýkoli nápad nebo řešení. Podívejte se, jak rychle lze RESTful API vytvořit pomocí ChatGPT, Spring Boot, Gradle a Heroku.
featured image - Jak rychle zavést nové API pomocí Spring Boot a Gradle
John Vester HackerNoon profile picture
0-item
1-item
2-item


Posledních pět let jsem měl na zdi své kanceláře citát „všechno začíná nápadem“.


Moje žena našla tento produkt na Etsy krátce poté, co jsem začal vyvíjet kolekci API pro fitness aplikaci. Miluji toto prohlášení, protože zachycuje vášeň, která mě pohlcuje během fází tvorby nového projektu. I po třech desetiletích mé kariéry je to stále můj oblíbený aspekt práce inženýra.


Během této doby jsem se naučil, že na nápadu záleží pouze tehdy, má-li někdo možnost ho zažít. Pokud nápadu trvá příliš dlouho, než se stane skutečností, skončíte s promarněnou příležitostí, protože vás někdo jiný porazí. To je důvod, proč se startupy vždy předhánějí, aby dostaly své nápady na trh co nejrychleji.


Pojďme si projít, jak můžeme udělat nápad ve skutečnost... rychle.

Předpoklady

V tomto článku budeme mít věci jednoduché. K vytvoření RESTful API použijeme Java 17 a Spring Boot 3. V tomto příkladu použijeme Gradle pro naši automatizaci sestavování.


Zatímco myšlenka služby, kterou plánujeme uvést na trh, by normálně používala vrstvu persistence, necháme ji stranou pro tento příklad a staticky definujeme naše data v rámci třídy úložiště.


Nebudeme si dělat starosti s přidáním jakéhokoli zabezpečení pro tento příklad, jednoduše povolíme anonymní přístup pro tento důkaz konceptu.

Motivační citace API

Předpokládejme, že naším nápadem je API motivačních nabídek. Abych se ujistil, že závodíme co nejrychleji, požádal jsem ChatGPT, aby pro mě vytvořil specifikaci OpenAPI.


ChatGPT během několika sekund poskytl odpověď:


Zde je specifikace OpenAPI v YAML, kterou ChatGPT vygeneroval:


 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


Potřeboval jsem provést pouze jednu ruční aktualizaci – ujistit se, že pro schéma Quote jsou vyžadovány vlastnosti id a quote . A to jen proto, že jsem zapomněl zmínit toto omezení pro ChatGPT ve své původní výzvě.

Díky tomu jsme připraveni vyvinout novou službu pomocí přístupu API-First .

Vytváření Spring Boot Service pomocí API-First

V tomto příkladu použiji Spring Boot CLI k vytvoření nového projektu. Zde je návod, jak nainstalovat CLI pomocí Homebrew:


 $ brew tap spring-io/tap $ brew install spring-boot

Vytvořte novou službu Spring Boot Service

Projekt nazveme quotes , vytvoříme jej pomocí následujícího příkazu:


 $ spring init --dependencies=web quotes


Podívejme se na obsah složky s quotes :


 $ 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


Dále upravíme soubor build.gradle , jak je ukázáno níže, abychom přijali přístup API-First.


 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() }


Nakonec umístíme vygenerovanou specifikaci OpenAPI do složky resources/static jako openapi.yaml .

Vygenerujte objekty API a Model

Po otevření projektu v IntelliJ jsem provedl následující příkaz k vytvoření pahýlů API a modelových objektů.


 ./gradlew clean build


Nyní můžeme vidět objekty api a model vytvořené z naší specifikace OpenAPI. Zde je soubor QuotesAPI.java :


Přidejte obchodní logiku

Když je základní služba připravena a již dodržuje naši smlouvu OpenAPI, začneme do služby přidávat určitou obchodní logiku.


Nejprve vytvoříme třídu QuotesRepository , která vrací data pro naši službu. Jak bylo uvedeno výše, normálně by to bylo uloženo v nějaké vyhrazené perzistentní vrstvě. V tomto příkladu napevno zakódování dat v hodnotě pěti uvozovek funguje dobře a udržuje nás to soustředěné.


 @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)); } }


Dále vytvoříme QuotesService , která bude interagovat s QuotesRepository . Tento přístup udrží data oddělená od obchodní logiky.


 @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())); } }


Nakonec musíme implementovat QuotesApi generované z našeho přístupu API-First:


 @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); } }


V tuto chvíli máme plně funkční API motivačních nabídek, doplněné malou sbírkou odpovědí.

Některé položky na závěr

Spring Boot nám dává možnost webového uživatelského rozhraní Swagger Docs prostřednictvím závislosti springdoc-openapi-starter-webmvc-ui .


 dependencies { ... implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.5' ... }


Zatímco framework umožňuje inženýrům používat jednoduché anotace k popisu jejich API, můžeme použít náš stávající soubor openapi.yaml ve složce resources/static .


Tento přístup můžeme implementovat v souboru application-properties.yaml spolu s několika dalšími drobnými aktualizacemi konfigurace:


 server: port: ${PORT:8080} spring: application: name: quotes springdoc: swagger-ui: path: /swagger-docs url: openapi.yaml


Jen pro zajímavost přidáme soubor banner.txt pro použití při spuštění služby. Tento soubor umístíme do složky resources .


 ${AnsiColor.BLUE} _ __ _ _ _ ___ | |_ ___ ___ / _` | | | |/ _ \| __/ _ \/ __| | (_| | |_| | (_) | || __/\__ \ \__, |\__,_|\___/ \__\___||___/ |_| ${AnsiColor.DEFAULT} :: Running Spring Boot ${AnsiColor.BLUE}${spring-boot.version}${AnsiColor.DEFAULT} :: Port #${AnsiColor.BLUE}${server.port}${AnsiColor.DEFAULT} ::


Nyní, když spustíme službu lokálně, můžeme vidět banner:


Po spuštění můžeme ověřit, že Swagger Docs fungují, návštěvou koncového bodu /swagger-docs .



Nakonec vytvoříme nové úložiště založené na Git, abychom mohli sledovat jakékoli budoucí změny:


 $ git init $ git add . $ git commit -m "Initial commit for the Motivational Quotes API"


Nyní se podívejme, jak rychle můžeme naši službu nasadit .

Použití Heroku k dokončení cesty

Doposud bylo primárním cílem při představení mého nového nápadu vytvořit specifikaci OpenAPI a napsat nějakou obchodní logiku pro mou službu. Všechno ostatní za mě zvládl Spring Boot.


Pokud jde o provozování mé služby, raději používám Heroku, protože se skvěle hodí pro služby Spring Boot. Své služby mohu nasadit rychle, aniž bych se dostal do problémů s cloudovou infrastrukturou. Heroku také usnadňuje předávání konfiguračních hodnot pro mé aplikace založené na Java .


Abychom odpovídali verzi Java, kterou používáme, vytvoříme soubor system.properties v kořenové složce projektu. Soubor má jeden řádek:


 java.runtime.version = 17


Poté vytvořím Procfile ve stejném umístění pro přizpůsobení chování nasazení. Tento soubor má také jeden řádek:


 web: java -jar build/libs/quotes-0.0.1-SNAPSHOT.jar


Je čas nasadit. S Heroku CLI mohu službu nasadit pomocí několika jednoduchých příkazů. Nejprve ověřím CLI a poté vytvořím novou aplikaci Heroku.


 $ 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


Moje instance aplikace Heroku se jmenuje vast-crag-43256 (mohl jsem předat zadaný název) a služba poběží na https://vast-crag-43256-bb5e35ea87de.herokuapp.com/.


Poslední věcí, kterou musíte udělat, je nasadit službu pomocí příkazu Git k odeslání kódu do Heroku:


 $ git push heroku master


Po dokončení tohoto příkazu můžeme ověřit úspěšné nasazení prostřednictvím řídicího panelu Heroku:


Nyní jsme připraveni vzít naši novou službu na testovací jízdu!

Motivační citáty v akci

Se službou Motivational Quotes spuštěnou na Heroku můžeme pomocí řady příkazů curl ověřit, zda vše funguje podle očekávání.


Nejprve si ukažme kompletní seznam všech pěti motivačních citátů:


 $ 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." } ]


Pojďme získat jeden motivační citát podle ID:


 $ 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." }


Pojďme si dát náhodný motivační citát:


 $ 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." }


Můžeme dokonce procházet i Swagger Docs.


Závěr

Čas uvedení na trh může vytvořit nebo rozbít jakýkoli nápad. To je důvod, proč se startupy laserově zaměřují na co nejrychlejší dodání svých inovací. Čím déle trvá dojetí do cíle, tím větší je riziko, že závodník dorazí před vámi.


Moji čtenáři si možná vzpomenou na mé osobní prohlášení o poslání, které se podle mého názoru může vztahovat na každého IT profesionála:


"Zaměřte svůj čas na poskytování funkcí/funkcí, které rozšiřují hodnotu vašeho duševního vlastnictví. Využijte rámce, produkty a služby pro vše ostatní."

— J. Vester


V tomto článku jsme viděli, jak Spring Boot zvládl vše potřebné k implementaci RESTful API. S využitím ChatGPT jsme dokonce byli schopni vyjádřit lidskými slovy, co jsme chtěli, aby naše služba byla, a během několika sekund pro nás vytvořil specifikaci OpenAPI. To nám umožnilo využít přístup API-First. Jakmile jsme byli připraveni, byli jsme schopni doručit náš nápad pomocí Heroku vydáním několika příkazů CLI.

Spring Boot, ChatGPT a Heroku poskytly rámce a služby, takže jsem mohl zůstat laserově zaměřený na realizaci svého nápadu. Díky tomu jsem se mohl držet svého osobního poslání, a co je důležitější, rychle realizovat svůj nápad. Jediné, co jsem musel udělat, bylo zaměřit se na obchodní logiku za mým nápadem – a tak to má být!


Pokud máte zájem, zdrojový kód tohoto článku najdete na GitLabu .


Mějte opravdu skvělý den!

L O A D I N G
. . . comments & more!

About Author

John Vester HackerNoon profile picture
John Vester@johnjvester
Information Technology professional with 25+ years expertise in application design and architecture.

ZAVĚŠIT ZNAČKY

TENTO ČLÁNEK BYL PŘEDSTAVEN V...