DevNet API Scavenger Hunt How I built a REST microservice Ashley Roach – Cisco DevNet Principal Engineer & Evangelist @aroach
About Me API & Cloud Evangelist 10+ Yrs Technical Product Mgmt Life-long, self-taught developer Denver, CO github.com/aroach & github.com/ciscodevnet Podcast: devtools.libsyn.com slideshare.net/aroach
DevNet Vision Help developers build solutions and grow their careers. Learn Code Inspire Monetize
§1: Why and What §2: Show the code
§1: Why and What
Cross-train our technical field
What Did We Do? Created background “mini-hacks” activity at sales conference Needed a way for them to submit answers Why not make them do it via an API?!
How we ran it Three challenges per day (Jive site) Answers were provided at the beginning of the next day Support via a Cisco Spark room Submissions were analyzed after the event Small monetary rewards to top 3 finishers
Meetup!
Solution evaluation was hardest part Wrote a CLI Created manually, but could have used swagger-code- gen Wrote test cases Manual validation in the end
§ 2: Show the code
Project Requirements Build an API quickly (~a couple days) Data Persistence User and API Authorization Only an API (No UI for user) Package in a “cloud native” way
Infrastructure Architecture Scheduler CI/CD DBaaS
Technologies involved and evaluated I know MEAN stack (Mongo, Express, Angular, Node) I wanted to try out building using a REST modeling tool Swagger-node Osprey (RAML-based): seemed less feature rich Containerized to be deployed on ciscoshipped.io GitHub Postman MongoHub (Mongo client) mLab (Hosted mongo)
OpenAPI Spec (fka Swagger) Open specification for describing REST APIs A top-down approach where you would use the Swagger Editor to create your Swagger definition and then use the integrated Swagger Codegen tools to generate server implementation. A bottom-up approach where you have an existing REST API for which you want to create a Swagger definition.
Dockerfile FROM node:5.11.1 # Create app directory RUN mkdir -p /usr/src/app # Establish where your CMD will execute WORKDIR /usr/src/app # Bundle app source into the container COPY ./node_modules /usr/src/app/node_modules COPY ./api /usr/src/app/api COPY ./config /usr/src/app/config COPY ./app.js /usr/src/app/ # Expose the port for the app EXPOSE 10010 # Execute "node app.js" CMD ["node", "app.js"]
Docker run --link Legacy container links within the Docker default bridge. This is a bridge network named bridge created automatically when you install Docker. Superceeded by Docker Networks feature
Makefile run: docker run --rm --name $(NAME)-$(INSTANCE) $(LINK) $(PORTS) $(VOLUMES) $(ENV) $(NS)/$(REPO):$(VERSION) $ make run $ docker run --rm --name devnet-challenge-api-default --link mymongo:mongo -p 8080:10010 --env-file=.env ciscodevnet/devnet-challenge-api:v1
Node Libraries Used Swagger-node Express: Node HTTP server Bcrypt: Password hashing in DB Mongoose: Node mongo library Jsonwebtoken: JWT library Password-generator: generate random passwords Marked: Convert Markdown to HTML for docs
Swagger-node Runtime environment that includes Swagger Editor swagger project <command> Start Edit node app.js for proper deployments
Swagger Editor
My swagger-node workflow IDEA Swagger Edit Add/Edit Model & Controller Swagger test Make build & run Verify git add / commit / push shipped deploy
Anatomy of project Correspond to swagger properties: // swagger.yaml ├── Dockerfile ├── README.md ├── api │ ├── controllers │ │ ├── README.md │ │ ├── authenticate.controller.js │ │ ├── challenge.controller.js │ │ ├── challenge.model.js │ │ ├── health.controller.js │ │ ├── user.controller.js │ │ └── user.model.js │ ├── helpers │ │ └── mongoose │ │ ├── common-fields.js │ │ └── search.js │ ├── mocks │ │ └── README.md │ └── swagger │ └── swagger.yaml Correspond to swagger properties: // swagger.yaml x-swagger-router-controller operationId
# swagger.yaml paths: /users: x-swagger-router-controller: user.controller post: description: Create a user account operationId: createUser produces: - application/json parameters: - name: user in: body description: Your requested username required: true schema: $ref: "#/definitions/NewUser" responses: "201": description: "created user" $ref: "#/definitions/NewUserResponse" "400": description: Bad request (duplicate user) $ref: "#/definitions/ErrorResponse" default: description: "unexpected error" // user.controller.js exports.createUser = function(req, res) { }
var express = require('express'); app.use(express.static('static')); ├── app.js ├── config │ ├── README.md │ ├── default.yaml │ └── seeds │ └── basic.js ├── env_make ├── Makefile ├── package.json ├── static │ ├── css │ │ └── main.css │ └── howto.md └── test └── api ├── controllers │ ├── authenticate.js │ └── health.js └── helpers └── README.md // app.js var express = require('express'); app.use(express.static('static'));
Takeaways Swagger-node provides fast REST API creation Prototyping, mocking Spec-first development was an adjustment Container-based workflows made deployment super simple
Helpful Links https://communities.cisco.com/people/asroach/blog/2016/09/19/building-the-devnet-api- scavenger-hunt https://communities.cisco.com/people/asroach/blog/2016/08/11/creating-a-cisco-spark- membership-via-google-forms https://github.com/swagger-api/swagger-node https://github.com/CiscoDevNet/rest-api-swagger https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens http://blog.mongodb.org/post/32866457221/password-authentication-with-mongoose-part-1 http://www.itnotes.de/docker/development/tools/2014/08/31/speed-up-your-docker-workflow- with-a-makefile/ http://sahatyalkabov.com/how-to-implement-password-reset-in-nodejs/ https://marcqualie.com/2015/07/docker-dotenv
Thank you!