Date post: | 08-Jan-2017 |
Category: |
Software |
Upload: | ashley-roach |
View: | 163 times |
Download: | 8 times |
How I built a REST microservice
DevNet API Scavenger HuntAshley Roach – Cisco DevNetPrincipal 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
3
DevNet VisionHelp developers build solutions
and grow their careers.
Learn Code Inspire Monetize
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
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
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
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.
DockerfileFROM 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
My swagger-node workflowIDEA
Swagger Edit
Add/Edit Model &
Controller
Swagger test
Make build & runVerify
git add / commit /
push
shipped deploy
Verify
.├── 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│ │ ├── README.md│ │ └── mongoose│ │ ├── common-fields.js│ │ └── search.js│ ├── mocks│ │ └── README.md│ └── swagger│ └── swagger.yaml
Correspond to swagger properties:// swagger.yaml• x-swagger-router-
controller• operationId
Anatomy of project
# swagger.yamlpaths: /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" schema: $ref: "#/definitions/NewUserResponse" "400": description: Bad request (duplicate user) schema: $ref: "#/definitions/ErrorResponse" default: description: "unexpected error" schema: $ref: "#/definitions/ErrorResponse"
// user.controller.jsexports.createUser = function(req, res) { }
├── app.js├── config│ ├── README.md│ ├── default.yaml│ └── seeds│ └── basic.js├── env_make├── Makefile├── package.json├── static│ ├── css│ │ └── main.css│ └── howto.md└── test └── api ├── controllers │ ├── README.md │ ├── authenticate.js │ └── health.js └── helpers └── README.md
// app.jsvar express = require('express');app.use(express.static('static'));
• Swagger-node provides fast REST API creation• Prototyping, mocking• Spec-first development was an adjustment• Container-based workflows made deployment
super simple
Takeaways
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