class: center, middle # My Experience in Building [Swagger Editor](http://editor.swagger.io) # Use arrow keys to navigate → --- # About Me
### Mohsen Azimi #### Software Engineer @Apigee * Github: [`@mohsen1`](https://github.com/mohsen1) * Twitter: [`@mohsen____`](https://twitter.com/mohsen____) * Website: [`azimi.me`](http://azimi.me) --- class: center, middle # What is Swagger? ---  --- # Swagger API * #### API specification format --- # Swagger API * #### API specification format * #### Tools for generating documentation (Swagger UI) --- # Swagger API * #### API specification format * #### Tools for generating documentation (Swagger UI) * #### Tools for generating API spec from the code (Swagger Core) --- # Swagger API * #### API specification format * #### Tools for generating documentation (Swagger UI) * #### Tools for generating API spec from the code (Swagger Core) * #### Tools for consuming APIs in client side (SwaggerJS) --- # Swagger API * #### API specification format * #### Tools for generating documentation (Swagger UI) * #### Tools for generating API spec from the code (Swagger Core) * #### Tools for consuming APIs in client side (SwaggerJS) * #### Tools for generating server and client code from the specs --- # Swagger API * #### API specification format * #### Tools for generating documentation (Swagger UI) * #### Tools for generating API spec from the code (Swagger Core) * #### Tools for consuming APIs in client side (SwaggerJS) * #### Tools for generating server and client code from the specs * #### A lot of [community-driven projects](https://github.com/swagger-api/swagger-spec#additional-libraries) --- # Specs first or code first? --- # Specs first or code first?
Both!
--- class: center, middle # Show me the code --- # Swagger 1.2 [http://petstore.swagger.io/api/api-docs](http://petstore.swagger.io/api/api-docs) ```json apiVersion: "1.0.0", swaggerVersion: "1.2", apis: [ { path: "/pet", description: "Operations about pets" }, { path: "/user", description: "Operations about user" }, { path: "/store", description: "Operations about store" } ], authorizations: { .... ``` --- #####
pet.json
```json { "resourcePath": "/pet", "apis": [ { "path": "/pet/findByTags", "operations": [ { "method": "GET", "summary": "Finds Pets by tags", "responseMessages": [ { "code": 400, "message": "Invalid tag value" } ] } ] }, { "path": "/pet/{petId}", "operations": [ { "method": "PATCH", ... ``` --- class: center, middle # Swagger 2.0 --- # Swagger 2.0 * #### Single file for specification --- # Swagger 2.0 * #### Single file for specification * #### Tree view of the API --- # Swagger 2.0 * #### Single file for specification * #### Tree view of the API * #### More JSON Schema --- # Swagger 2.0 * #### Single file for specification * #### Tree view of the API * #### More JSON Schema * #### Introduction of JSON References --- # Swagger 2.0 * #### Single file for specification * #### Tree view of the API * #### More JSON Schema * #### Introduction of JSON References * #### Makrdown in descriptions --- # Swagger 2.0 * #### Single file for specification * #### Tree view of the API * #### More JSON Schema * #### Introduction of JSON References * #### Makrdown in descriptions * #### A JSON Hyper-Schema for validating Swagger 2.0 specs --- # Swagger 2.0 * #### Single file for specification * #### Tree view of the API * #### More JSON Schema * #### Introduction of JSON References * #### Makrdown in descriptions * #### A JSON Hyper-Schema for validating Swagger 2.0 specs * #### Fixes many issues raised by the community * #### YAML as first-class citizen --- class: center, middle # Show me the code --- #YAML for human ```yaml swagger: '2.0' info: version: 1.0.0 title: A simple API paths: /: get: responses: 200: description: OK ``` --- # JSON for machine ```json { "swagger": "2.0", "info": { "version": "1.0.0", "title": "A simple API" }, "paths": { "/": { "get": { "responses": { "200": { "description": "OK" } } } } } } ``` --- class: center, middle ### How should you make an API?
--- class: center, middle ### How should you make ~~an API~~
anything
?
--- class: center, middle ### How should you make ~~an API~~
anything
?
Design it first!
--- # Design First API Development --- # Design First API Development * ### Fast feedback loop --- # Design First API Development * ### Fast feedback loop * ### Well structured API --- # Design First API Development * ### Fast feedback loop * ### Well structured API * ### Collaborative development --- # Design First API Development * ### Fast feedback loop * ### Well structured API * ### Collaborative development * ### Well documented API --- # Design First API Development * ### Fast feedback loop * ### Well structured API * ### Collaborative development * ### Well documented API * ### Testable API --- class: center, middle ### Good design is only possible with good tools  --- # The case for an editor --- # The case for an editor * ### There was no tool for authoring Swagger specs with fast feedback loop --- # The case for an editor * ### There was no tool for authoring Swagger specs with fast feedback loop * ### Nobody have all the Swagger specs on top of their head to write an accurate specs * ### \* Not even [@webron](https://github.com/webron) or [@fehguy](https://github.com/fehguy) --- # The case for an editor * ### There was no tool for authoring Swagger specs with fast feedback loop * ### Nobody have all the Swagger specs on top of their head to write an accurate specs * * ### Other API specifications had authoring tools \* Not even [@webron](https://github.com/webron) or [@fehguy](https://github.com/fehguy) --- # Swagger Editor
A tool to enable design-first API development
Live documentations preview
Semantic and Schema error reporter
Syntactic error reporter
Code storage (local storage or a backend)
Import/Export Swagger specs in YAML and JSON
Can be hooked to a backend
Try operation
Documentation/Code fold sync
Code navigation
Authentication support
Tag navigation
--- class: center, middle # Starting the project and making choices --- class: center, middle
# Started with Yoeman --- class: center, middle
#AngularJS --- class: center, middle
# Pure JavaScript --- class: center, middle
#SwaggerUI for rendering (Initially) --- class: center, middle
#Ace for code editor --- class: center, middle
# Grunt for build tools --- class: center, middle
#JSHint --- class: center, middle
#JSCS --- class: center, middle
#Github for hosting the code and tracking issues --- # Editor workflow
--- # Editor workflow
--- class: center, middle # Easy! --- # Hacking it together
--- # It works!
--- class: center, middle # Spec changes on every keypress --- class: center, middle # Spec can be invalid --- class: center, middle ## User wants to know if their spec is invalid --- class: center, middle ## User wants to see errors in the specs --- # Challenges * ### Render fast * ### Keep typing smooth * ### Report errors --- # Challenges * ### Render fast * ### Keep typing smooth * ### Report errors --- # Rendering Fast * ### Rendering is not fast! Specially if spec is large. --- # Rendering Fast * ### Rendering is not fast! Specially if spec is large. * ### Throttling the render task is reasonable. --- # Rendering Fast * ### Rendering is not fast! Specially if spec is large. * ### Throttling the render task is reasonable. * ### AngularJS does not re-render entire HTML when scope changes partially, don't override the scope on each keypress --- # Keeping typing experience smooth * ### Throttling rendering task helps not blocking the UI while typing --- # Keeping typing experience smooth * ### Throttling rendering task helps not blocking the UI while typing * ### Parsing YAML and walking the spec tree for validation is expensive, let's throttle those too --- class: center, middle ### A lot of tasks should run when user stops changing the spec (Error checking, rendering and saving) ### Each task can fail in it's own way --- class: center, middle # Pub-Sub #### Publish–subscribe pattern --- # Pub-Sub --- # Pub-Sub * ### Each task(component) can emit an error --- # Pub-Sub * ### Each task(component) can emit an error * ### Error reporter will show errors to user no matter which component they are coming from --- # Pub-Sub * ### Each task(component) can emit an error * ### Error reporter will show errors to user no matter which component they are coming from * ### One component keeps the state of all tasks success --- # Change listening and change listeners ```js Storage.addChangeListener('yaml', update); ``` ```js this.addChangeListener = function (key, fn) { if (angular.isFunction(fn)) { if (!changeListeners[key]) { changeListeners[key] = []; } changeListeners[key].push(fn); } }; ``` [see this in Github](https://github.com/swagger-api/swagger-editor/blob/master/app%2Fscripts%2Fservices%2Flocal-storage.js#L46-L53) ---
--- # Challenges revisited * ### Render fast
✔
* ### Keep typing smooth
✔
* ### Report errors
✔
--- # A new problem
--- # A new problem ## JSON does not care about property
order
, therefore Swagger operation and responses may lose their order during YAML→JSON conversion --- class: center, middle # We need to sort object properties based on their position in YAML --- # Some processors sort keys alphabetically ```yml foo: jaz: 2 bar: 1 ``` ```json { "foo": { "bar": 1, "jaz": 2 } } ``` --- ### To sort properties based on their position in the YAML we need an abstract syntax tree (AST) of the YAML --- #### What is an AST?
--- ```yml foo: jaz: 2 bar: 1 ``` ```yaml value: value: "foo" start_mark: line: 0 column: 0 end_mark: line: 0 column: 3 value: value: "jaz" start_mark: line: 1 column: 2 end_mark: line: 1 column: 5 value: "2" start_mark: line: 1 column: 7 end_mark: .... ``` --- ### Using an array instead of objects to keep the order ```yaml /: get: ... post: ... ``` ```js { "post": { /* ... */ }, "get": { /* ... */ } } ``` ```js { "operations": [ { "operationsName": "get", /* ... */ }, { "operationsName": "post", /* ... */ } ] } ``` --- ## Sorting object keys
--- #### Complete workflow
--- # AST can do much more * ### Points to exactly where an error occurred (Jump to line) --- # AST can do much more * ### Points to exactly where an error occurred (Jump to line) * ### Points to exactly where a path, operation or parameter is located in code (Jump to YAML) --- # AST can do much more * ### Points to exactly where an error occurred (Jump to line) * ### Points to exactly where a path, operation or parameter is located in code (Jump to YAML) * ### Brings into the view the operation that is being edited currently --- ## Jump to line link when there is a YAML syntax error
--- # From YAML syntax error to line number YAML syntax error gives back the line number and column number ```json problem_mark: buffer: "swagger: '2.0'↵info:↵ version: 1.0.0↵ title: '..." column: 8 line: 3 pointer: 46 ``` --- class: center, middle # Easy! --- # Jump to line link when there is an error in Swagger spec
--- # Swagger errors are JSON Schema errors ### JSON Schema errors have: #### Line number in JSON #### JSON path to error --- class: center, middle # Line number in JSON is useless! --- ### Getting the line number from a JSON path
--- # AST walker * ### In-order tree walking --- # AST walker * ### In-order tree walking * ### Very cheap operation --- # AST walker * ### In-order tree walking * ### Very cheap operation * ### We need to update the AST when spec changes --- # Auto-completion * ### We needs to know possible keywords for current point (row, col) --- # Auto-completion * ### We needs to know possible keywords for current point (row, col) * ### Scanning the AST will give us where in the Swagger tree are we --- # Scanning the AST * ### Breadth first search (BFS) --- # Scanning the AST * ### Breadth first search (BFS) * ### Expensive operation --- # Scanning the AST * ### Breadth first search (BFS) * ### Expensive operation * ### Should fail gracefully --- # Providing suggestions based on JSON Path * ### A secondary tree that has list of possible keywords (Keyword map) --- # Providing suggestions based on JSON Path * ### A secondary tree that has list of possible keywords (Keyword map) * ### Walk the keyword map with that path and return all possible keywords --- # Providing suggestions based on JSON Path * ### A secondary tree that has list of possible keywords (Keyword map) * ### Walk the keyword map with that path and return all possible keywords * ### Keyword map can be extended with vendor extensions --- # Swagger Editor keyword map ```json { swagger: String, info: { version: String, title: String, description: String, termsOfService: String, contact: { name: String, url: String, email: String }, license: { name: String, url: String } } } ``` --- # Try this Operation
--- # Try this Operation * ## Request preview (body and URL) --- # Try this Operation * ## Request preview (body and URL) * ## Form for parameters and request body --- # Try this Operation * ## Request preview (body and URL) * ## Form for parameters and request body * ## Response preview (Raw, Pretty and Rendered) --- ### Making the form
--- # CORS * ### It's a big problem --- # CORS * ### It's a big problem * ### Online Swagger Editor is a web application --- # CORS * ### It's a big problem * ### Online Swagger Editor is a web application * ### There is no way to know if a request failed because of cross-origin policy --- # Moving out the client logic * ### UI should not make the calls --- # Moving out the client logic * ### UI should not make the calls * ### JSON Schema generation should be it's own module --- # Moving out the client logic * ### UI should not make the calls * ### JSON Schema generation should be it's own module * ### A stand-alone "Swagger Client" --- class: center, middle # Modules made for Swagger Editor --- # [`_.applyDiff`](https://github.com/mohsen1/apply-diff) * ## Updates an object deeply * ## Avoids any unnecessary overrides * ## Available as Lodash/Underscore plugin --- # [JSON Formatter](https://github.com/mohsen1/json-formatter)
--- # [JSON Formatter](https://github.com/mohsen1/json-formatter) * ## Angular directive for collapsible JSON in HTML * ## Available in Bower for AngularJS apps * ## Very popular (70 Github Stars) --- # [Angular JSON Schema Form](https://github.com/mohsen1/angular-json-schema-form) * ## Generate forms from JSON Schema * ## `ng-model` compatible * ## Available in Bower --- # [JSON Schema View](https://github.com/mohsen1/json-schema-view)
--- # [JSON Schema View](https://github.com/mohsen1/json-schema-view) * ## Similar to JSON Formatter * ## Renders JSON Schema in a nice collapsible format * ## AngularJS Directive available in Bower --- # [CORS it!](https://github.com/mohsen1/cors-it) * ## Tiny Node.js app for proxying cross-origin calls * ## Used to make it possible to import specs from anywhere in the online editor * ## Available in npm --- # [AngularJS Directive Yoeman Generator](https://github.com/mohsen1/generator-angular-directive) * ### Uses [Bower Publishable Angular Directive Boilerplate](https://github.com/mohsen1/angular-directive-boilerplate) * ### Easily bootstrap an AngularJS directive that can be published to the world * ### Project structure, build tools and tests --- class: center, middle # Questions?