You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In this blog, I will explain my stages for documenting and building APIs in Node.js.
There are three main stages:
Documenting the API
Creating the models / entities
Developing the API
Documenting the API
Documenting the API is almost a requirement today when building APIs.
It allows the business to decide what each API should do
It defines how the APIs should be organized
You're able to share the API specs so others can start to implement calling them before they are live
It makes developing the API a ton easier because you know how the API should work
Documenting is quite a hard scenario. You should definitely use OpenAPI 3.0 (or previously known as Swagger). It allows you to define what a RESTful API should do and look like. The problem with OpenAPI 3.0 is that is can be quite daunting if you haven't seen it before:
paths:
/users:
get:
summary: Returns a list of users.description: Optional extended description in CommonMark or HTML.responses:
'200': # status codedescription: A JSON array of user namescontent:
application/json:
schema:
type: arrayitems:
type: string
The above REST API returns a simple JSON array of strings. It is important that before building your API, you define it with the OpenAPI spec. This means you can decide on functionality before implementing so you spend less time re-writing.
The other part is that OpenAPI can also define models, which you can think of re-usable structures in your APIs. For example, let's say we have a User model. The User model contains a name, email and phone number. We might have two APIs:
GET /users - which returns an array of our User model
GET /users/:id - might return a single User model
paths:
/users:
get:
summary: List of Userstags: []responses:
'200':
description: OKcontent:
application/json:
schema:
type: arrayitems:
$ref: '#/components/schemas/User'operationId: get-users'/users/{id}':
parameters:
- schema:
type: stringname: idin: pathrequired: trueget:
summary: Single User by IDtags: []responses:
'200':
description: OKcontent:
application/json:
schema:
$ref: '#/components/schemas/User'operationId: get-users-idcomponents:
schemas:
User:
title: Usertype: objectproperties:
name:
type: stringemail:
type: stringphone:
type: stringdescription: User structure
Notice in this API spec, our User model lives in the Components property. The problem I have is that I really don't enjoy manually writing YAML. There are lots of tools for building, maintaining and viewing OpenAPI specifications, but my favourite is Stoplight. It was shown to me by my friend Connor and it has changed my life. It makes building APIs fun.
Creating the Models / Entities / Using an ORM
Using an ORM, or at least encapsulating your database access and business logic makes writing web APIs a ton easier. It allows you to separate out the web API (Express) logic from any database or business logic. It means that you can also re-use your business logic and database access across multiple APIs instead of writing it over and over again.
There lots of different ORMs and ways to create Models for your data (TypeORM, mongoose, Sequelize). Since I am primarily working with Db2 for i, I have the struggle that Db2 isn't a well-supported database with those ORMs.
Previously I was manually creating classes for all my models and data access. I was getting frustrated with re-writing a lot of the stuff and wanted something to create everything for me (kind of like a traditional ORM would) - so I built db2Model.
db2Model will build classes based on a Db2 for i table for me. It will create
each column as a property in the class (with the correct JavaScript types and column documentation)
static methods to get a model (row) by primary or unique key(s).
instance methods to update and delete the row based on the properties.
instance methods to fetch other Models based on foreign keys in the column
Here's an example model for the DEPARTMENT table in the Db2 for i Sample schema.
constdb2=require('../db2');constGenericTable=require('./GenericTable');constEmployee=require('./Employee');module.exports=classDepartmentextendsGenericTable{static_table='DEPARTMENT';static_schema='SAMPLE';static_keys=["DEPTNO"];static_columns=["DEPTNO","DEPTNAME","MGRNO","ADMRDEPT","LOCATION"];constructor(row){super();/** @type {String} DEPTNO */this.deptno=row.DEPTNO.trim();/** @type {String} DEPTNAME */this.deptname=row.DEPTNAME;/** @type {String} MGRNO */this.mgrno=(row.MGRNO ? row.MGRNO.trim() : null);/** @type {String} ADMRDEPT */this.admrdept=row.ADMRDEPT.trim();/** @type {String} LOCATION */this.location=(row.LOCATION ? row.LOCATION.trim() : null);}/** * Fetchs Employee by mgrno * @returns {Employee} Returns new instance of Employee */asyncgetEmployee(){returnawaitEmployee.Get(this.mgrno);}/** * Fetchs Department by admrdept * @returns {Department} Returns new instance of Department */asyncgetDepartment(){returnawaitDepartment.Get(this.admrdept);}Delete(){//Code removed to preserve space}Update(){//Code removed to preserve space}/** * Fetchs Department by keys * @param {String} deptno * @returns {Department} Returns new instance of Department */staticasyncGet(deptno){constrow=awaitthis.Find({deptno},1);return(row.length===1 ? row[0] : null);}}
All that code is self-generated from db2Model. Notice, that it extends the GenericTable class. That parent class has two extra methods:
Find which allows us to query our table with a where clause and limit
Join which allows us to query and join to another table by it's Model too.
It means that in our express APIs we can just inherit and use our Model to do all the work. Of course, we can add more instance methods to our model to do more work too!
app.get('/departments',async(req,res)=>{constdepts=awaitDepartment.Find();res.json(depts);//Returns array of Department models});app.get('/departments/:id',async(req,res)=>{constdeptno=req.params.id;constdept=awaitDepartment.Get(deptnp);res.json(dept);//Returns single Department model});app.post('/department/:id',async(req,res)=>{//Simple update API - should add more validation checksconstdeptno=req.params.id;constnewLocation=req.body.location;//New locationtry{constdepartment=Department.Get(deptno);department.location=newLocation;department.Update();res.status(200).json({message: "Update successful."});}catch(e){res.status(500).json({message: "Update failed."});}});
Developing the API
I think I've posted enough code examples. The important part about building the API is that your web APIs match your OpenAPI spec.
That's where https://www.npmjs.com/package/express-openapi-validator can help. You can build your OpenAPI specification with Stoplight, define the validator in your express application and link it to your OpenAPI specification which validates all input and output based on your definitions.
awaitnewOpenApiValidator({apiSpec: './test/resources/openapi.yaml',validateRequests: true,// (default)validateResponses: true,// false by default}).install(app);
The page linked above has a great example of an OpenAPI spec and an express application.
The text was updated successfully, but these errors were encountered:
In this blog, I will explain my stages for documenting and building APIs in Node.js.
There are three main stages:
Documenting the API
Documenting the API is almost a requirement today when building APIs.
Documenting is quite a hard scenario. You should definitely use OpenAPI 3.0 (or previously known as Swagger). It allows you to define what a RESTful API should do and look like. The problem with OpenAPI 3.0 is that is can be quite daunting if you haven't seen it before:
The above REST API returns a simple JSON array of strings. It is important that before building your API, you define it with the OpenAPI spec. This means you can decide on functionality before implementing so you spend less time re-writing.
The other part is that OpenAPI can also define models, which you can think of re-usable structures in your APIs. For example, let's say we have a User model. The User model contains a name, email and phone number. We might have two APIs:
GET /users
- which returns an array of our User modelGET /users/:id
- might return a single User modelNotice in this API spec, our User model lives in the Components property. The problem I have is that I really don't enjoy manually writing YAML. There are lots of tools for building, maintaining and viewing OpenAPI specifications, but my favourite is Stoplight. It was shown to me by my friend Connor and it has changed my life. It makes building APIs fun.
Creating the Models / Entities / Using an ORM
Using an ORM, or at least encapsulating your database access and business logic makes writing web APIs a ton easier. It allows you to separate out the web API (Express) logic from any database or business logic. It means that you can also re-use your business logic and database access across multiple APIs instead of writing it over and over again.
There lots of different ORMs and ways to create Models for your data (TypeORM, mongoose, Sequelize). Since I am primarily working with Db2 for i, I have the struggle that Db2 isn't a well-supported database with those ORMs.
Previously I was manually creating classes for all my models and data access. I was getting frustrated with re-writing a lot of the stuff and wanted something to create everything for me (kind of like a traditional ORM would) - so I built db2Model.
db2Model will build classes based on a Db2 for i table for me. It will create
Here's an example model for the
DEPARTMENT
table in the Db2 for i Sample schema.All that code is self-generated from db2Model. Notice, that it extends the
GenericTable
class. That parent class has two extra methods:Find
which allows us to query our table with a where clause and limitJoin
which allows us to query and join to another table by it's Model too.It means that in our express APIs we can just inherit and use our Model to do all the work. Of course, we can add more instance methods to our model to do more work too!
Developing the API
I think I've posted enough code examples. The important part about building the API is that your web APIs match your OpenAPI spec.
That's where https://www.npmjs.com/package/express-openapi-validator can help. You can build your OpenAPI specification with Stoplight, define the validator in your express application and link it to your OpenAPI specification which validates all input and output based on your definitions.
The page linked above has a great example of an OpenAPI spec and an express application.
The text was updated successfully, but these errors were encountered: