How To Conquer Monkey Code! Banana Free API Generation 🙊

wrannaman
ITNEXT
Published in
7 min readJun 10, 2019

--

You’re still writing monkey code?!?!?!! Photo by Jamie Haughton on Unsplash

This article is a tutorial on code generation and automatic api creation using sugar-generate which is free and open source on github and npm.

I feel a little stupid. I’ve been writing the same API code and boilerplate for years and it didn’t occur to me to write code that writes this code for me. But now that I’ve started using code generators, I’m never going back. We’ve gone from assembly to C to …Javascript. It’s clear the future will be about writing less code to do more.

I hadn’t deeply explored code generation but my quick search took me to two places:

Swagger Codegen

https://swagger.io/tools/swagger-codegen/

This looks promising!! Except when you actually look at what it generates. I don’t want server stubs. I want it to take a schema and generate the damn thing for me.

Strapi

Strapi is a pretty cool choice. No complaints here. I just am wary of buying into large frameworks like this. When shit hits the fan, I don’t know where to go to fix it.

Also the second I tried to put my own local mongodb database in, the app crashed and I couldn’t get it to recover. Probably something simple but annoying none the less.

Both options are fine, obviously, a lot of people find these two modules useful. I wanted to do something a little different. Something a little lighter, and something that would focus on my productivity.

Sugar Generate

Let’s get started with sugar-generate. It’s a free and open source NPM module to generate CRUD APIs so you don’t have to.

Prerequisites

  • Have MongoDB installed and running
brew install mongodb && sudo mongod --bind_ip_all

The — bind_ip_all will be important when trying to connect from docker.

Then install the sugar-generate node module.

npm i -g sugar-generate

Create a schema. Schema’s are JSON representations of your APIs. Below is a simple one for an API called Monkey

{
"schema": {
"first_name": {
"type": "String",
"default": ""
},
"last_name": {
"type": "String",
"default": ""
},
"isDead": {
"type": "Boolean",
"default": false
},
"age": {
"type": "Number",
"default": false
}
},
"statics": {
}
}

We will continue with the Monkey schema but here is an example of a slightly more complex schema that sugar-generate supports

{
"schema": {
"first_name": {
"type": "String",
"default": ""
},
"last_name": {
"type": "String",
"default": ""
},
"email": {
"type": "String",
"trim": true,
"required": true,
"unique": true,
"immutable": true
},
"password": {
"type": "String",
"trim": true,
"select": false,
"immutable": true
},
"intro": {
"type": "Boolean",
"default": false
},
"team": {
"type": "ObjectId",
"ref": "Team"
},
"sub": {
"one": {
"type": "String",
"trim": true,
"required": true
},
"two": {
"type": "Number",
"required": true
}
},
"role": {
"type": "String",
"enum": ["user", "maker"],
"default": "user"
}
},
"statics": {
"statuses": ["created", "under_review", "listed", "deleted"],
"status": {
"active": "active",
"inactive": "inactive",
"deleted": "deleted"
}
}
}

Under the hood, we’re using mongoose so the schemas are designed to mimic the mongoose schema representation. You can see this in the generated code.

const database = require('../connection/mongo');
const {
Schema
} = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const schema = new Schema({
first_name: {
"type": String,
"default": ""
},
last_name: {
"type": String,
"default": ""
},
isDead: {
"type": Boolean,
"default": false
},
age: {
"type": Number,
"default": false
},
}, {
timestamps: true
});
schema.plugin(mongoosePaginate);
module.exports = database.model("monkey", schema);

Now on to the fun part.

sugar-generate \
--type api \
--name monkey \
--schema /path/to/monkey.json \
--destination /where/you/want/the/code
sugar-generate output

and now you have your generated API! Let’s take a look at the output.

We have a simple config file containing out database connection, port, and a few other items I plan to add in the future.

our connections folder holds our database connection.

Our controllers hold our single endpoint with create, get, update, and delete functions.

Our mongoose model sits here

Super simple routing

You love tests don’t you.

User-can is some magic I want to implement in the future. The idea is that a simple middleware layer will extend common functionality like authentication for people and machines.

the rest of this crap I'm sure you’re intimately familiar with. Only one thing to point out here is the swagger.json. When you start the API, this file gets loaded in the Swagger UI.

Obligatory NPM install

npm i

Let’s run the test suite to make sure the generator worked properly.

npm run test

Looking good! Let’s fire up the server! Generate the swagger doc, and start the server

npm run docs && npm start

and now navigate to localhost:7777

and here you have your ready-to-deploy api.

… and how about deployment? We got you covered there too

Build the docker container.

We’re going to have to make one small change to the configs/config.json file

// in config/config.json 
// change mongoURL to mongodb://<your ip address>:27017/sugar
docker build -t monkeys:0.0.1 .

Now run it!

docker run -ti -p 3030:3030 -e PORT=3030 monkeys:0.0.1 

if you get the “Mongo OKAY” message you’re connected and ready to rock and roll.

If you’re looking to get it on the internet, try Google Cloud Run. It’s my new favorite services from Google (no affiliation). Just push this docker container to google and have it up and running in no time on the web with an SSL cert. It’s also a scale to zero “serverless” service so you’ll have infinite scalability all the way down to zero without any ops effort or maintenance 🤗🤗.

docker build -t gcr.io/<your google project id>/monkeys  .
docker push gcr.io/<your google project id>/monkeys

now let’s hop into the google console cloud run service!

select create service

on the next page click the “select” button in the container image URL

now let’s pick our container we pushed

name the service and hit create!

after about 30 seconds you’ll have the new api deployed online over ssl

Hit the new url and voila! You’ll have to change the swagger.json to the new address. Make that change and hit “Explore” in the swagger ui.

You can probably see now why I feel a little behind the curve. I now no longer have to

  • write monkey code
  • write stupid boilerplate
  • write docker files
  • write lets encrypt crons
  • set up a server
  • manage the server
  • get phone calls at 2 am because the service is down
  • worry about cost (it spins up and down with usage)
  • get yelled at for spinning up 30 c5xl because of Christmas load anticipation

and I get to do all that in about a minute (once you’ve done it a few times)

So what’s the catch? Primarily it’s that the project is young.

Here’s a bit more about the project

Features 🙉

  • Generates simple Nodejs code
  • Uses Mongodb with Mongoose ORM
  • Easy to build / deploy / maintain
  • Dockerfile included
  • Generates CRUD APIs
    — create
    — get (many, with pagination; supports search, sort, filter, pagination out of the box)
    — getOne
    — update
    — delete

What it’s good at 🙊

  • Generating an initial API
  • Microservice oriented
    - Ready to deploy (build with docker => deploy)

What it’s not good at (yet) 🙈

  • idempotent changes (i.e. it doesn’t know if you wrote code in there or changed things around)
  • working with modified code
  • populating table joins
  • custom actions inside controller functions

I’m building all kinds of fun stuff over at SugarKubes. Let me know what you’re building with sugar-generate and what features you’d like to see!

Hugs,

AP

--

--