372 aflæsninger
372 aflæsninger

Sådan introduceres en ny API hurtigt ved hjælp af Spring Boot og Gradle

ved John Vester14m2025/03/24
Read on Terminal Reader

For langt; At læse

Time to market kan skabe eller ødelægge enhver idé eller løsning. Se, hvor hurtigt en RESTful API kan oprettes ved at udnytte ChatGPT, Spring Boot, Gradle og Heroku.
featured image - Sådan introduceres en ny API hurtigt ved hjælp af Spring Boot og Gradle
John Vester HackerNoon profile picture
0-item
1-item
2-item


I de sidste fem år har jeg haft citatet "alt begynder med en idé" på væggen på mit kontor.


Min kone fandt dette produkt på Etsy kort efter, at jeg begyndte at udvikle en API-kollektion til en fitnessapplikation. Jeg elsker dette udsagn, fordi det fanger den passion, der fortærer mig under oprettelsesstadierne af et nyt projekt. Dette er stadig mit yndlingsaspekt ved at være ingeniør, selv tre årtier inde i min karriere.


Det, jeg har lært i løbet af denne tid, er, at en idé kun betyder noget, hvis nogen har mulighed for at opleve den. Hvis en idé tager for lang tid om at blive til virkelighed, ender du med en forpasset chance, da en anden slår dig til bunds. Det er grunden til, at startups altid ræser for at få deres ideer på markedet så hurtigt som muligt.


Lad os gennemgå, hvordan vi kan gøre en idé til virkelighed … hurtigt.

Forudsætninger

Til denne artikel vil vi holde tingene enkle. Vi bruger Java 17 og Spring Boot 3 til at skabe en RESTful API. I dette eksempel vil vi bruge Gradle til vores byggeautomatisering.


Mens den serviceidé, vi planlægger at bringe på markedet, normalt ville bruge et persistenslag, sætter vi det til side for dette eksempel og statisk definerer vores data inden for en lagerklasse.


Vi vil ikke bekymre os om at tilføje nogen sikkerhed til dette eksempel, blot at tillade anonym adgang til dette proof of concept.

Motivational Quotes API

Lad os antage, at vores idé er en motiverende citat API. For at sikre, at vi kører så hurtigt som muligt, bad jeg ChatGPT om at oprette en OpenAPI-specifikation til mig.


Inden for sekunder gav ChatGPT svaret:


Her er OpenAPI-specifikationen, i YAML, som ChatGPT genererede:


 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


Jeg behøvede kun at lave én manuel opdatering - at sikre mig, at egenskaberne for id og quote var påkrævet til Quote . Og det er kun fordi jeg glemte at nævne denne begrænsning til ChatGPT i min oprindelige prompt.

Med det er vi klar til at udvikle den nye service ved hjælp af en API-First tilgang.

Opbygning af Spring Boot Service ved hjælp af API-First

Til dette eksempel vil jeg bruge Spring Boot CLI til at oprette et nyt projekt. Sådan kan du installere CLI ved hjælp af Homebrew:


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

Opret en ny Spring Boot Service

Vi kalder quotes og opretter det med følgende kommando:


 $ spring init --dependencies=web quotes


Lad os undersøge indholdet af 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


Dernæst redigerer vi build.gradle filen som vist nedenfor for at anvende API-First-tilgangen.


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


Til sidst placerer vi den genererede OpenAPI-specifikation i mappen resources/static som openapi.yaml .

Generer API- og Model-objekterne

Efter at have åbnet projektet i IntelliJ, udførte jeg følgende kommando for at bygge API-stubbe og modelobjekter.


 ./gradlew clean build


Nu kan vi se api og model oprettet ud fra vores OpenAPI-specifikation. Her er filen QuotesAPI.java :


Tilføj forretningslogikken

Med basistjenesten klar og allerede overholder vores OpenAPI-kontrakt, begynder vi at tilføje noget forretningslogik til tjenesten.


Først opretter vi en QuotesRepository -klasse, som returnerer dataene til vores tjeneste. Som nævnt ovenfor vil dette normalt blive lagret i et eller andet dedikeret persistenslag. I dette eksempel fungerer hårdkodning af data for fem anførselstegn fint, og det holder os fokuserede.


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


Dernæst opretter vi en QuotesService , som vil interagere med QuotesRepository . Denne tilgang vil holde dataene adskilt fra forretningslogikken.


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


Til sidst skal vi bare implementere QuotesApi genereret fra vores API-First tilgang:


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


På dette tidspunkt har vi en fuldt funktionel Motivational Quotes API, komplet med en lille samling af svar.

Nogle sidste ting

Spring Boot giver os mulighed for en webbaseret Swagger Docs-brugergrænseflade via springdoc-openapi-starter-webmvc-ui afhængigheden.


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


Selvom rammeværket tillader ingeniører at bruge simple annoteringer til at beskrive deres API, kan vi bruge vores eksisterende openapi.yaml -fil i mappen resources/static .


Vi kan implementere denne tilgang i filen application-properties.yaml sammen med et par andre mindre konfigurationsopdateringer:


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


Bare for sjov, lad os tilføje en banner.txt -fil til brug, når tjenesten starter. Vi placerer denne fil i resources .


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


Nu, når vi starter tjenesten lokalt, kan vi se banneret:


Når vi først er startet, kan vi validere, at Swagger Docs fungerer ved at besøge /swagger-docs slutpunktet.



Endelig opretter vi et nyt Git-baseret lager, så vi kan spore eventuelle fremtidige ændringer:


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


Lad os nu se, hvor hurtigt vi kan implementere vores service .

Brug af Heroku til at afslutte rejsen

Indtil videre har det primære fokus for at introducere min nye idé været at skabe en OpenAPI-specifikation og skrive noget forretningslogik til min service. Spring Boot klarede alt andet for mig.


Når det kommer til at køre min tjeneste, foretrækker jeg at bruge Heroku, fordi det passer godt til Spring Boot-tjenester. Jeg kan implementere mine tjenester hurtigt uden at blive hængende med cloud-infrastrukturproblemer. Heroku gør det også nemt at sende konfigurationsværdier til mine Java-baserede applikationer .


For at matche den Java-version, vi bruger, opretter vi en system.properties -fil i projektets rodmapp. Filen har én linje:


 java.runtime.version = 17


Derefter opretter jeg en Procfile på samme sted for at tilpasse implementeringsadfærden. Denne fil har også en linje:


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


Det er tid til at implementere. Med Heroku CLI kan jeg implementere tjenesten ved hjælp af et par enkle kommandoer. Først godkender jeg CLI og opretter derefter en ny Heroku-app.


 $ 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


Min Heroku app-instans hedder vast-crag-43256 (jeg kunne have bestået i et specificeret navn), og tjenesten kører på https://vast-crag-43256-bb5e35ea87de.herokuapp.com/.


Den sidste ting at gøre er at implementere tjenesten ved at bruge en Git-kommando til at skubbe koden til Heroku:


 $ git push heroku master


Når denne kommando er fuldført, kan vi validere en vellykket implementering via Heroku-dashboardet:


Nu er vi klar til at prøve vores nye service!

Motiverende citater i aktion

Med Motivational Quotes-tjenesten, der kører på Heroku, kan vi validere, at alt fungerer som forventet ved hjælp af en række curl .


Lad os først få en komplet liste over alle fem motiverende citater:


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


Lad os hente et enkelt motiverende citat efter 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." }


Lad os få et tilfældigt motiverende citat:


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


Vi kan endda gennemse Swagger Docs også.


Konklusion

Time to market kan skabe eller ødelægge enhver idé. Det er grunden til, at startups er laser-fokuserede på at levere deres innovationer så hurtigt som muligt. Jo længere tid det tager at komme i mål, jo større er risikoen for, at en konkurrent kommer før dig.


Mine læsere kan huske min personlige missionserklæring, som jeg føler kan anvende på enhver it-professionel:


"Fokuser din tid på at levere funktioner/funktionalitet, der udvider værdien af din intellektuelle ejendom. Udnyt rammer, produkter og tjenester til alt andet."

— J. Vester


I denne artikel så vi, hvordan Spring Boot håndterede alt det nødvendige for at implementere en RESTful API. Ved at udnytte ChatGPT var vi endda i stand til at udtrykke med menneskelige ord, hvad vi ønskede, at vores service skulle være, og det skabte en OpenAPI-specifikation for os i løbet af få sekunder. Dette gjorde det muligt for os at udnytte en API-First-tilgang. Når vi var klar, var vi i stand til at levere vores idé ved hjælp af Heroku ved at udstede et par CLI-kommandoer.

Spring Boot, ChatGPT og Heroku leverede rammerne og tjenesterne, så jeg kunne forblive laserfokuseret på at realisere min idé. Som et resultat var jeg i stand til at overholde min personlige missionserklæring og, endnu vigtigere, levere min idé hurtigt. Det eneste, jeg skulle gøre, var at fokusere på forretningslogikken bag min idé – og sådan burde det være!


Hvis du er interesseret, kan kildekoden til denne artikel findes på GitLab .


Hav en rigtig god dag!

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks