An extension of “Design-First” methodology is “Contract-First” where the developer defines the contract of the API before the implementation is coded. Just-in-time and just-enough design is critical to agility. Applying design-first / contact-first methodology to the world of API development results in “API-First” development. The basic idea is that you create an API contract before implementing the full code and plumbing. The human-readable API specification becomes the quick first deliverable that allows fast, quick feedback from various stakeholders. These rapid iterations are a game changer because changing the API specification takes minutes not hours or days! Once the team determines that the API specification is “good enough” a full maven Spring Boot Application can be generated. Many other languages are supported as well – more on that later. The developer codes the business logic implementation in the server stub. While the developer is coding, the QA teams can be handed the spec as well so they get a head start on service testing.
The Open API Specification is a language and vendor neutral API specification standard. There are many permutations of tools, technologies, languages to approach API design and development, most new server-side development happens in the Java programming language. This document will walk through a real world scenario of putting ‘API-First in Practice’ with Open API for the first time. The goal is to provide a clear path to achieving agile API development and being effective at it.
Read about the Open API Initiative.
There are 4 high-level steps:
The first step is essentially starting the API development using Open API Spec 2.0. Begin working on evolving and iterating the API specification by collaborating with the product owner, service consumers and other stakeholders. Once the team is comfortable that the API specification is 'good enough' - generate the server in Spring Boot. Deploy the app to the cloud or locally. At this point the round-trip engineering starts. All updates to the API in the code automatically updates the API specification that is co-deployed via annotations.
Use Open API 2.0 specification standard and the YAML format to describe the API as follows:
The high-level context of the API:
swagger: '2.0' info: title: LOB Request Write-Side API description: Transaction Request aggregate Write-Side API to manage the overall transaction context. /transactions is the aggregate root through which this API will be modeled. Basically, the business user will start and manage transactions explicitly (or implicitly). Past-tense events will be published after the transaction completes. The model depicted in this API is exposed for write operations only per the CQRS pattern, it is possible that the entities encapsulated within the service implementation are further enriched to perform the business logic that's expected. version: "1.0.0" schemes: - https basePath: /v1 produces: - application/json - application/xml
Expect the consumers of the API to read the info sections, paths, verbs and model information to fully understand the API and how to interact with it.
paths: /transactions: post: summary: | Starts a transaction. It can start either a Multi-line App or a Mono-line App Transaction. All types of transaction types are supported via this API. Business rules/logic will be executed to ensure this operation can be executed. Transactions are a container that tracks and manages the overall processing. description: | This is the aggregate root of the API. If only one LOB request exists under the transaction then a monoline app request is created. A multi-line app request contains more than one 'lob requests'. Each 'lob request' has an associated policy app/lob. This end-point contains a single request or multiple requests - and executes the StartRequestCommand. The Multiline Request endpoint creates a new multi-line app request (and child requests if provided). This API should be used for all requests (monoline app or multi-line apps). This is the Multi-Line App Request Aggregate Root. consumes: - application/json - application/xml produces: - application/json - application/xml parameters: - in: body name: transaction description: | If a transaction_id is not provided, one will be created by the service. Account is optional. Agency is optional. These can be added to the transaction later. required: true schema: $ref: "#/definitions/Transaction" tags: - Transaction responses: 200: description: Successful addition of a transaction. 400: description: Invalid request received - please check the API Contract. 403: description: Forbidden. Client is not permitted to perform this operation. 409: description: Conflict. Resource already exists. default: description: Unexpected error schema: $ref: '#/definitions/Error'
The path parameters define the shape of the API via URIs. Each URI definition has multiple HTTP verbs that can act on it.
POST: has a summary of what the API expects and what it responds with on a creation.
Summary and description fields are important to document so that the consumer of the API knows how to use it.
Consumes & Produces - specifies the data formats the API will accept and produce. the Parameters specify where and how the data will enter the API e.g. body, path, header, query etc.
tags - these are optional but help in the documentation of the API.
responses - the responses specify how the API responds and what's in the response body.
definitions - Define the models in the definitions - this section is typically at the end of the API spec file.
definitions: Transaction: type: object properties: transactionId: type: string description: Unique identifier representing a specific transaction. status: type: string description: The status of the transaction. transactionType: type: string description: The activity for the User Intent accountNumber: $ref: '#/definitions/Account' agency: $ref: '#/definitions/Agency' lobRequests: type: array items: $ref: '#/definitions/LOBRequest' LOBRequest: type: object properties: lobCd: type: string description: Line of business code. This is unique per transaction. status: type: string description: Status of the LOBRequest. startDate: type: string format: date description: The date when the request was started. completionDate: type: string format: date description: The date when the request was completed. policy: $ref: '#/definitions/Policy' underwritinginstructions: type: array items: $ref: '#/definitions/UnderwritingInstruction' Policy: type: object properties: policy_id: type: string description: This is a unique identified (GUID) that represents the policy aggregate. lobCd: type: string description: Line of business code. policyTerm: type: number description: Represents the policy term number. UnderwritingInstruction: type: object properties: instructionType: type: string description: The instruction type. instructionDate: type: string format: date-time description: Represents the instruction date-time. instructionRemark: type: string description: Represents the instruction date-time. Account: type: object properties: accountNumber: type: string description: The account number for the account. Agency: type: object properties: agencyNumber: type: string description: The agency number for the account. Error: type: object properties: code: type: integer format: int32 message: type: string fields: type: string
You can start the Open API 2.0 Editor here It will start up with an example. Alternatively, you can import another YAML specification - see the YAML specifications in the references section.
As the API is developing - the specification file can and should be shared with other collaborators for review. The main idea is to ensure that the paths and models are good enough. In other words, you don't want to strive for perfection rather a few brief meetings with the stakeholders to ensure that there is a common understanding and consensus. The idea is that API-first allows for rapid iterations without changing the code/plumbing in the initial phases.
The first-cut of the API spec should minimally have the RESTful paths, responses and high level response objects. The API should be small-enough that it fits within a person’s head. Of course, good understanding of domain driven design, API design, REST design and Open API spec is required.
This design spec can save you hours of implementation and refactoring effort in the plumbing of the code. This allows subject matter experts to discuss the API and make changes. Quality engineers can get involved and begin early test design and development. Architects can begin to think about system architecture implications on sourcing of data. Data analysts can begin thinking about data fields and standards alignment where appropriate. This spec should become the camp fire across which multiple teams can gather to discuss the API and make changes.
To further accelerate the API development process, go ahead and use the API Editor to Generate the Server. Alternatively a command line tool can be used.
A 'Spring Boot' server gets generated along with a Maven pom file and it's dependencies. A compressed zip file with all the scaffolding code for the API is downloaded.
This can be expanded and imported as a Maven project. The parent pom should be updated. Package names should be renamed to match the needs of the service.
The project already contains a Maven pom file and a Spring Boot project with dependencies. it can be run as-is and deployed - it just works. Open a command terminal
mvn spring-boot:run .
When you run the Spring Boot API - you will see the Annotations have been added to the code - and they show up via the api-docs and also the swagger ui.
This api is a JSON format that represents the exact YAML file that was written. Going forward as the code is changed to evolve the shape of the API and it's implementation, SpringFox annotations in the code will always keep the API in sync. If new API end-points are added to this or new verbs - the developer is expected to use the annotations. This should be simple because the API interface class already has annotations and following the same conventions over time will be much easier.
A user-friendly and interactive Web-Page is generated automatically (Swagger UI). This allows for a quick execution of the API - the web-form allows for data to be entered directly and this allows the API to be tested quickly by any user without any special tools or technology skillsets.
There are many permutations of tools, technologies, languages and methods that try to approach API design and development. Weeks of microservices coding can save you hours of API designing. The goal is to provide a clear path to achieving API-First development and being effective at it. API-First Development practice as outlined in this document is effective and economical.
Here's an (opinionated) list of things you need to know (kind of):