Programowanie za pomocą Java API, część 1: OpenAPI i Swagger

Podczas gdy ty dostawałeś kawę, rozwój aplikacji Java się zmienił - znowu .

W świecie napędzanym szybkimi zmianami i innowacjami to ironia losu, że API powracają. Podobnie jak ekwiwalent kodowania systemu metra w Nowym Jorku w dobie samochodów autonomicznych, interfejsy API są starą technologią - starożytną, ale niezbędną. Co ciekawe, ta niewidoczna, codzienna architektura IT jest przeobrażana i wykorzystywana w obecnych trendach technologicznych.

Chociaż interfejsy API są wszędzie, stały się szczególnie widoczne w swoim zdalnym wcieleniu jako usługi RESTful, które są podstawą wdrożeń w chmurze. Usługi w chmurze to publiczne interfejsy API , które charakteryzują publiczne punkty końcowe i opublikowane struktury. Aplikacje oparte na chmurze również zmierzają w kierunku mikrousług , które są niezależnymi, ale powiązanymi wdrożeniami. Wszystkie te czynniki zwiększają znaczenie interfejsów API.

Z tego dwuczęściowego samouczka dowiesz się, jak umieścić interfejsy API języka Java w sercu procesu projektowania i rozwoju, od koncepcji po kodowanie. Część 1 rozpoczyna się od omówienia i wprowadza do OpenAPI, znanego również jako Swagger. W części 2 dowiesz się, jak używać definicji interfejsu API Swaggera do tworzenia aplikacji Spring Web MVC z interfejsem Angular 2.

Co to jest Java API?

Interfejsy API są tak powszechne w tworzeniu oprogramowania, że ​​czasami zakłada się, że programiści po prostu wiedzą, czym one są. Zamiast polegać na osmozie, poświęćmy chwilę, aby rozpakować, co mamy na myśli, gdy mówimy o API.

Ogólnie można powiedzieć, że interfejsy API wyznaczają granice między systemami i zarządzają nimi.

Po pierwsze, API oznacza „interfejs programowania aplikacji”. Rolą interfejsu API jest określenie sposobu interakcji składników oprogramowania. Jeśli znasz programowanie obiektowe, znasz interfejsy API w ich wcieleniu jako interfejsy i klasy używane do uzyskiwania dostępu do podstawowych funkcji języka lub jako publiczne oblicze bibliotek innych firm i możliwości systemu operacyjnego.

Ogólnie możemy powiedzieć, że interfejsy API wyznaczają granice między systemami i zarządzają nimi, jak pokazano na rysunku 1.

Matthew Tyson

Więc gdzie to prowadzi nas do rozwoju opartego na API?

Interfejsy API języka Java do przetwarzania w chmurze, mikrousług i REST

Programowanie za pomocą interfejsów API wysuwa się na pierwszy plan dzięki nowoczesnemu interfejsowi API sieciowemu: interfejsowi API eksponowanemu w sieci (NEA) , w którym granica między systemami przebiega „przez sieć ”. Te granice są już kluczowe dla aplikacji internetowych, które są wspólnym punktem kontaktu między klientami frontonu a serwerami zaplecza. Rewolucja w chmurze gwałtownie zwiększyła znaczenie interfejsów API języka Java.

Wszelkie działania programistyczne, które wymagają korzystania z usług w chmurze (które są w zasadzie publicznymi interfejsami API) i dekonstruowania systemów na mniejsze, niezależne, ale powiązane wdrożenia (znane również jako mikrousługi), w dużym stopniu polegają na interfejsach API. Interfejsy API dostępne w sieci są po prostu bardziej uniwersalne, łatwiejsze do uzyskania i łatwiejsze do modyfikowania i rozszerzania niż tradycyjne interfejsy API. Obecny trend architektoniczny polega na wykorzystaniu tych cech.

Mikrousługi i publiczne interfejsy API wyrosły z korzeni architektury zorientowanej na usługi (SOA) i oprogramowania jako usługi (SaaS). Chociaż architektura SOA była trendem od wielu lat, jej powszechne przyjęcie zostało utrudnione z powodu złożoności i narzutu SOA. Branża zdecydowała się na RESTful API jako de facto standard, zapewniając wystarczającą strukturę i konwencję z większą elastycznością w świecie rzeczywistym. Z REST jako tłem możemy tworzyć formalne definicje API, które zachowują czytelność dla ludzi. Programiści tworzą narzędzia wokół tych definicji.

Ogólnie rzecz biorąc, REST to konwencja mapowania zasobów na ścieżki HTTP i powiązane z nimi akcje. Prawdopodobnie widziałeś je jako metody HTTP GET i POST. Kluczowe jest użycie samego protokołu HTTP jako standardu i nałożenie na niego konwencjonalnych mapowań w celu zapewnienia przewidywalności.

Wykorzystanie API Java w projektowaniu

Widzisz znaczenie interfejsów API, ale w jaki sposób wykorzystasz je na swoją korzyść?

Używanie definicji Java API do kierowania procesem projektowania i rozwoju to skuteczny sposób na uporządkowanie myślenia o systemach IT. Korzystając z definicji Java API od samego początku cyklu rozwoju oprogramowania (zbieranie koncepcji i wymagań), utworzysz cenny artefakt techniczny, który będzie przydatny aż do wdrożenia, a także do bieżącej konserwacji.

Zastanówmy się, jak definicje Java API łączą koncepcyjne i implementacyjne etapy rozwoju.

Opisowe a nakazowe interfejsy API

Warto rozróżnić opisowe i nakazowe interfejsy API. Opisowe API opisuje sposób, w jaki kod faktycznie funkcje, natomiast nakazowy API opisuje jak kod powinien działać.

Oba te style są przydatne i oba są znacznie ulepszone dzięki zastosowaniu ustrukturyzowanego, standardowego formatu definicji interfejsu API. Z reguły używanie interfejsu API do kierowania tworzeniem kodu jest użyciem opisowym, podczas gdy użycie kodu do wyprowadzania definicji interfejsu API języka Java jest użyciem opisowym.

Gromadzenie wymagań za pomocą Java API

W spektrum od konceptu do implementacji gromadzenie wymagań jest daleko idące od strony koncepcji. Ale nawet na etapie koncepcyjnym tworzenia aplikacji możemy zacząć myśleć w kategoriach API.

Załóżmy, że projektowany system ma do czynienia z rowerami górskimi - konstrukcją, częściami i tak dalej. Jako programista zorientowany obiektowo możesz zacząć od rozmowy z interesariuszami na temat wymagań. Po tym dość szybko pomyślałbyś o BikePartklasie abstrakcyjnej .

Następnie należy przemyśleć aplikację internetową, która zarządzałaby różnymi obiektami części rowerowych. Wkrótce pojawią się wspólne wymagania dotyczące zarządzania tymi częściami rowerowymi. Oto migawka etapu dokumentacji wymagań dla aplikacji części rowerowych:

  • Aplikacja musi mieć możliwość utworzenia części rowerowej (dźwignia zmiany biegów, hamulec itp.).
  • Autoryzowany użytkownik musi mieć możliwość wyświetlania, tworzenia i uaktywniania typu części.
  • Nieautoryzowany użytkownik musi być w stanie wyświetlić listę aktywnych typów części i przeglądać listy poszczególnych wystąpień typów części w systemie.

Już widać, jak kształtują się zarysy usług. Mając na uwadze ewentualne interfejsy API, możesz rozpocząć szkicowanie tych usług. Jako przykład, oto częściowa lista usług RESTful CRUD dla typów części rowerowych:

  • Utwórz typ części rowerowej: PUT /part-type/
  • Zaktualizuj typ części rowerowej: POST /part-type/
  • Lista typów części: GET /part-type/
  • Uzyskaj szczegółowe informacje o typie części: GET /part-type/:id

Zwróć uwagę, jak usługi CRUD zaczynają wskazywać kształt różnych granic usług. Jeśli tworzysz w stylu mikrousług, możesz już zobaczyć trzy mikrousługi wyłaniające się z projektu:

  • Usługa części rowerowej
  • Usługa typu część rowerowa
  • Usługa uwierzytelniania / autoryzacji

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.

Podczas tworzenia aplikacji zobaczysz także wartość używania interfejsów API do rejestrowania wzajemnych negocjacji między programowaniem a biznesem. Korzystanie z narzędzi API przyspieszy zarówno stosowanie, jak i dokumentowanie zmian w kodzie.

Bardziej szczegółowe specyfikacje i faktyczne kodowanie mogą wymagać większej szczegółowości niż zwięzła definicja na liście 1. Ponadto większe i bardziej złożone systemy mogą wymagać skalowalnych możliwości, takich jak odwołania do dokumentów. Listing 2 przedstawia bardziej rozbudowany przykład interfejsu API BikePart.

Listing 2. Dodanie szczegółu do definicji BikePart API

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