Design First

“Design first” process

It can be divided into 3 parts:

  • API ideation
  • OpenApi specification
  • Coding

API ideation


Verbal description of API that we want to have and what we want to achieve by it, including resource (usually abstract object) definition to which our API is referring to and data that are going to be provided and handled by API. As a final result of this part we should provide information about:

  • reasurce URL address (endpoint)
  • data returned by API (expected responses)
  • error handling (behavior in case of error)
  • supported methods/operations (GET/POST/PUT/DELETE etc…)

For instance: For API for credit cards information stored in the system we can have:

  • URL: /creditCards
  • methods: GET (to retrieve list of cards) supporting:
    • selections: query parameters for cardType, description, authorizationDays
    • sorting: card, description, authorizationDays
    • features: paging, freeText search

Having this plan we can design OpenApi specification.

OpenAPI specification


The plan is converted to a human and machine-readable contract, such as an OpenAPI specification document, (Swagger document) from which the code will be built in last part.

OpenApi specification includes:

  • defintion in JSON file
  • Postman collection creation
  • Testing collection against Mockup server

OpenAPI json file


Depending on the implementation level a new file with OpenApi specifaction is created or existing one is udpated. For IPTOR standard API existing iptor_erp_api.json file should be downloaded from GIT repository and updated, whereas for customer modification a new file with customer name as a prefix should be created (i.e. customerName_erp_api.json). See OpenAPI Naming Reference and OpenAPI Work Procedure.

Below is OpenAPI specification for API that retrieves the list of credit cards. It is an excerpt from iptor_erp_api.json with all crucial elements that describe this one API:

"/creditCards": {
      "get" : {
        "tags" : [ "Under development" ],
        "summary" : "This API is used to get list of credit cards",
        "description" : "This API is used to get list of credit cards",
        "parameters" : [ {
          "name" : "cardType",
          "in" : "query",
          "description" : "Card type",
          "schema" : {
            "title" : "Card type",
            "maxLength" : 6,
            "type" : "string",
            "description" : "Card type",
            "example" : "AMEX"
          }
        },
        {
          "name" : "description",
          "in" : "query",
          "description" : "Description",
          "schema" : {
            "title" : "Description",
            "maxLength" : 30,
            "type" : "string",
            "description" : "Description",
            "example" : "Visa credit card"
          }
        },
        {
          "name" : "authorizationDays",
          "in" : "query",
          "description" : "Authorization days",
          "schema" : {
            "title" : "Authorization days",
            "maximum" : 999,
            "type" : "integer",
            "format" : "int32",
            "description" : "Authorization days",
            "example" : 123
          }
        }, {
          "$ref" : "#/components/parameters/control-limit"
        }, {
          "$ref" : "#/components/parameters/control-offset"
        }, {
          "$ref" : "#/components/parameters/control-orderBy"
        }, {
          "$ref" : "#/components/parameters/control-freeTextSearch"
        }  ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "content": {
              "application/json" :{
                "schema" :{
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "items" :{
                          "type" : "array",
                          "items" : {
                            "type" : "object",
                            "properties": {
                              "card" : {
                                "title": "Card",
                                "maxLength": 10,
                                "type": "string",
                                "description": "Card",
                                "example": "My card"
                              },
                              "description" : {
                                "title" : "Description",
                                "maxLength" : 30,
                                "type" : "string",
                                "description" : "Description",
                                "example" : "AMEX credit card"
                              },
                              "cardType": {
                                "title": "Card type",
                                "maxLength": 6,
                                "type": "string",
                                "description": "Card type",
                                "example": "AMEX"
                              },
                              "authorizationDays": {
                                "title": "Authorization days",
                                "maximum": 999,
                                "type": "integer",
                                "format": "int32",
                                "description": "Authorization days",
                                "example": 123
                              }
                            }
                          }
                        }
                      }
                    },
                    "control" : {
                      "title" : "Total records",
                      "type" : "object",
                      "properties" : {
                        "total" : {
                          "$ref" : "#/components/schemas/control-total"
                        }
                      },
                      "description" : "Total number of records in file (array)"
                    }
                  }
                }
              }
            }
          },
          "4xx" : {
            "description" : "Client error",
            "$ref" : "#/components/responses/default-error"
          }
        },
        "x-aperio" : {
          "control-parameters" : {
            "method" : "creditCards.get",
            "openCrossRef" : false,
            "program" : "MGRR9999"
          }
        }
      }
    }

??? Start: Clearify

Designed get method besides standard, mandatory (excluding tags) elements like:

  • tags (Under developent helps to indentify on-going development)
  • description
  • parameters (query/path) and their defintions
  • responses (successful and error)

??? End

It includes also references to common control components that handle paging with limit and offset, freeText search and orderBy features required in API plan.

{
  "$ref" : "#/components/parameters/control-limit"
}, {
  "$ref" : "#/components/parameters/control-offset"
}, {
  "$ref" : "#/components/parameters/control-orderBy"
}, {
  "$ref" : "#/components/parameters/control-freeTextSearch"
}

Please note also x-aperio element which is not required in this part of process, but it’s crucial for establishing connection between API and backend program that will be executed by this method in the final implementation:

"x-aperio" : {
    "control-parameters" : {
    "method" : "creditCards.get",
    "openCrossRef" : false,
    "program" : "MGRR9999"
    }
}

Is also a good practice to define example attribute for parameteres and response properties. These values are used as example values in published OpenAPI specification and as values returned by mockup server istead of pure data types:

"properties": {
  "card" : {
  "title": "Card",
  "maxLength": 10,
  "type": "string",
  "description": "Card",
  "example": "My card"
  }
}

Card example value

Results of updated OpenAPI specification in json file can be directly previewed in VisualStudio code using plug-in SwaggerViewer:

/creditCards, SwaggerViewer

To make this OpenAPI specification available from Postman, changes need to be synchronized with GIT repository and published in corresponding api-bridge.

Postman collection


Postman collection should include base version of the request as well as various combinations of available parameters defined in specification (including mandatory path and optional query parameters). See Postman for more information about this tool.

To be able to run any collection request, baseURL to valid mockup server must be setup in the collection variables. The role of the mockup server is described in this article. How the OpenAPI is injected in mock server you can read in deployment article. For standard API it is:

http://dkdcvs134.ibs.net:778/rest-oidc/v1

Using this baseUrl path API request is created:

method path

Number of requests based on the same API method, but with various parameters can be created as collection that will be used for testing in the next step:

Postman collection

{{baseURL}}/creditCards
{{baseURL}}/creditCards?limit=1
{{baseURL}}/creditCards?limit=1&offset=1
{{baseURL}}/creditCards?cardType=VISA
{{baseURL}}/creditCards?orderBy=description
...

Testing collection on mockup server


Created collections should be extended by test definitions that verify if API respones are valid against schema defintion and expected response codes defined in OpenAPI specification. There is no need to have a database connection, Mockup server is used instead.

Under Tests tab for selected request, test scripts can be entered manually using JavaScript or some standard one can be selected from snippets: snipptes

To test response schema a schema from OpenAPI specification can be provided as parameter:

const schema = {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "items" :{
                          "type" : "array",
                          "items" : {
                            "type" : "object",
                            "required" : ["card", "description", "cardType", "authorizationDays"],
                            "properties": {
                              "card" : {
                                "title": "Card",
                                "maxLength": 10,
                                "type": "string",
                                "description": "Card",
                                "example": "My card"
                              }
                              [...]
                            }
                          }
                        }
                      }
                    },
                    "control" : {
                      "title" : "Total records",
                      "type" : "object",
                      "properties" : {
                        "total" : {
                          "title" : "Total records",
                            "maximum" : 999999999,
                            "type" : "integer"
                        }
                      },
                      "description" : "Total number of records in file (array)"
                    }
                  }
                }
[...]
pm.test("Should be validated by schema", () => {
    pm.response.to.have.jsonSchema(schema)
});

Later, when the corresponding backend program development is completed requests from Postman collection will re-directed to api-bridge with connection to the develpoment enviroment with phisical data. However, it is a good idea to prepare postamn tests in advance based on data that will be retrieved from the development environment database. Having such tests we can directly test if backaned program works correctly and validate if changes applied in the future will not disturb overall functionality.

Coding


When OpenAPI specification is ready and successfully tested in Postman against Mockup server, the development of backend programs can be started.
OpenAPI defines what input parameters and expected responses should be implemented in the backend programs and postman collections verify if returned data are valid.
There are number of sample programs in IAF100AP library on smibsrd0.ibs.net that can be utilised as a base for new manager programs:

IAF100AP/QSAMPLES 

When manager program is completed, baseUrl in Postman collection setup can be updated with the link to dedicated api-bridge that will map API request using Aperio to call the newly created mananger programs.
By running collection requests with test scripts we can validate reponses against expected results.