Building a Node.js E-Commerce API for noobs — Swagger

Flo Sloot
Flo Sloot
Jul 10, 2017 · 5 min read

This time I’m going to get my hands really dirty!
Since I’m building an API that’s meant for more than one frontend application I think it’s a good idea to use best practices to document and develop it…

So far..

.. I have tested what impact it has when authenticating against Moltin everytime I’d like to call Moltin API for products, reviews, checkout, whatever; not that big of an issue because Moltin is blazingly fast! Though, I don’t think it’s supposed to be used this way? (Maybe someone can give me an answer to that question)
And created a basic webserver using express.

But what’s about an real API

Real API, real documentation, real swagger…
Swagger is the real deal!
I think.
Never worked with it.
But I want to make use of the AWS API-Gateway later.. So I’m going to put it into a schema that can be imported by the API-Gateway!

Code

First of all I’ll get rid of the previously used app.js and create a new repo, install the Swagger CLI and create a swagger project!

$ mkdir ecommerce-api &&
$ cd $_ &&
$ npm i -g swagger &&
$ swagger project create ecommerce-api && #I choose express
$ swagger project start ecommerce-api

Voilà! This tells me I can run a test to the newly create API from a new terminal window:

$ curl http://127.0.0.1:10010/hello?name=Scott

Yeah! API up and running!

Meanwhile I’ll open the swagger-editor in chrome with

$ swagger project edit ecommerce-api

Looks useful.

When opening the project in an editor, I find a prebuilt structure which makes it pretty easy to follow the best practices in terms of folder structure in Swagger!

Also I got an app.js that looks pretty much the same as the one I created before…

'use strict';var SwaggerExpress = require('swagger-express-mw');
var app = require('express')();
module.exports = app; // for testing
var config = {
appRoot: __dirname // required config
};
SwaggerExpress.create(config, function(err, swaggerExpress) {
if (err) { throw err; }
// install middleware
swaggerExpress.register(app);
var port = process.env.PORT || 10010;
app.listen(port);
if (swaggerExpress.runner.swagger.paths['/hello']) {
console.log('try this:\ncurl
http://127.0.0.1:' + port + '/hello?name=Scott');
}

});

I don’t need the if statement on the bottom so I just remove it.

Basic…
What’s actually more fun is the Swagger file in /api/swagger/swagger.yaml => looks crazy to me; might be because I’m not used to working with .yaml files.

swagger: "2.0"
info:
version: "0.0.1"
title: Hello World App
# during dev, should point to your local machine
host: localhost:10010
# basePath prefixes all resource paths
basePath: /
#
schemes:
# tip: remove http to make production-grade
- http
- https
# format of bodies a client can send (Content-Type)
consumes:
- application/json
# format of the responses to the client (Accepts)
produces:
- application/json
paths:
/hello:
# binds a127 app logic to a route
x-swagger-router-controller: hello_world
get:
description: Returns 'Hello' to the caller
# used as the method name of the controller
operationId: hello
parameters:
- name: name
in: query
description: The name of the person to whom to say hello
required: false
type: string
responses:
"200":
description: Success
schema:
# a pointer to a definition
$ref: "#/definitions/HelloWorldResponse"
# responses may fall through to errors
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
/swagger:
x-swagger-pipe: swagger_raw
# complex objects have schema definitions
definitions:
HelloWorldResponse:
required:
- message
properties:
message:
type: string
ErrorResponse:
required:
- message
properties:
message:
type: string

Shoutout to whomever created this CLI! Thank you for the comments ;)

I’ll just copy the /hello part from the file and paste it right between “$ref” and “/swagger:” rename the duplicate to /hey and paste it

     ...# the new path
/hey:
# binds a127 app logic to a route
x-swagger-router-controller: hello_world
get:
description: Returns 'hey' to the caller
# used as the method name of the controller
operationId: hey
parameters:
- name: name
in: query
description: The name of the person to whom to say hello
required: false
type: string
responses:
"200":
description: Success
schema:
# a pointer to a definition
$ref: "#/definitions/HelloWorldResponse"
# responses may fall through to errors
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
...

Looking at the browser window where the swagger editor is still open I can see my new route!! Yeah, nice!
It’s probably not going to work before I create the function with the operationId = “hey” in the /api/controllers/hello_world.js (here I also found the operationId =” hello”)

...module.exports = {
hello: hello,
hey: hey
};
...function hey(req, res) {
// variables defined in the Swagger document can be referenced using req.swagger.params.{parameter_name}
var name = req.swagger.params.name.value || 'stranger';
var hey = util.format('Hello, %s!', name);
// this sends back a JSON response which is a single string
res.json(hey);
}

So I just duplicated the already existing hello function and renamed it to hey..
I’d like to test it!!

$  curl http://localhost:10010/hey?name=Bob # returns 'Hello, Bob!'

Nice! Working as expected!
That was easy!

Bring Moltin and my middleware back!

Alright, so now I got a really professional looking API ready to roll!

Only thing left now is to bring back the functionality I had in the Express Code before!

I create a new file in the controllers folder and call it moltin_requests.js

// require the util module thats backed into node
const util = require('util');
// same same
const moltin = require('moltin');
const Moltin = moltin.gateway({
client_id: 'BlaBla_client_id',
client_secret: 'BlaBla_client_secret'
});
function moltin_auth(req, res) {
Moltin.Authenticate()
.then(response => {
console.log('authenticated', response);
res.json(util.format(response));
})
}
// export the authentication function
module.exports = {
moltin_auth
};

Also I need to update the swagger file to rename the path, it’s controller and the function that get’s triggered.. Should probably also create a new response schema:

...
/moltinAuthenticate:
# binds a127 app logic to a route
x-swagger-router-controller: moltin_requests
get:
description: Returns the Moltin API response after authenticating
# used as the method name of the controller
operationId: moltin_auth
responses:
"200":
description: Success
schema:
# a pointer to a definition
$ref: "#/definitions/MoltinAuthResponse"
# responses may fall through to errors
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
...
# complex objects have schema definitions
definitions:
HelloWorldResponse:
required:
- message
properties:
message:
type: string
MoltinAuthResponse:
required:
- authentication
properties:
authentication:
type: object

ErrorResponse:
required:
- message
properties:
message:
type: string

Let’s give it a shot!

$ curl http://localhost:10010/moltinAuthenticate # returns an object

Last thing I’m going to takle is the middleware thing.. which is basically the same as before!

moltin_requests.js

const util = require('util');const moltin = require('moltin');
const Moltin = moltin.gateway({
client_id: 'BlaBla_client_id',
client_secret: 'BlaBla_client_id'
});
function moltin_auth(req, res) {
Moltin.Authenticate()
.then(response => {
console.log('authenticated', response);
res.json(util.format(response));
})
}
// don't get too confused here.. this function is basically doing // the same as moltin_auth() but you'll get the point
function moltin_auth_middleware(req, res, next) {
Moltin.Authenticate()
.then(response => {
console.log('authenticated via middleware', response);
next();
})
}
// export the middleware function
module.exports = {
moltin_auth,
moltin_auth_middleware
};

app.js

'use strict';const SwaggerExpress = require('swagger-express-mw');// require only the middleware function I just created
const { moltin_auth_middleware } = require('./api/controllers/moltin_requests');
const app = require('express')();
const config = {
appRoot: __dirname // required config
};
// tell express to use the middleware function as middleware
app.use(moltin_auth_middleware)
SwaggerExpress.create(config, function(err, swaggerExpress) {
if (err) { throw err; }
// install middleware
swaggerExpress.register(app);
const port = process.env.PORT || 10010;
app.listen(port);
});
module.exports = app; // for testing

No big changes!! Great :)

$ curl http://localhost:10010/hello 
# this will now log the moltin response to the terminal running the # project and log 'Hello, Bob!' to the current one!

I for sure should create a dedicated folder for middlewares.. just to keep things clean!

DONE!

Working awesome so far!!!
Next, I’m going to clean things up and create real functions an new routes!

Part Four

Flo Sloot

Written by

Flo Sloot

in love with JS, Freelancer, Hamburg ⚓️

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade