Programmazione con API Java, parte 1: OpenAPI e Swagger

Mentre stavi prendendo il caffè, lo sviluppo di applicazioni Java è cambiato ... di nuovo .

In un mondo guidato da rapidi cambiamenti e innovazioni, è ironico che le API stiano tornando. Come l'equivalente di codifica della metropolitana di New York nell'era delle auto a guida autonoma, le API sono una vecchia tecnologia, antica ma indispensabile. Ciò che è interessante è il modo in cui questa invisibile architettura IT quotidiana viene rivisitata e utilizzata nelle attuali tendenze tecnologiche.

Sebbene le API siano ovunque, sono diventate particolarmente importanti nella loro incarnazione remota come servizi RESTful, che sono la spina dorsale delle distribuzioni cloud. I servizi cloud sono API pubbliche , caratterizzate da endpoint rivolti al pubblico e strutture pubblicate. Anche le app basate su cloud tendono verso i microservizi , che sono distribuzioni indipendenti ma correlate. Tutti questi fattori aumentano l'importanza delle API.

In questo tutorial in due parti imparerai come mettere le API Java al centro del tuo processo di progettazione e sviluppo, dal concetto alla codifica. La parte 1 inizia con una panoramica e ti introduce a OpenAPI, noto anche come Swagger. Nella parte 2, imparerai come utilizzare le definizioni API di Swagger per sviluppare un'app Spring Web MVC con un frontend Angular 2.

Cos'è un'API Java?

Le API sono così comuni nello sviluppo del software che a volte si presume che i programmatori sappiano semplicemente cosa sono. Piuttosto che fare affidamento sull'osmosi, prendiamoci un minuto per scompattare cosa intendiamo quando parliamo di API.

In generale, possiamo dire che le API impostano e gestiscono i confini tra i sistemi.

Innanzitutto, API sta per "interfaccia di programmazione dell'applicazione". Il ruolo di un'API è specificare come interagiscono i componenti software. Se hai familiarità con la programmazione orientata agli oggetti, conosci le API nella loro incarnazione come interfacce e classi utilizzate per ottenere l'accesso alle funzionalità sottostanti del linguaggio o come il volto pubblico di librerie di terze parti e funzionalità del sistema operativo.

In generale, possiamo dire che le API impostano e gestiscono i confini tra i sistemi, come mostrato nella Figura 1.

Matthew Tyson

Quindi dove ci lascia con lo sviluppo basato su API?

API Java per cloud computing, microservizi e REST

La programmazione con le API viene alla ribalta con la moderna API web: un'API esposta alla rete (NEA) , dove il confine tra i sistemi è "oltre il cavo". Questi confini sono già centrali per le app Web, che sono il punto di contatto comune tra client front-end e server back-end. La rivoluzione del cloud ha aumentato in modo esponenziale l'importanza delle API Java.

Qualsiasi attività di programmazione che richiede il consumo di servizi cloud (che sono fondamentalmente API pubbliche) e la decostruzione dei sistemi in distribuzioni più piccole, indipendenti ma correlate (note anche come microservizi), fa molto affidamento sulle API. Le API esposte in rete sono semplicemente più universali, ottenute più facilmente e più prontamente modificate ed estese rispetto alle API tradizionali. L'attuale tendenza architettonica è quella di sfruttare queste caratteristiche.

I microservizi e le API pubbliche derivano dalle radici dell'architettura orientata ai servizi (SOA) e del software-as-a-service (SaaS). Sebbene SOA sia stata una tendenza per molti anni, l'adozione diffusa è stata ostacolata dalla complessità e dai costi generali di SOA. Il settore ha optato per le API RESTful come standard de facto, fornendo una struttura e una convenzione sufficienti con maggiore flessibilità nel mondo reale. Con REST come sfondo, possiamo creare definizioni API formali che mantengano la leggibilità umana. Gli sviluppatori creano strumenti attorno a queste definizioni.

In generale, REST è una convenzione per la mappatura delle risorse ai percorsi HTTP e alle azioni associate. Probabilmente li hai visti come metodi HTTP GET e POST. La chiave è utilizzare HTTP stesso come standard e sovrapporre le mappature convenzionali per la prevedibilità.

Utilizzo di API Java nella progettazione

Puoi vedere l'importanza delle API, ma come le useresti a tuo vantaggio?

L'utilizzo delle definizioni API Java per guidare il processo di progettazione e sviluppo è un modo efficiente per strutturare il pensiero sui sistemi IT. Utilizzando le definizioni API Java sin dall'inizio del ciclo di vita dello sviluppo del software (raccolta di concetti e requisiti) creerai un prezioso artefatto tecnico che è utile fino alla distribuzione, nonché per la manutenzione continua.

Consideriamo come le definizioni dell'API Java colmino le fasi di sviluppo concettuale e di implementazione.

API descrittive vs prescrittive

È utile fare una distinzione tra API descrittive e prescrittive. Un API descrittivo descrive il modo in cui il codice effettivamente funzioni, mentre un'API prescrittivo descrive come il codice dovrebbe funzionare.

Entrambi questi stili sono utili ed entrambi sono notevolmente migliorati utilizzando un formato standard strutturato per la definizione dell'API. Come regola generale, l'utilizzo dell'API per guidare la creazione del codice è un utilizzo prescrittivo, mentre l'utilizzo del codice per l'output della definizione dell'API Java è un utilizzo descrittivo.

Raccolta dei requisiti con le API Java

Sullo spettro dal concetto all'implementazione, la raccolta dei requisiti è decisamente oltre il lato del concetto. Ma anche nella fase concettuale dello sviluppo di app, possiamo iniziare a pensare in termini di API.

Say your system-in-design is dealing with mountain bikes--construction, parts, and so forth. As an object-oriented developer, you'd start by talking to stakeholders about requirements. Pretty quickly after that, you would be thinking about an abstract BikePart class.

Next, you would think through the web application that would manage the various bike parts objects. Soon, you would arrive at common requirements to manage those bike parts. Here's a snapshot of the requirements phase of documentation for a bike parts app:

  • The application must be able to create a type of bike part (gear shifter, brake, etc.).
  • An authorized user must be able to list, create, and make a part type active.
  • An unauthorized user must be able to list active part types, and view lists of individual part-type instances in the system.

Already you can see the outlines of services taking shape. With eventual APIs in mind, you can begin sketching out those services. As an example, here's a partial listing of RESTful CRUD services for bike-part types:

  • Create bike part type: PUT /part-type/
  • Update bike part type: POST /part-type/
  • List part types: GET /part-type/
  • Get part type detail: GET /part-type/:id

Notice how the CRUD services begin to hint at the shape of various service boundaries. If you're building in a microservices style, you can already see three microservices emerging from the design:

  • A bike-part service
  • A bike part-type service
  • An authentication/authorization service

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.

Man mano che crei l'applicazione, vedrai anche il valore dell'utilizzo delle API per catturare la negoziazione avanti e indietro tra sviluppo e business. L'utilizzo degli strumenti API velocizzerà sia l'applicazione che la documentazione delle modifiche al codice.

Specifiche più granulari e codifica effettiva possono richiedere maggiori dettagli rispetto alla definizione concisa nel Listato 1. Inoltre, sistemi più grandi e più complessi potrebbero meritare funzionalità scalabili, come i riferimenti ai documenti. Il Listato 2 mostra un esempio più dettagliato dell'API BikePart.

Listato 2. Aggiunta di dettagli alla definizione API BikePart

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