Skip to content

Build and evolve a REST API design-first with OpenAPI-Generator and Node.js. API CodeFlow is an agile, design‑first workflow that integrates API specifications into the build process, so API docs and code are continually in sync.

RepreZen/API-Codeflow-Node.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Node.js Example

API CodeFlow Logo

This project serves as a demo for an API CodeFlow approach to API service implementation. This entails the following three steps, repeated as the API evolves:

  1. Design your API in OpenApi.

  2. Generate stub code in Node.js (JavaScript).

  3. Implement your business logic.

This demo will create a working API to manage a database of live pets for a pet store. (No animals have been harmed in the creation of this demo.)

Custom Code Generation

A custom code generator was built especially for this demo, to show how you can tailor code generation to meet your specific needs. This code generator is not complete, in the sense that it lacks a number of useful features. However it does actually work, and it includes all of the following:

  • Automatic generation of controllers and handlers for all operations defined by the API. The controllers are fixed code that are not intended for user editing and will be overwritten during regeneration. They serve as bridges between the service framework and the handlers. Handlers are where business logic belongs. Handlers are never overwritten by the generator.

  • Controllers and handlers are organized by tags to simplify code management.

  • Automatic integration of Swagger-UI, with options to re-route Try-It-Out requests to your running service, overriding server definitions in the model.

  • A very simple built-in database with basic CRUD capabilities.

Working Through the Demo

Overview

The demo proceeds in five phases (plus some initial set-up). There are branches defined for each phase, which you can use to quickly bring your workspace up to that point of the demo, rather than manually working through each step.

💡

If you have checked out a branch for the end of one phase and then worked through the next phase manually, you will almost certainly have files in your working tree that will block an attempt to simply check out the branch for the next phase. To proceed, clean out your working tree with:

git clean -fd

If you have also modified non-ignored files, you will also need to do this:

git reset . ; git checkout .

The phases are:

  1. Setup - install and launch RepreZen API Studio, and install Nodeclipse from the Eclipse Marketplace, so you’ll be able to work with Node.js code.

  2. Obtain the custom generator from the demo repository and activate it in your workspace.

  3. Design - Create one of the standard OpenAPI v3 example models available in RepreZen API Studio.

  4. Generate - Prepare a Node.js project for the service implementation, and use the code generator to populate it.

  5. Implement - Write your business logic into the generated stubs.

  6. Iterate (DesignGenerateImplement) in order to add a new method to the API

So let’s dig in!

Phase 0 - Setup

If you don’t already have RepreZen API Studio installed, you’ll want to visit the RepreZen website and sign up for a free trial. If you’re already an Eclipse IDE user, you may want to consider installing API Studio from Eclipse Marketplace, rather than using the stand-alone installer offered in the sign-up process. Installation options are explained here.

Once you’re up and running, you should install Nodeclipse from Eclipse Marketplace, which you can find on the Help menu. Follow the instructions, and after a restart you’ll have added robust support for Node.js projects to the product.

Eclipse Marketplace
⚠️
There is an unimportant conflict involving a particular feature required by Nodeclipse and already present (in a different version) in API Studio. During installation you’ll be informed of this asd presented with a recommendation as to how to proceed. You should accept the recommendation.

Your final setup step, if you haven’t done it already, is to clone this project to a local working directory on your machine.

git clone [email protected]:RepreZen/API-Codeflow-Node.js.git

Phase 1 - GenTemplate

💡
The end state of this phase is captured in branch 01.gentemplate.

In this step you will change your workspace to one provided in the demo project, having checked out a branch that includes the generator as a workspace project (in contrast to the numerous pre-packaged geneartors that are available out of the box in API Studio).

Follow these steps:

  1. In your demo project working directory, checkout the 01.gentemplate branch.

    git checkout 01.gentemplate
  2. In API Studio, use File → Switch workspace → Other…​ and navigate to your working directory, and then into the workspace folder you’ll find there.

    Switch Workspace
    Select Workspace
  3. API Studio will restart after you click the Launch button.

  4. Use File → Import…​, and in the resulting dialog select the Maven / Existing Maven Projects option and click Next. In the next panel, use the Browse button to locate your working directory and click Next. You should check tne NodeGenTemplate project, and click Finish.

    Import Maven Project
    Import NodeGenTemplate
  5. There will be small delay while this project builds for the first time on your machine.

⚠️
In some cases, the initial build will not work correctly, due to a bug that we hope to remedy shortly. You will know this from red error markers on some of the folders inside the the main NodeGenTemplate project folder. If you see them, right-cliick on that project folder, select Run As → Maven build…​, and then type compile into the Goal field before pressing Run.

Phase 2 - Design

💡
The end-state of this phase is captured in branch 02.petstore.

We won’t actually design a model here. Instead, we’ll just use one of the OpenApi3 models available from the API Studio Examples Wizard.

Follow these steps:

  1. Click on the drop-down arrow of the New tool in the toolbar, just under the File menu.

  2. Select RepreZen Examples to open the Examples Wizard.

    Open the Examples Wizard
  3. Click on the OpenAPI v3 tab.

  4. Select the Expanded Pet Store (v3) example, and press Finish.

    Expanded Pet Store Example
  5. You should see a new project in your workspace, and the example model file itself will automatically open in an editor.

  6. Browse through the model briefly to familiarize yourself with its operations and other components.

Phase 3 - The Pet Store Service

💡
The end state of this phase is captured in branch 03.service.

This is where we’ll generate code for the model we created, in phase 2. We’ll arrange for the generated files to land directly in a Node.js project that we will set up for that purpose. Later regeneration cycles will all continue to feed into that project.

Follow these steps:

  1. Right-click in the Project Explorer pane and use New → Node.js Project to bring up a wizard.

    Create a Node.js Project
  2. Type PetStoreService for the Project name.

  3. Select the none/empty template, then press Finish. A new project appears in your workspace.

    Create PetStoreService Project
  4. In your model project, locate the petstore-expanded.yaml file in the models folder, and click on it.

  5. Click on the Create a New GenTarget button in the toolbar, just to the left of the Generate button/menu.

    Create GenTarget
    💡
    If you do not see this in the toolbar, be sure that you are in the RepreZen perspective, by clicking on the appropriate button on the far right of the toolbar: reprezen perspective.
  6. Type "node" in the resulting dialog’s search box, and you should see our NodeGenTemplate generator. Select it and press Finish. A new GenTarget is created in your project, and the .gen file that describes it opens in an editor.

    Select NodeGenTemplate
  7. Make and save the following changes in this file:

    1. Near the top, change the value for relativeOutputDir to ../../../../PetStoreService. This is what will cause generated files to flow directly into the project we just created.

    2. Set pathPrefix to /api, to align with the path prefix listed in the first server defined in our model. This will cause the running service to properly recognize and route requests sent from Swagger-UI.

    3. Set swaggerUIPath to api-ui. The default, /api, clashes with the pathPrefix that is dictated by the server definition in our model. (Of course, we could also just change that server definition to use a different path prefix, or just remove it altogether.)

      Update GenTarget Definition
  8. Run the generator, by clicking on the big Generate button in the toolbar. (Since we’ve been actively editing the .gen file for the NodeGenTemplate generator, the menu should show that as the generator to run. If not, click instead on the small arrow to the right, and select NodeGenTemplate from the list of targets.)

    The Generate Button
  9. Even though the service project files are now present, they will not appear in Project Explorer until you cause a refresh of the project files. Right-click on PetStoreProject in Project Explorer and then select Refresh to do this.

    Refresh the Service Project
💡
We’ll be doing this a couple more times in later phases.

Phase 4 - Implementing Business Logic

💡
The end state of this phase is captured in branch 04.implement.

Now it’s time to write the code that will implement the business logic of our API service.

You should only need to touch files in the handlers folder of the PetStoreService project. In this case there’s only one file - Untagged.js. Normally, there could be several files here, named after the tags defined in the model. When operations are grouped using tags, this allows the overall implementation code base to be split into more manageable pieces. In our example model, tags are not used, so all the handlers ended up in a single Untagged source file.

Generated Code

If you’re reasonably proficient with Javascript, Node.js and Express.js, you may want to take a crack at this yourself. But you can also skip forward by chekcing out the necessary files from branch 04.implement of the demo repo. In that case you may want to take a look at the before and after images of handlers/Untagged.js, just to get a sense of what’s going on.

To check out final the implementation from the repo, use this command, from the root of your working tree:

git checkout origin/04.implement -- workspace/PetStoreService

You’ll need to refresh the PetStoreService again to see the changes in API Studio.

The basic design of the handlers goes like this:

  • Each controller method implements the logic for a single operation defined in the model.

  • The methods are named after operation ids if they exist. Otherwise they’re a combination of the operation’s path string (up to but not including the first path parameter) and the operation’s HTTP method. Name collisions are disambiguated with trailing integers.

  • Each method is declared with a parameter list that corresponds to the operation’s declared parameters in the model. If any path-level parameters are inhereted by this operation, they follow the operation’s own parameters. If the operation defines a RequestBody there will be a final body parameter.

  • The handler is expected return a new Promise that has either been resolved to a value for the response payload, or rejected with an error object that should have code and message properties.

  • The non-error response can also be an object with code and value properties, in which case the code value will be used for the HTTP status code, and the value property will be used for the payload.

  • If the response payload is undefined, no response will be provided, and the default status code will be 204. Otherwise the default status code will be 200.

  • All payloads - including the error objects - are sent as JSON values.

  • Each handler makes calls to validators, one for each parameter. Stubs for the validators are also provided, after all the handlers.

  • Validators should throw an error object if validation fails.

  • Each validator that does not throw must return a final value for the parameter it checked. This is where, e.g. a string value from a query parameter is converted into an integer after testing that it’s syntactically valid.

If you want to run your implementation, you can follow these steps:

  1. Right-click on the package.json file in the service project, and select Run As → npm install. You’ll only need to do this again if you change the file or remove the node_modules directory.

    Perofmr npm Install
  2. Refresh the PetStoreService project again. This is needed in order for the results of the build to become available in the project, since the build itself is carried out in a separate process.

  3. Right click on app.js in the service project, and select Run As → Node Application. You should see a start-up message in a console pane that makes itself visible.

    Launch the Service App
    Service Listening Message
  4. Visit http://localhost:3000/api-ui in a web browser. You should see Swagger-UI displaying your model. The "Try It Out" buttons will work, and requests will be directed to your running instance, regardless of the server definitions in the model itself.

    Swagger-UI Connected to Service

Phase 5 - Iterate

💡
The end state of this phase is captured in branch 05.patch.

Missing from the API model is an operation that allows modification of selected properties of a pet. In phase 5 we add a patch operation to the /pets/{petId} path to supply this capability. The steps are:

  1. Add the operation to the model file, petstore-expanded.yaml in the model project.

  2. Rerun the generator. Everything but the handler files will be refreshed and will reflect the additional operation.

  3. Add a handler for the new patch method to the handler file (the corresponding controller will already be updated).

To check out a working implementation from the demo repository, use the following command (then refresh the PetStoreService project again):

git checkout origin/05.patch -- workspace/PetStoreService 'workspace/Expanded Pet Store (v3)/models'

You’ll find that another method has been added to the handlers/Untagged.js source file.

And that’s it. At that point you should be able to re-launch the application and make use of the nifty new patch method.

⚠️
If you attempt to re-launch the app and see an error message indicating that the port is already in use, it’s because your prior launch is still running and still listening on port 3000. To terminate that launch, open the Console view (use Window → Show view → Other…​ and then select the General/Console view and click Open.) Near the right end of that view’s toolbar, open the Display Selected Console menu, and select a console labled PetStoreService…​ that is not marked as terminated. You’ll then see a square red toolbar button that you can use to terminate the launch. At that point you should be able to successfully re-launch the service app.

About

Build and evolve a REST API design-first with OpenAPI-Generator and Node.js. API CodeFlow is an agile, design‑first workflow that integrates API specifications into the build process, so API docs and code are continually in sync.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published