Programiranje s Java API-ima, 1. dio: OpenAPI i Swagger

Dok ste uzimali kavu, razvoj Java programa promijenio se - opet .

U svijetu koji vode brze promjene i inovacije, ironično je da se API-ji vraćaju. Kao i ekvivalent kodiranja njujorškog sustava podzemne željeznice u doba autonomnih automobila, API-ji su stara tehnologija - drevni, ali neophodni. Zanimljivo je kako se ova nevidljiva, svakodnevna IT arhitektura preispituje i koristi u trenutnim tehnološkim trendovima.

Iako su API-ji svugdje, postali su posebno istaknuti u njihovoj daljinskoj inkarnaciji kao RESTful usluge, koje su okosnica implementacije u oblaku. Usluge u oblaku javni su API-ji , koje karakteriziraju krajnje točke okrenute prema javnosti i objavljene strukture. Aplikacije zasnovane na oblaku također imaju tendenciju ka mikro uslugama , koje su neovisne, ali povezane implementacije. Svi ovi čimbenici povećavaju istaknutost API-ja.

U ovom ćete dvodijelnom vodiču naučiti kako Java API-je staviti u središte vašeg procesa dizajna i razvoja, od koncepta do kodiranja. Prvi dio započinje pregledom i uvodi vas u OpenAPI, također poznat kao Swagger. U 2. dijelu naučit ćete kako koristiti Swaggerove API definicije za razvoj Spring Web MVC aplikacije s kutnim 2 sučeljem.

Što je Java API?

API-ji su toliko uobičajeni u razvoju softvera da se ponekad pretpostavlja da programeri jednostavno znaju što su. Umjesto da se oslanjamo na osmozu, odvojimo minutu da raspakiramo što mislimo kad govorimo o API-ima.

Općenito, možemo reći da API-ji postavljaju i upravljaju granicama između sustava.

Prvo, API je skraćenica od "sučelje za programiranje aplikacija". Uloga API-ja je odrediti kako softverske komponente međusobno djeluju. Ako ste upoznati s objektno orijentiranim programiranjem, API-je u njihovoj inkarnaciji znate kao sučelja i klase korištene za dobivanje pristupa osnovnim značajkama jezika ili kao javno lice knjižnica trećih strana i mogućnosti OS-a.

Općenito, možemo reći da API-ji postavljaju i upravljaju granicama između sustava, kao što se vidi na slici 1.

Matthew Tyson

Pa gdje nas to ostavlja s razvojem vođenim API-jem?

Java API-ji za računalstvo u oblaku, mikroservise i REST

Programiranje s API-ima dolazi do izražaja s modernim web API-jem: mrežnim API-jem (NEA) , gdje je granica između sustava "preko žice". Te su granice već središnje za web aplikacije, koje su uobičajena kontaktna točka između prednjih klijenata i pozadinskih poslužitelja. Revolucija u oblaku eksponencijalno je povećala važnost Java API-ja.

Bilo koja programska aktivnost koja zahtijeva konzumiranje usluga u oblaku (koje su u osnovi javni API-ji) i dekonstruiranje sustava u manje, neovisne, ali povezane implementacije (poznate i kao mikroservisi), u velikoj se mjeri oslanja na API-je. Mrežno izloženi API-ji jednostavno su univerzalniji, lakše se dobivaju i lakše se mijenjaju i proširuju od tradicionalnih API-ja. Trenutni arhitektonski trend je iskorištavanje ovih značajki.

Mikroservisi i javni API-ji nastali su iz korijena uslužno orijentirane arhitekture (SOA) i softvera kao usluge (SaaS). Iako je SOA trend već dugi niz godina, široko prihvaćanje ometeno je složenošću i režijom SOA-e. Industrija se odlučila za RESTful API-je kao de facto standard, pružajući taman dovoljno strukture i konvencija s više stvarne fleksibilnosti. S REST-om kao pozadinom možemo stvoriti formalne API definicije koje zadržavaju ljudsku čitljivost. Programeri stvaraju alat oko tih definicija.

Općenito, REST je konvencija za mapiranje resursa na HTTP staze i njihove povezane radnje. Vjerojatno ste ih vidjeli kao HTTP GET i POST metode. Ključno je koristiti sam HTTP kao standard, a povrh toga slojiti konvencionalna mapiranja radi predvidljivosti.

Korištenje Java API-ja u dizajnu

Možete vidjeti važnost API-ja, ali kako biste ih koristili u svoju korist?

Korištenje definicija Java API-ja za pokretanje procesa dizajna i razvoja učinkovit je način za strukturiranje vašeg razmišljanja o IT sustavima. Korištenjem definicija Java API-a od samih početaka životnog ciklusa razvoja softvera (prikupljanje koncepata i zahtjeva) stvorit ćete vrijedan tehnički artefakt koji je koristan sve do implementacije, kao i za trajno održavanje.

Razmotrimo kako definicije Java API-ja premošćuju konceptualne i implementacijske faze razvoja.

Opisni i preskriptivni API-ji

Korisno je napraviti razliku između opisnih API-ja i propisanih API-ja. Opisni API opisuje način na koji se kod stvarnim funkcijama, dok je propisan API opisuje kako kod bi trebao funkcionirati.

Oba su ova stila korisna, a oba su uvelike poboljšana korištenjem strukturiranog standardnog formata za definiciju API-ja. U pravilu je korištenje API-ja za pogon stvaranja koda propisana upotreba, dok je korištenje koda za izlaz Java API definicije opisna upotreba.

Prikupljanje zahtjeva s Java API-ima

Na spektru konceptualne do provedbe, prikupljanje zahtjeva je daleko na koncepcijskoj strani. Ali čak i u konceptualnoj fazi razvoja aplikacije, možemo početi razmišljati u smislu API-ja.

Recimo da se vaš dizajnirani sustav bavi brdskim biciklima - konstrukcijom, dijelovima i slično. Kao objektno orijentirani programer započeli biste razgovorom sa dionicima o zahtjevima. Prilično brzo nakon toga razmišljali biste o apstraktnom BikePartpredavanju.

Zatim biste razmislili kroz web aplikaciju koja bi upravljala različitim objektima dijelova bicikla. Uskoro biste došli do zajedničkih zahtjeva za upravljanje tim dijelovima bicikla. Evo kratkog pregleda faze zahtjeva dokumentacije za aplikaciju dijelova bicikla:

  • Aplikacija mora biti u stanju stvoriti vrstu dijela za bicikl (mjenjač brzina, kočnica itd.).
  • Ovlašteni korisnik mora biti u mogućnosti popisati, stvoriti i učiniti tip dijela aktivnim.
  • Neovlašteni korisnik mora imati mogućnost popisa aktivnih vrsta dijelova i pregledavanja popisa pojedinačnih primjeraka dijela dijela u sustavu.

Već vidite obrise usluga koji se oblikuju. Imajući na umu eventualne API-je, možete početi skicirati te usluge. Kao primjer, evo djelomičnog popisa RESTful CRUD usluga za vrste dijelova bicikla:

  • Izradite vrstu dijela za bicikl: PUT /part-type/
  • Ažuriranje vrste dijela bicikla: POST /part-type/
  • Popis vrsta dijelova: GET /part-type/
  • Doznajte detalje o tipu dijela: GET /part-type/:id

Primijetite kako CRUD usluge počinju nagovještavati oblik različitih granica usluga. Ako gradite u stilu mikro usluga, iz dizajna već možete vidjeti tri mikro usluge:

  • Usluga dijelova za bicikl
  • Usluga biciklističkog dijela
  • Usluga provjere autentičnosti / autorizacije

Because I think of APIs as boundaries of related entities, I consider the microservices from this list to be API surfaces. Together, they offer a big-picture view of the application architecture. Details of the services themselves are also described in a fashion that you will use for the technical specification, which is the next phase of the software development lifecycle.

Technical specification with Java APIs

If you've included the API focus as part of requirements gathering, then you already have a good framework for technical specification. The next stage is selecting the technology stack you will use to implement the specification.

With so much focus on building RESTful APIs, developers have an embarrassment of riches when it comes to implementation. Regardless of the stack you choose, fleshing out the API even further at this stage will increase your understanding of the app's architectural needs. Options might include a VM (virtual machine) to host the application, a database capable of managing the volume and type of data you're serving, and a cloud platform in the case of IaaS or PaaS deployment.

You can use the API to drive "downward" toward schemas (or document structures n NoSQL), or "upward" toward UI elements. As you develop the API specification, you will likely notice an interplay between these concerns. This is all good and part of the process. The API becomes a central, living place to capture these changes.

Another concern to keep in mind is which public APIs your system will expose. Give extra thought and care to these. Along with assisting in the development effort, public APIs serve as the published contract that external systems use to interface with yours.

Public cloud APIs

In general, APIs define the contract of a software system, providing a known and stable interface against which to program other systems. Specifically, a public cloud API is a public contract with other organizations and programmers building systems. Examples are the GitHub and Facebook APIs.

Documenting the Java API

At this stage, you will want to start capturing your APIs in formal syntax. I've listed a few prominent API standards in Table 1.

Comparing API formats

 
Name Summary Stars on GitHub URL
OpenAPI JSON and YML Supported API Standard descended from the Swagger project, includes variety of tools in the Swagger ecosystem. ~6,500 //github.com/OAI/OpenAPI-Specification
RAML YML based spec supported mainly by MuleSoft ~3,000 //github.com/raml-org/raml-spec
API BluePrint An API design language using MarkDown-like syntax ~5,500 //github.com/apiaryio/api-blueprint/

Virtually any format you choose for documenting your API should be okay. Just look for a format that is structured, has a formal spec and good tooling around it, and looks like it will be actively maintained long term. Both RAML and OpenAPI fit that bill. Another neat project is API Blueprint, which uses markdown syntax. For examples in this article we're going to use OpenAPI and Swagger.

OpenAPI and Swagger

OpenAPI is a JSON format for describing REST-based APIs. Swagger started as OpenAPI, but has evolved into a set of tools around the OpenAPI format. The two technologies complement each other well.

Introducing OpenAPI

OpenAPI is currently the most common choice for creating RESTful definitions. A compelling alternative is RAML (RESTful API Markup Language), which is based on YAML. Personally, I've found the tooling in Swagger (especially the visual designer) more polished and error-free than in RAML.

OpenAPI uses JSON syntax, which is familiar to most developers. If you'd rather not strain your eyes parsing JSON, there are UIs to make working with it easier. Part 2 introduces UIs for RESTful definitions.

Listing 1 is a sample of OpenAPI's JSON syntax.

Listing 1. OpenAPI definition for a simple BikePart

 "paths": { "/part-type": { "get": { "description": "Gets all the part-types available in the system", "operationId": "getPartTypes", "produces": [ "application/json" ], "responses": { "200": { "description": "Gets the BikeParts", "schema": { "type": "array", "items": { "$ref": "#/definitions/BikePart" } } } } } } } 

This definition is so concise it is practically Spartan, which is fine for now. There's plenty of room to increase the detail and complexity of the API definition going forward. I'll show you a more detailed iteration of this definition shortly.

Coding from the Java API

Requirements gathering is done and the basic app has been spec'd out, which means you're ready for the fun part---coding! Having a formal Java API definition gives you some distinct advantages. For one thing, you know what endpoints the back-end and front-end developers need to create and code against, respectively. Even if you are a team of one, you'll quickly see the value of an API-driven approach when you begin coding.

Dok izrađujete aplikaciju, vidjet ćete i vrijednost upotrebe API-ja za bilježenje pregovora između razvoja i poslovanja. Korištenje API alata ubrzat će primjenu i dokumentiranje promjena koda.

Granularnije specifikacije i stvarno kodiranje mogu zahtijevati više detalja od kratke definicije iz popisa 1. Uz to, veći i složeniji sustavi mogu zaslužiti mogućnosti koje će se skalirati, poput referenci na dokumente. Popis 2 prikazuje detaljniji primjer BikePart API-ja.

Popis 2. Dodavanje detalja u definiciju BikePart API-ja

 "paths": { "/part-type": { "get": { "description": "Gets all the part-types available in the system", "operationId": "getPartTypes", "produces": [ "application/json" ], "parameters": [ { "name": "limit", "in": "query", "description": "maximum number of results to return", "required": false, "type": "integer", "format": "int32" } ], "responses": { "200": { "description": "part-type listing", "schema": { "type": "array", "items": { "$ref": "#/definitions/PartType" } } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/Error" } } } }