diff --git a/docs/.gemspec b/docs/.gemspec new file mode 100644 index 0000000..ce94972 --- /dev/null +++ b/docs/.gemspec @@ -0,0 +1,20 @@ +# coding: utf-8 + +Gem::Specification.new do |spec| + spec.name = "docstrap-theme" + spec.version = "v1.0.1" + spec.authors = ["Osmar Reyes"] + spec.email = ["osmarreyesst@gmail.com"] + + spec.summary = %q{Docstrap documentation theme} + spec.description = "Docstrap is a open source theme for your documentation" + spec.homepage = "" + spec.license = "MIT" + + spec.files = git ls-files -z.split("\x0").select { |f| f.match(%r{^(assets|_layouts|_includes|_sass|LICENSE|README)}i) } + + spec.add_runtime_dependency "jekyll-seo-tag", "~> 2.0" + + spec.add_development_dependency "jekyll", "~> 3.3" + spec.add_development_dependency "bundler", "~> 1.12" + end \ No newline at end of file diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..45c1505 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,3 @@ +_site +.sass-cache +.jekyll-metadata diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 0000000..c472b4e --- /dev/null +++ b/docs/404.html @@ -0,0 +1,24 @@ +--- +layout: default +--- + + + +
+

404

+ +

Page not found :(

+

The requested page could not be found.

+
diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 0000000..0835083 --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,31 @@ +source "https://rubygems.org" + +# Hello! This is where you manage which Jekyll version is used to run. +# When you want to use a different version, change it below, save the +# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: +# +# bundle exec jekyll serve +# +# This will help ensure the proper Jekyll version is running. +# Happy Jekylling! +gem "jekyll", "~> 3.8.5" + +# This is the default theme for new Jekyll sites. You may change this to anything you like. +# gem "minima", "~> 2.0" + +# If you want to use GitHub Pages, remove the "gem "jekyll"" above and +# uncomment the line below. To upgrade, run `bundle update github-pages`. +# gem "github-pages", group: :jekyll_plugins + +# If you have any plugins, put them here! +group :jekyll_plugins do + gem "jekyll-feed", "~> 0.6" + gem 'jekyll-seo-tag' +end + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] + +# Performance-booster for watching directories on Windows +gem "wdm", "~> 0.1.0" if Gem.win_platform? + diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock new file mode 100644 index 0000000..e012109 --- /dev/null +++ b/docs/Gemfile.lock @@ -0,0 +1,68 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + colorator (1.1.0) + concurrent-ruby (1.1.6) + em-websocket (0.5.1) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0.6.0) + eventmachine (1.2.7) + ffi (1.12.2) + forwardable-extended (2.6.0) + http_parser.rb (0.6.0) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + jekyll (3.8.5) + addressable (~> 2.4) + colorator (~> 1.0) + em-websocket (~> 0.5) + i18n (~> 0.7) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (~> 1.14) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + jekyll-feed (0.13.0) + jekyll (>= 3.7, < 5.0) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-seo-tag (2.6.1) + jekyll (>= 3.3, < 5.0) + jekyll-watch (2.2.1) + listen (~> 3.0) + kramdown (1.17.0) + liquid (4.0.3) + listen (3.2.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + mercenary (0.3.6) + pathutil (0.16.2) + forwardable-extended (~> 2.6) + public_suffix (3.1.1) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + rouge (3.13.0) + safe_yaml (1.0.5) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + +PLATFORMS + ruby + +DEPENDENCIES + jekyll (~> 3.8.5) + jekyll-feed (~> 0.6) + jekyll-seo-tag + tzinfo-data + +BUNDLED WITH + 1.17.2 diff --git a/docs/LICENSE b/docs/LICENSE new file mode 100644 index 0000000..4ec2a9c --- /dev/null +++ b/docs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 rebelstackio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..885e408 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,63 @@ +# For technical reasons, this file is *NOT* reloaded automatically when you use +# 'bundle exec jekyll serve'. If you change this file, please restart the server process. + +# Site settings +# These are used to personalize your new site. If you look in the HTML files, +# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. +# You can create any custom variable you would like, and they will be accessible +# in the templates via {{ site.myvariable }}. +title: Expressif Documentation +email: osmarreyesst@gmai.com +description: >- # this means to ignore newlines until "baseurl:" + expressif is an opinionated wrapper and bootstrap for the express framework Routing that vastly simplifies creating self-documenting RESTful web services. It borrows (overtly) heavily from ayEs but opines further for the sake of simplifying the construction of RESTful APIs. +baseurl: "/expressif/" # the subpath of your site, e.g. /blog +url: "" # the base hostname & protocol for your site, e.g. http://example.com +twitter_username: jekyllrb +github_username: oreyes1991 +benefits: >- +
+ +

Secure

+

+ Authorization is handled using JWT and supports adding additional middleware to handle, for example, roles and/or permissions. +

+
+
+ +

Self documenting endpoints

+

+ expressif can handle self-documented endpoints, will deliver a JSON file with each endpoint information +

+
+links: >- + + docstrap logo + + + metaflux logo + +name: Expressif +repository: https://github.com/rebelstackio/expressif +discord: https://discord.gg/rj4UUErTnj +stackoverflow: \#linkto-so +themecolor: orange +clearlogo: assets/img/default-logo-white.png +darklogo: assets/img/default-logo.png + +# Build settings +markdown: kramdown +plugins: + - jekyll-feed + - jekyll-seo-tag + +# Exclude from processing. +# The following items will not be processed, by default. Create a custom list +# to override the default setting. +# exclude: +# - Gemfile +# - Gemfile.lock +# - node_modules +# - vendor/bundle/ +# - vendor/cache/ +# - vendor/gems/ +# - vendor/ruby/ diff --git a/docs/_includes/blog_menu.html b/docs/_includes/blog_menu.html new file mode 100644 index 0000000..8e1c56f --- /dev/null +++ b/docs/_includes/blog_menu.html @@ -0,0 +1,10 @@ + + {% for post in site.posts %} + + + {{post.title}} - + + + + {% endfor %} + \ No newline at end of file diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html new file mode 100644 index 0000000..a2ed9ae --- /dev/null +++ b/docs/_includes/footer.html @@ -0,0 +1,18 @@ + diff --git a/docs/_includes/header.html b/docs/_includes/header.html new file mode 100644 index 0000000..4aa7194 --- /dev/null +++ b/docs/_includes/header.html @@ -0,0 +1,31 @@ +
+ +
+ + + + +
+
+ + +
+
diff --git a/docs/_includes/sidebar.html b/docs/_includes/sidebar.html new file mode 100644 index 0000000..f7ae14e --- /dev/null +++ b/docs/_includes/sidebar.html @@ -0,0 +1,15 @@ +{% assign pages = site.pages | sort: "tabindex"%} + + + {% for page in pages %} + {% if page.layout == "docs" %} + +
+ + {{page.title}} + +
+
+ {% endif %} + {% endfor %} +
diff --git a/docs/_layouts/blog.html b/docs/_layouts/blog.html new file mode 100644 index 0000000..39cb1e8 --- /dev/null +++ b/docs/_layouts/blog.html @@ -0,0 +1,18 @@ +--- +layout: default +--- + +
+ {%- include blog_menu.html -%} + {{content}} +
+ {{page.date | date: "%b,%d %Y"}} +
+
+ + \ No newline at end of file diff --git a/docs/_layouts/community.html b/docs/_layouts/community.html new file mode 100644 index 0000000..433e77f --- /dev/null +++ b/docs/_layouts/community.html @@ -0,0 +1,7 @@ +--- +layout: default +--- + +
+ {{content}} +
diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 0000000..84cfcf9 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,46 @@ + + + + + + + {% seo %} + {{site.title}} + + + + + + + + {%- include header.html -%} +
+
+
+ {{ content }} +
+
+ {%- include footer.html -%} +
+ + + + + diff --git a/docs/_layouts/docs.html b/docs/_layouts/docs.html new file mode 100644 index 0000000..7d4a32e --- /dev/null +++ b/docs/_layouts/docs.html @@ -0,0 +1,18 @@ +--- +layout: default +--- + +
+ {%- include sidebar.html -%} + {{ content }} +
+ + \ No newline at end of file diff --git a/docs/_layouts/home.html b/docs/_layouts/home.html new file mode 100644 index 0000000..f51c27b --- /dev/null +++ b/docs/_layouts/home.html @@ -0,0 +1,27 @@ +--- +layout: default +--- + +
+
+
+
+

{{site.name}}

+

+ {{site.description}} +

+ +
+ default-logo +
+
+ {{site.benefits}} +
+ +
+
diff --git a/docs/_posts/2021-01-19-welcome-to-expressif.md b/docs/_posts/2021-01-19-welcome-to-expressif.md new file mode 100644 index 0000000..64a7c6d --- /dev/null +++ b/docs/_posts/2021-01-19-welcome-to-expressif.md @@ -0,0 +1,30 @@ +--- +layout: blog +title: "Welcome to Expressif" +categories: blog update +--- +# Welcome to the first entry of Expressif +We're implementing for the first time Documentation template (docstrap), we know there are a lot of improvements to do, but we feel proud of our first version, whit this template we now can create new blog entries for every new version updates or patch notes. +

+ +## How does it work? + +You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated. + +To add new posts, simply add a file in the `_posts` directory that follows the convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works. + +Jekyll also offers powerful support for code snippets: + +```ruby +def print_hi(name) + puts "Hi, #{name}" +end +print_hi('Tom') +#=> prints 'Hi, Tom' to STDOUT. +``` + +Check out the [Jekyll docs][jekyll-docs] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll Talk][jekyll-talk]. + +[jekyll-docs]: https://jekyllrb.com/docs/home +[jekyll-gh]: https://github.com/jekyll/jekyll +[jekyll-talk]: https://talk.jekyllrb.com/ diff --git a/docs/_sass/docstrap.scss b/docs/_sass/docstrap.scss new file mode 100644 index 0000000..287913b --- /dev/null +++ b/docs/_sass/docstrap.scss @@ -0,0 +1,79 @@ +@charset "utf-8"; +/*variables*/ +$custom-border-radius: 6px; +$clear-color: ghostwhite; +/* purple theme */ +$main-color: #84099e; +$main-color-light: rgba(132, 9, 158, .5); +/* default theme */ +$default-d-color: #09569e; +$default-d-color-light: rgba(9, 86, 158, .5); +/* orange theme*/ +$orange-color: #e48d0d; +$orange-color-light: rgba(228, 141, 13, .5); +/* fuchsia theme*/ +$fuchsia-color: #e91e63; +$fuchsia-color-light: rgba(233, 30, 99, .5); +/* dark theme*/ + +$dark-color: #333333; +$custom-blue: #00a4df; +$custom-red: #f56954; + +/*media querys*/ + +@mixin media-query($device) { + @media screen and (max-width: $device) { + @content; + } +} + +@mixin relative-font-size($ratio) { + font-size: $base-font-size * $ratio; +} + +@media only screen and (min-device-width: 300px) + and (max-device-width: 800px) + and (orientation: portrait) + { + .benefits { + grid-auto-flow: row !important; + row-gap: 10px; + padding: 0 10px !important; + } + .mobile-hidden { + display: none !important; + } + .main-header { + grid-template-columns: auto 1fr; + & .active { + display: none; + } + } + .footer img { + width: 3em; + } + .sumary { + grid-template-columns: unset !important; + & img { + grid-area: 1 / 1; + } + } + pretty-menu::after { + display: none !important; + } + .related > div { + grid-auto-flow: row !important; + } + .md-content{ + margin-left: unset !important; + } + } + + +/* import other sass files */ +@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap'); +@import + "docstrap/base", + "docstrap/theme_color.scss" +; diff --git a/docs/_sass/docstrap/base.scss b/docs/_sass/docstrap/base.scss new file mode 100644 index 0000000..0a55b7c --- /dev/null +++ b/docs/_sass/docstrap/base.scss @@ -0,0 +1,272 @@ +html, body { + font-family: 'Roboto', sans-serif; + background-color: $clear-color; + margin: 0; + padding: 0; + height: 100% +} + +body { + display: grid; + /* place-items: center; */ +} + +/*HEADER*/ + +.main-header { + position: fixed; + top: 0; + left: 0; + right: 0; + display: grid; + grid-template-columns: .5fr 4fr 1fr; + padding: 14px 10px; + background-color: $default-d-color; + color: #fff; + column-gap: 10px; + z-index: 100; + overflow-x: auto; + height: 98px; + box-sizing: border-box; + & .items{ + display: grid; + grid-auto-flow: column; + place-content: center start; + column-gap: 10px; + & > * { + position: relative; + cursor: default; + &.active::after { + position: absolute; + content: ""; + border-bottom: 2px solid rgba(255,255,255,.6); + left: 0; + right: 0; + bottom: -3px; + } + } + & > *:not(.active) { + color: rgba(255,255,255, .7); + cursor: pointer; + transition: color .3s ease; + user-select: none; + &:hover { + color: #fff; + } + } + } + & .logo > img { + padding: 10px; + box-sizing: border-box; + width: 70px; + } + & .logo { + place-content: center start; + align-items: center; + column-gap: 10px; + } + & .socials { + display: grid; + grid-auto-flow: column; + place-items:center; + & > div > * { + font-size: 2em; + cursor: pointer; + } + & > a { + color: #fff; + font-size: 28px; + &:hover { + color: rgba(255,255,255,.6); + } + } + } + & .item { + & > a { + color: inherit; + text-decoration: none; + } + } +} + +/*--------------------- main content ------------------------- */ + +.main-content { + display: grid; + max-width: calc(100vw); + margin-bottom: 239px; + padding: 10px 15px; + row-gap: 15px; + & > h2 { + margin: 15px 0; + text-align: center; + } +} + +.sumary { + display: grid; + grid-template-columns: 1fr 1fr; + background-color: #fff; + padding: 10px; + & > div { + padding: 0 15px; + color: #666; + & > p { + margin: 10px 0; + text-align: justify; + } + } + & > img { + width: 10em; + place-self: center; + } + & h1 { + color: $dark-color; + } + & pretty-button * { + font-size: 20px !important; + color: $default-d-color-light; + border-color: $default-d-color-light; + &:hover { + color: $default-d-color; + border-color: $default-d-color; + } + } +} + +.benefits { + display: grid; + grid-auto-flow: column; + column-gap: 10px; + background-color: rgba(252, 250, 226,.5); + text-align: justify; + padding: 0 15px; + & > * { + padding: 5px; + display: grid; + } + & .porperty > svg { + place-self: center; + font-size: 50px; + color: $default-d-color + } +} +.related { + display: grid; + text-align: center; + & > div { + display: grid; + grid-auto-flow: column; + place-items: center; + } + & img { + width: 150px; + cursor: pointer; + } +} + +.communication, .issues { + padding: 10px; +} + +.communication h3, .issues h3 { + margin: 10px + 0px; +} + +#content { + margin-top: 100px; + position: relative; +} + +.wrapper { + height: calc(100% - 101px); + display: grid; + margin-top: 101px; + overflow-y: auto; + position: relative; +} + +/*-----------------FOOTER-----------------*/ +.footer { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + background-color: #d9d9d9; + position: absolute; + bottom: 0; + place-content: center; + padding: 10px; + left: 0; + right: 0; + column-gap: 10px; + & img { + grid-area: 2 / 2; + width: 5em; + place-self: center; + } + & div { + display: grid; + place-self: center; + } + & a { + text-decoration: none; + color: var(--primary-bg); + transition: all .3s ease; + &:hover { + color: var(--primary-bg-hv); + } + } +} + +/*--------------------sidebar------------------------------------*/ + +pretty-menu-item { + & a { + color: inherit; + text-decoration: none; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + & .p-menu-item-box > div { + position: relative; + } +} + +pretty-menu::after { + position: absolute; +} +/*-------------------- DOCS CONTENT ------------------*/ +.md-content { + margin-left: 250px; + & ul { + padding-left: 20px; + } + &.no-menu { + margin-left: 0; + } +} + +.article-date { + padding: 10px 15px; + color: #666; + font-style: italic; +} + +main.page-content { + position: relative; +} + +code.highlighter-rouge { + padding: 0 5px; + background-color: #282c34; + margin: 5px; + color: #fff; +} + +*[class^=language-] { + margin-top: 10px; + margin-bottom: 10px; +} diff --git a/docs/_sass/docstrap/theme_color.scss b/docs/_sass/docstrap/theme_color.scss new file mode 100644 index 0000000..45818b8 --- /dev/null +++ b/docs/_sass/docstrap/theme_color.scss @@ -0,0 +1,56 @@ +/*--------------------------- themes----------------------------------- */ +/**/ +.docs-theme-purple{ + & .main-header { + background-color: $main-color !important; + } + & .sumary pretty-button * { + color: $main-color-light !important; + border-color: $main-color-light !important; + &:hover { + color: $main-color !important; + border-color: $main-color !important; + } + } + & .benefits .porperty > svg { + color: $main-color !important + } +} +/**/ +/**/ +.docs-theme-orange { + & .main-header { + background-color: $orange-color !important; + } + & .sumary pretty-button * { + color: $orange-color-light !important; + border-color: $orange-color-light !important; + &:hover { + color: $orange-color !important; + border-color: $orange-color !important; + } + } + & .benefits .porperty > svg { + color: $orange-color !important + } +} +/**/ +/**/ +.docs-theme-fuchsia{ + & .main-header { + background-color: $fuchsia-color !important; + } + & .sumary pretty-button * { + color: $fuchsia-color-light !important; + border-color: $fuchsia-color-light !important; + &:hover { + color: $fuchsia-color !important; + border-color: $fuchsia-color !important; + } + } + & .benefits .porperty > svg { + color: $fuchsia-color !important + } +} +/**/ +/*---------------------------END-THEMES-------------------------------*/ diff --git a/docs/assets/img/ServiceRequestFlow.svg b/docs/assets/img/ServiceRequestFlow.svg new file mode 100644 index 0000000..68781fd --- /dev/null +++ b/docs/assets/img/ServiceRequestFlow.svg @@ -0,0 +1,2 @@ + +
Validate Request

ayEs.reqvalidator#validate



[Not supported by viewer]
Authorise

ayEs.auth#parseAuthHeaders
ayEs.auth#decodeJWT

+ custom auth middleware
[Not supported by viewer]
Validate Parameters

ayEs.jsonvalidator#validateReq


+ JSON Schema
[Not supported by viewer]
Respond

ayEs.Respond#*



[Not supported by viewer]
Controller Middleware

  ayEs.Error#*
  ayEs.Respond#*

  + custom middleware
[Not supported by viewer]
\ No newline at end of file diff --git a/docs/assets/img/default-logo-white.png b/docs/assets/img/default-logo-white.png new file mode 100644 index 0000000..14ef5ac Binary files /dev/null and b/docs/assets/img/default-logo-white.png differ diff --git a/docs/assets/img/default-logo.png b/docs/assets/img/default-logo.png new file mode 100644 index 0000000..50c78ed Binary files /dev/null and b/docs/assets/img/default-logo.png differ diff --git a/docs/assets/img/docstrap-white.svg b/docs/assets/img/docstrap-white.svg new file mode 100644 index 0000000..681125e --- /dev/null +++ b/docs/assets/img/docstrap-white.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/img/docstrap.svg b/docs/assets/img/docstrap.svg new file mode 100644 index 0000000..b202228 --- /dev/null +++ b/docs/assets/img/docstrap.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/img/metaflux-logo-black.svg b/docs/assets/img/metaflux-logo-black.svg new file mode 100644 index 0000000..ddb1fdd --- /dev/null +++ b/docs/assets/img/metaflux-logo-black.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/docs/assets/js/index.js b/docs/assets/js/index.js new file mode 100644 index 0000000..abdf2af --- /dev/null +++ b/docs/assets/js/index.js @@ -0,0 +1,22 @@ +document.addEventListener('DOMContentLoaded', () => { + setActiveHeaderTab(); +}); + +/** + * On load set active tab to the top menu + */ +function setActiveHeaderTab() { + const { pathname } = document.location; + const tabName = getTabName(pathname); + changeHeaderActiveTab(tabName); +} +/** + * toggle active class to the header elementes + * @param {String} name tab name + */ +function changeHeaderActiveTab(name) { + const newActive = document.querySelector(`.main-header div[name="${name}"]`); + const prevActive = document.querySelector('.main-header .active'); + prevActive.classList.remove('active'); + newActive.classList.add('active'); +} \ No newline at end of file diff --git a/docs/assets/js/store.js b/docs/assets/js/store.js new file mode 100644 index 0000000..fb7c1ae --- /dev/null +++ b/docs/assets/js/store.js @@ -0,0 +1,13 @@ +window.storage = new Store( + { + //ini state + headerTabActive: 0 + }, + { + //handlres + CHANGE_VIEW: (action, state) => { + console.log(action) + return { newState: state } + } + } +); diff --git a/docs/assets/main.scss b/docs/assets/main.scss new file mode 100644 index 0000000..676a760 --- /dev/null +++ b/docs/assets/main.scss @@ -0,0 +1,5 @@ +--- +# Only the main Sass file needs front matter (the dashes are enough) +--- + +@import "docstrap"; \ No newline at end of file diff --git a/docs/blog.md b/docs/blog.md new file mode 100644 index 0000000..a254463 --- /dev/null +++ b/docs/blog.md @@ -0,0 +1,13 @@ +--- +layout: blog +permalink: /blog/ +date: 2021-01-19 14:26:46 -0500 +author: Osmar Reyes +--- + +# Expressiff blog Overview + +Welcome to the blog for Expressif, here the dev team will be leaving their thoughts, ideas, or just some explanation, the obstacles, and here you will be able to see the core, the heart of the beast, as we update this library will highlight pieces of code, sketches or diagrams that help us to conquer our goal. + +We love this community, that's why Expressif is open source, we want you to get involved, to help us improve, perhaps report a bug in our [repository](https://github.com/rebelstackio/expressif), or just forked and play with it and if you can improve something you can feel free to create a pull request, connect to our [discord](https://discord.gg/rj4UUErTnj) channel and pitch your ideas. + diff --git a/docs/community.md b/docs/community.md new file mode 100644 index 0000000..8a92867 --- /dev/null +++ b/docs/community.md @@ -0,0 +1,12 @@ +--- +layout: community +title: Community +permalink: /community/ +--- + +### Communication +The Expressif community is most readily found on its [Discord](https://discord.gg/rj4UUErTnj) + +### Issues +Github is used for tracking issues. The primary location for these is the main [Expressif repository](https://github.com/rebelstackio/expressif/issues). +If you’re a Expressif user, you’re highly encouraged to keep an eye on these issues and jump in on the discussions, to help us understand how to design tradeoffs that might affect you. diff --git a/docs/docs/api.md b/docs/docs/api.md new file mode 100644 index 0000000..48ca516 --- /dev/null +++ b/docs/docs/api.md @@ -0,0 +1,673 @@ +--- +layout: docs +title: Api Reference +permalink: /docs/api/ +tabindex: 2 +--- + +# Api Reference +

+ +## Auth API +

+ +### new ayEs#Auth(String jwtsecret, Object options) -> Object ayEs#auth +Create `ayEs#Auth` instance. +

+ +__options__ + +* _logger_: A custom logger for the instance to use. +

+ +### Auth#decodeJWT(String jwt, String jwtsecret) -> Object +Decodes the given `jwt` string and returns the jwt payload as an object. Throws an error if `jwt` is not valid. +

+ +### Auth#decodeErr(Object) -> Object ayEs#Error +Helper function that take the error object returned by `Auth#decodeJWT` and parses it to a custom [`ayEs#Error#AuthError`](#new-errorautherrorstring-message-string-code---object) type with relevant error code and message. +

+ +### Auth#encodeJWT(Object payload, String jwtsecret) -> String +Returns a JWT string with `payload`, signed with the given secret key `jwtsecret`. +

+ +### ayEs#returnAuthInstance(String jwtsecret, Object options) -> Object ayEs#auth +Helper factory function that returns an `ayEs#Auth` instances. +

+ +### ayEs#auth#generateAuthMiddleWare() -> Function +Returns the auth middleware function. + +This is exposed so that you can add additional authentication middleware if required. + +```js +const authMiddleware = []; +authMiddleware.push(auth.generateAuthMiddleWare()); +authMiddleware.push(someOtherAuthFunction); +const routerOptions = { + auth: auth, // auth property can be an array of functions. + routes: [ ... ] +} +``` +

+ +## Error +A set of custom error objects for use in controller middleware to standardise error responses. + +All `Error` constructors accept a code parameter that can be used to pass in a code string as a non-verbose mechanism to give more specific detail about an error (see [error codes](#errorcodes)). + +ayEs error objects are intended for use along side the [response](#response) library to form a standard error response to api request. +

+ +### Error API + +#### new Error#BadRequestError(String message, String code) -> Object +Returns an `BadRequestError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 400; +``` +

+ +#### new Error#NotFoundError(String message, String code) -> Object +Returns an `NotFoundError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 404; +``` +

+ +#### new Error#BadHeaderError(String message, String code) -> Object +Returns an `BadHeaderError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 400; +``` +

+ +#### new Error#AuthError(String message, String code) -> Object +Returns an `AuthError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 401; +``` + +This is intended for authentication errors, not authorisation errors (see [Error#ForbiddenError](#new-errorforbiddenerrorstring-message-string-code---object)) +

+ +#### new Error#ForbiddenError(String message, String code) -> Object +Returns an `ForbiddenError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 403; +``` +

+ +#### new Error#UnauthorizedError(String message, String code) -> Object +Returns an `UnauthorizedError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 401; +``` +This is intended for authentication errors, not authorisation errors (see [Error#ForbiddenError](#new-errorforbiddenerrorstring-message-string-code---object)) +

+ +#### new Error#UnavailableRetryError(String message, String code, String retryafter) -> Object +Returns an `UnavailableRetryError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 503; + error.retryafter = retryafter; +``` +This error includes a `retryafter` property to indicate a wait period until retrying to access the service. Can be used for temporary unavailability, such as cache updates. +

+ +#### new Error#ConflictError(String message, String code) -> Object +Returns an `ConflictError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 409; +``` +

+ +#### new Error#DataBaseReturnError(String message, String code) -> Object +Returns an `DataBaseReturnError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 500; +``` +

+ +#### new Error#JSONValidationError(String message, Object errorData, String code) -> Object +Returns an `JSONValidationError` instance with properties +```js + error.message = message; + error.code = code; + error.httpstatus = 400; + error.info = errorData; +``` +This error is used by the [`JSONValidator`](#jsonvalidator) lib to return errors on validation. The validation error data is passed in the `info` property. +

+ +### Server Errors +There are a set of errors that wrap server errors and are passed the original error as a parameter to the constructor. This error object is then available on the `errObj` property. +

+ +#### new Error#DataBaseError(Object errobj, String message, String code) -> Object +Returns an `DataBaseError` instance with properties +```js + error.message = message; + error.errObj = errobj; + error.code = code; + error.httpstatus = 500; +``` +

+ +#### new Error#ServerError(Object errobj, String message, String code) -> Object +Returns an `ServerError` instance with properties +```js + error.message = message; + error.errObj = errobj; + error.code = code; + error.httpstatus = 500; +``` +

+ +#### new Error#FBError(Object errobj, String message, String code) -> Object +Returns an `FBError` instance with properties +```js + error.message = message; + error.errObj = errobj; + error.code = code; + error.httpstatus = 500; +``` +

+ +#### new Error#AWSError(Object errobj, String message, String code) -> Object +Returns an `AWSError` instance with properties +```js + error.message = message; + error.errObj = errobj; + error.code = code; + error.httpstatus = 500; +``` +

+ +### Error#codes +Most times an error is sent back to a client along with a message to give more detail of the cause of the error. A `400 Bad Request` status does not let the client know what was incorrect in the request, so a message is added to clarify, "Email parameter must be a valid email". + +There are two good cases when it might be better to replace that message with a code instead. +* We care about bandwidth and want to send less bytes across the wire, +* we want to inform the client app of an error but not a user who might read the response content. + +For this purpose `atEs` includes the concept of error codes that can be passed to the custom error constructors that give a little more detail about the error cause. These codes are read by the `ayEs#response` functions and a custom header, `X-Error-Code`, is added with the code. This can be read by developers or client applications for greater granularity of errors without verbose strings over the wire. +

+ +#### codes +See available codes and their meanings [here](lib/error/codes.js). + +__TODO__ Allow for code customisation. +

+ +## JSONValidator +A wrapper for the [AJV](https://github.com/epoberezkin/ajv) JSON schema validation library used to validate request parameters. +

+ +The idea here is to create an instance of the `ayEs#JSONValidator` and register a set of JSON schema that can be used in route configuration. So, given a JSON schema for validating login parameters with an `$id` property of `postloginin`, such as +```js +const authReqSchema = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: 'postloginin', + title: 'Login Object', + type: 'object', + properties: { + email: { + title: 'user email', + type: 'string', + format: 'email' + }, + username: { + title: 'username', + type: 'string' + }, + password: { + title: 'user password', + type: 'string', + minLength: 5, + maxLength: 400 + } + }, + required: ['username', 'password'] +}; +``` +we can instantiate the validator either by passing the schema to the constructor +```js +const JSONValidator = ayEs.JSONValidator; +const jv = new JSONValidator(authReqSchema); +``` +or using the `JSONValidator#addSchema` instance function +```js +const JSONValidator = ayEs.JSONValidator; +const jv = new JSONValidator(); +jv.addSchema(authReqSchema); +``` +

+ +Now, this instance can be assigned to the [`Router#options#jsonv`](#options) property and the registered schema can be referenced in a route configuration as `validreq: 'postloginin'` +```js +{ + jsonv: jv, + routes: [ + { + method: 'post', + path: '/login', + mwares: loginController, + validreq: 'postloginin' // Reference the schema here + } + ] +} +``` +The router library will now add a validation middleware for request parameters using the schema indicated. Any failure against the schema is wrapped in a [`Error#JSONValidationError`](#new-errorjsonvalidationerrorstring-message-object-errordata-string-code---object) and reported back to the client using [`Respond#invalidRequest`](#invalidRequest). +

+ +#### $ref in JSON schema +If you use the [`$ref` property](https://spacetelescope.github.io/understanding-json-schema/structuring.html) in your JSON schema to reference common definitions in a separate schema file we must pass that to our `ayEs#JSONValidator` instance in a slightly different way. This is due to how it is passed to the underlying [`ajv` library](https://github.com/epoberezkin/ajv#ref). +

+ +First add all the definition schemas into the array of schemas you wish to register with the validator and then wrap the array into an options object. +```js +// schemas/defs.json +{ + "$id": "defs", // Id used to reference this schema in other schemas + "definitions": { + "username": { + "title": "Username", + "type": "string", + "pattern": "^[a-zA-Z0-9\\-_.]{3,25}$" + } + } +} + +// schemas/user.json +[{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "GET User Params", + "type": "object", + "required": ["username"], + "properties": { + "username": { "$ref": "defs#/definitions/username" } + } +}] + +// routes/user.js +const JSONValidator = ayEs.JSONValidator; +const ds = require('schemas/defs'); +const su = require('schemas/user'); + +su.push(ds); +const jvoptions = { schemas: su }; +const jv = new JSONValidator(null, jvoptions); +``` +

+ +## Respond +A wrapper lib for the [`Express#res.send`](https://expressjs.com/en/4x/api.html#res.send) function. All responses are standardised. Data returned for a successful request can be wrapped with `respond#wrapSuccessData()` before being passed to `respond#success()` to be returned to the requestor. +

+ +```js +const ayEs = require('ayes'); +const respond = ayEs.respond; + +// controller for /login route +const loginController = function loginController(req, res) { + const { username, password } = req.body; + if (password) { + const response = { + id: Math.floor(Math.random() * 6) + 1, + username + }; + respond.success(res, req, respond.wrapSuccessData(response, req.path)); + } +}; + +// Responds to requester with JSON body +{ + "data": { + "id": 2, + "username": "nectarsoft" + }, + "path": "/login" +} +``` + +### Respond API +#### respond#forbidden(Object response, Object Request, Object Error) +Will respond to the requestor with http status `403`. +

+ +The last parameter is intended to be a custom `ayEs#Error` object and can include `message`, `httpstatus` and `code` properties. +

+ +If `httpstatus` is present, this will be used in place of `403`. +

+ +The `code` property is anticipated to be one of ['ayes#Error#codes](#errorcodes) and if present `respond#forbidden` returns an empty body and includes the custom header `X-Error-Code` set to the value of `code`. +

+ +If `code` is not present a response body is sent using the `message` property from the `Error` parameter if present or 'Forbidden' if not. +```js +{ + "data": { + "message": "Forbidden" // Or Error.message is present + }, + "type": "ForbiddenError" +} + +``` +

+ +#### respond#invalidRequest(Object response, Object Request, Object Error) +This response is intended to pass back information about any invalid request so a requester can amend and resubmit their failed request. +

+ +Any information to be passed to the requester can be attached to the `Error.info` property of the last parameter. +

+ +So, for example, if used in conjunction with an [`Error#JSONValidationError`](#new-errorjsonvalidationerrorstring-message-object-errordata-string-code---object) returned by the [`ayEs#JSONValidator`](#jsonvalidator) library we get a response body of the form +```js +response.invalidRequest(response, request ,JSONValidationError); +// Returns a request body of e.g. +{ + "data": { + "message": "JSON validation errors were found against schema: postloginin", + "info": [ + { + "keyword": "required", + "dataPath": "", + "schemaPath": "#/required", + "params": { + "missingProperty": "password" + }, + "message": "should have required property 'password'" + } + ] + }, + "type": "JSONValidationError", + "code": 400.43 +} +``` +

+ +#### respond#notAuthorized(Object response, Object Request, Object Error) +Will respond to the requestor with http status [`401`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401) and set the `WWW-Authenticate` header to `Bearer token_path="JWT"`. + +The last parameter is intended to be a custom `ayEs#Error` object and can include `message`, `httpstatus` and `code` properties. + +If `httpstatus` is present, this will be used in place of `401`. + +The `code` property is anticipated to be one of ['ayes#Error#codes](#errorcodes) and if present `respond#notAuthorized` returns an empty body and includes the custom header `X-Error-Code` set to the value of `code`. + +If `code` is not present a response body is sent using the `message` property from the `Error` parameter if present or 'Authorisation error' if not. +```js +{ + "data": { + "message": "Authorisation error" // Or Error.message is present + }, + "type": "Not_Authorized_Error" // Or Error Constructor name. +} +``` +

+ +#### respond#notFound(Object response, Object Request, Object Error) +Will respond to the requestor with http status [`404`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404). + +The last parameter is intended to be a custom `ayEs#Error` object and can include `message`, `httpstatus` and `code` properties. + +If `httpstatus` is present, this will be used in place of `404`. + +The `code` property is anticipated to be one of ['ayes#Error#codes](#errorcodes) and if present `respond#notFound` returns an empty body and includes the custom header `X-Error-Code` set to the value of `code`. + +If `code` is not present a response body is sent using the `message` property from the `Error` parameter if present or 'Resource not found' if not. +```js +{ + "data": { + "message": "Resource not found" // Or Error.message is present + }, + "type": "Not_Found_Error" // Or Error Constructor name. +} + +``` +

+ +#### respond#notImplemented(Object response, Object Request, Object Error) +Will respond to the requestor with http status [`501`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501). + +The last parameter is intended to be a custom `ayEs#Error` object and can include `message`, `httpstatus` and `code` properties. + +If `httpstatus` is present, this will be used in place of `501`. + +The `code` property is anticipated to be one of ['ayes#Error#codes](#errorcodes) and if present `respond#notImplemented` returns an empty body and includes the custom header `X-Error-Code` set to the value of `code`. + +If `code` is not present a response body is sent using the `message` property from the `Error` parameter if present or 'Not Implemented' if not. +```js +{ + "data": { + "message": "Not Implemented" // Or Error.message is present + }, + "type": "Not_Implemented_Error" // Or Error Constructor name. +} + +``` +

+ +#### respond#redirect(Object response, Object headers, Number statusCode, String noWrapDataStr) +Will respond to the requestor with http status [`307`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307). +

+ +The headers parameter should contain key value pairs of header names and values that will be added to the response. Typically this will include the `Location` header with an URL intended for the redirect. +

+ +If `httpstatus` is present, this will be used in place of `307`. +

+ +#### respond#serverError(Object response, Object Request, Object Error) +Will respond to the requestor with http status [`500`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500). +

+ +The last parameter is intended to be a custom `ayEs#Error` object and can include `message`, `httpstatus` and `code` properties. +

+ +If `httpstatus` is present, this will be used in place of `500`. +

+ +The `code` property is anticipated to be one of ['ayes#Error#codes](#errorcodes) and if present `respond#serverError` returns an empty body and includes the custom header `X-Error-Code` set to the value of `code`. +

+ +If `code` is not present a response body is sent using the `message` "Unexpected Error" if not and setting the type to "Server_Error". +```js +{ + "data": { + "message": "Unexpected Error" + }, + "type": "Server_Error" // Or Error Constructor name. +} + +``` +

+ +#### respond#success(Object response, Object request, Object WrappedData, Number HttpStatus) +Will respond to the requestor with http status [`200`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200). +

+ +If `HttpStatus` parameter is present this will be used in place of `200`. +

+ +If `WrappedData` if present it is used to build the response object, passing the data as teh `data` property of the response an either a `path` property, if one exists on the `wrappedData` object, or `type` property if not. + +```json +{ + "data": { + "id": 2, + "username": "nectarsoft" + }, + "path": "/login" +} +// Or +{ + "data": { + "id": 2, + "username": "nectarsoft" + }, + "type": "success" +} +``` +

+ +If no `WrappedData` parameter is passed `respond#success` will return an empty body, but still use http status `200` and not [`204`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204). +

+ +#### respond#unavailableRetry(Object response, Object Request, Object Error) +Will respond to the requestor with http status [`503`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503). +

+ +The last parameter is intended to be a custom `ayEs#Error` object and can include `message`, `httpstatus`, `retryafter` and `code` properties. +

+ +This response will set the `Retry-After` header to either the number 1 or a value passed in the `Error#retryafter` property. +

+ +If `httpstatus` is present, this will be used in place of `503`. +

+ +The `code` property is anticipated to be one of ['ayes#Error#codes](#errorcodes) and if present `respond#unavailableRetry` returns an empty body and includes the custom header `X-Error-Code` set to the value of `code`. +

+ +If `code` is not present a response body is sent using the `message` property from the `Error` parameter if present or 'Service temporarily unavailable. Please retry' if not. +```js +{ + "data": { + "message": "Service temporarily unavailable. Please retry" // Or Error.message is present + }, + "type": "Service_Unavailable_Please_Retry" // Or Error Constructor name. +} + +``` +

+ +#### respond#wrapSuccessData(Object Data, String path, Object options) +A function to wrap the return data into an options object for the `respond#success` function. +

+ +```javascript +const wrappedData = Respond.wrapSuccessData(response, req.path, { stripNull: true }); +Respond.success(res, req, wrappedData); +``` +

+ +__options__ +* stripNull : Boolean flag to pass to the `respond#success` function to indicate that any value in the data object with a null value should not be returned to the requester. +

+ +## Reqvalidator +A peculiar beast used for validating request formats. TODO. +

+ +## Router +#### Router#buildRouter(Object options) -> Express#Router +Build an Express Router instance containing endpoints for each of the routes configured in the `options.routes` +

+ +##### options +* _addOptionsRoute_: Boolean flag to indicate whether to add an `options` endpoint that returns a documentation JSON as described [here](#self-documenting-endpoints). Defaults to `false`. +* _auth_: This options takes an instance of [ayEs#Auth](#Auth).If present at this level the authentication middleware will be added to all endpoints configured in the `routes` array. +* _jsonv_: This option takes an instance of the [ayEs#JSONValidator](#JSONValidator). If present, route configurations (in the routes option array) can indicate a json schema registered with the validator to use to validate request parameters. +* _routes_: An array of endpoint configuration objects. Each object in the array will be used to build and add one endpoint to the returned `Express#Router`. Route configuration options are: + * _auth_: an instance of [ayEs#Auth](#Auth).If present at this level the authentication middleware will be added to only the endpoints configured in this route config. Clearly this will be overidden by any `Auth` instance in the `options.auth` option (which applies to all routes). If only some routes are required to be authenticated, or ypu wish to use a different authentication instance for any route, no `options.auth` option should be declared and the `auth` options set at the route configuration level for all authenticated routes. + * _method_: The [HTTP method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) for this endpoint. + * _mwares_: An array of express middleware functions (or single function) for this endpoint. These middleware functions will be added to the router AFTER any authentication and validation middlewares that are generated by the `Auth` and/or `JSONValidator` instances in the `auth` or `jsonv` options. + * _path_: The path for this endpoint. This can be any string excepted as an express route path (see [here](https://expressjs.com/en/guide/routing.html#route-paths)) + * _rxvalid_: A list of request validation requirements. __TODO__ Refactor this interface. + * _validreq_: A string identifier for a JSON schema registered with the `ayEs#JSONValidator` instance set as the `options.jsonv` option. The schema will be used to validate the request parameters to this endpoint. See [JSONValidator](#JSONValidator) for more details. + * _validres_: A string identifier for a JSON schema registered with the `ayEs#JSONValidator` instance set as the `options.jsonv` option. This is currently only used when [generating the documentation JSON](#self-documenting-endpoints) for the `OPTIONS` route. See [JSONValidator](#JSONValidator) for more details. +

+ +### Self documenting endpoints +If the flag `addOptionsRoute` is set on the options object passed to the `Router#buildRouter` function, it will add an `OPTIONS` endpoint at the root URL for that router that will return a `JSON` containing information about all routes within the router. This will include a `data` property that is an object whose property keys are the available paths for the router. Each path will have an array of objects describing each available verb for that path with the following properties: +

+ +* _verb_: HTTP method +* _validations_: What validations are carried out on the request format. Currently this will list required headers. +* _body_schema_: A JSON schema for the parameters for this request. +* _response_: A JSON schema describing the response for this endpoint. + +```json +{ + "data": { + "/login": [{ + "verb": "post", + "validations": { + "headers": { + "Accept": "application/json", + "Content-Type": "application/json" + } + }, + "body_schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "postloginin", + "title": "Login Object", + "type": "object", + "properties": { + "email": { + "title": "user email", + "type": "string", + "format": "email" + }, + "username": { + "title": "username", + "type": "string" + }, + "password": { + "title": "user password", + "type": "string", + "minLength": 5, + "maxLength": 400 + } + }, + "required": ["username", "password"] + }, + "response": { + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "postloginout", + "title": "Login Object", + "type": "object", + "properties": { + "id": { + "title": "user id", + "type": "string" + }, + "username": { + "title": "username", + "type": "string" + }, + "role": { + "title": "user role", + "type": "number" + } + }, + "required": ["id", "username", "role"] + } + }] + }, + "path": "/" +} +``` diff --git a/docs/docs/examples.md b/docs/docs/examples.md new file mode 100644 index 0000000..d31d80e --- /dev/null +++ b/docs/docs/examples.md @@ -0,0 +1,43 @@ +--- +layout: docs +title: Examples | Tutorials +permalink: /docs/examples/ +tabindex: 3 +--- + +# Examples + +## How to set your config file + +In the root of your generated template, you will see a _config.yml, this file is the main configuration file and should look something like this +```yml +title: Site Name +email: your@emal.com +description: >- # this means to ignore newlines until "baseurl:" + site description +baseurl: "/" # the subpath of your site, e.g. /blog +url: "" # the base hostname & protocol for your site, e.g. http://example.com +twitter_username: twitter_user +github_username: github_user +benefits: >- + bennefits of your project +links: >- + related links +name: Docstrap +repository: link to your repository +discord: linkto to your discord +stackoverflow: link to stackaoverflow +# Build settings +markdown: kramdown +plugins: + - jekyll-feed + - jekyll-seo-tag + +``` +this file will be parsed to the template with the variable site, so if you want to reference the property title in this file it will be ```site.title``` + +## How to set this to your Github pages? +The template is made in Jekyll, so you don't need to build every addition to the docs files, the template should be in the branch pointing your Github pages. +Let's say our gh-pages URL is ```gh_user.hithub.io/repo_name/``` our Jekyll template is using relative_url that means the folder structure for your site will be constructed as ```site.baseurl + url```. +By default ```baseurl: "/"``` so you will need to set it to ```baseurl: "/repo_name/"```, it is important to have both slashes at the beginning and end. + diff --git a/docs/docs/faq.md b/docs/docs/faq.md new file mode 100644 index 0000000..3119924 --- /dev/null +++ b/docs/docs/faq.md @@ -0,0 +1,7 @@ +--- +layout: docs +title: FAQ +permalink: /docs/faq/ +tabindex: 4 +--- +# Frequently asked questions \ No newline at end of file diff --git a/docs/docs/getting_started.md b/docs/docs/getting_started.md new file mode 100644 index 0000000..72b531c --- /dev/null +++ b/docs/docs/getting_started.md @@ -0,0 +1,111 @@ +--- +layout: docs +title: Getting Started +permalink: /docs/getting-started/ +tabindex: 1 +--- + +## Instalation +```bash +npm i @rebelstack-io/expressif +``` + +## Using expressif +```js +/* Bootstrap a server */ +const {Server} = require('expressif'); +let myserver = new Server(/* config, globals */); + +/* Create a sample login controller to deal with login requests. + * PLEASE NOTE: This is not a recommended login strategy for production sites. +*/ +const loginController = function loginController(req, res) { + const { username, password } = req.body; + if (password) { + const response = { + id: Math.floor(Math.random() * 6) + 1, + username + }; + res.status(200).send(response); + } +}; +/** + * The buildRouter helper function takes a configuration object with an + * array of route definitions. +*/ +const arouterdata = { + routes: [ + { + method: 'post', + path: '/login', + mwares: loginController + } + ] +}; +/** + * Call the Router#buildRouter function returns an express router with routes + * for each configuration in the routes array. +*/ +const authRouter = Router.buildRouter(arouterdata); +``` + +Okay, but so far this is just a wrapper for the `Express#Router`. It gives us a nice clean format for router definitions, easy to read and reason about. Now let's add more support for the [request flow](#at-your-express-service) outlined above. + +## Auth +ayEs provides an implementation of authentication by [JWT](https://jwt.io/) through the `Auth` lib. If an endpoint or a set of endpoints grouped into a router instance requires authentication, create and instance of the `ayEs#Auth` handler and pass it to the route configuration. +```js +const ayEs = require('ayes'); +const Auth = ayes.Auth; +const auth = new Auth(process.env.JWT_SECRET); +// Or use the factory function +const auth = ayEs.returnAuthInstance(process.env.JWT_SECRET); +const routerOptions = { + routes: [ + { + auth: auth, //Pass the auth instance here to authenticate just the /me endpoint. + method: 'post', + path: '/me', + mwares: getMe //A controller function + }, ... + ] +} +``` +If all routes for a particular router require authentication, simply pass the auth instance on the `options.auth` property of the router configuration instead. +```js +const routerOptions = { + auth: auth, //Pass the auth instance here to authenticate all routes by JWT. + routes: [ + { + method: 'post', + path: '/me', + mwares: getMe //A controller function + }, + { + method: 'put', + path: '/some/other/authenticated/route', + mwares: anotherController + } + ] +} +``` + +Request to endpoints configured with the `ayEs#Auth` lib must send in an `Authorization: Bearer ` header with a valid JWT to access the service. + +The lib adds an express middleware function to the route that will handle JWT validation for authentication. This middleware decodes the JWT present in the request's `Authorization` header, returning errors on failed validation. If the JWT is present and valid, the JWT payload is added to the express request object as the `dtoken` property, so you can access it inside any subsequent middleware. + +```js +/** + * With a JWT payload of + * { + * "exp": "2018-03-01T04:49:49.781Z", + * "user": { + * "id": "596dcd99dd19f9227f5a94b1", + * "username": "nectarsoft" + * } + * } +*/ +function (req, res) { + const username = req.dtoken.user.username; + console.log(username) // nectarsoft +} +``` diff --git a/docs/docs/overview.md b/docs/docs/overview.md new file mode 100644 index 0000000..9797e0f --- /dev/null +++ b/docs/docs/overview.md @@ -0,0 +1,18 @@ +--- +layout: docs +title: Overview +permalink: /docs/overview/ +tabindex: 0 +--- + +# Wath is Expressif? + +[![Build Status](https://travis-ci.com/rebelstackio/expressif.svg?branch=develop)](https://travis-ci.com/rebelstackio/expressif) + +expressif is an opinionated wrapper and bootstrap for the express framework(https://expressjs.com/en/guide/routing.html) that vastly simplifies creating self-documenting RESTful web services. It borrows (overtly) heavily from [ayEs](https://github.com/rebelstackio/ayEs) but opines further for the sake of simplifying the construction of RESTful APIs. +
+
+The request flow goes through `authorize` -> `validate request structure` -> `validate request parameters` -> `controller middleware` -> `response`. +

+ +![Service Request Flow]({{ site.baseurl }}{% link /assets/img/ServiceRequestFlow.svg %}) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..e15ffc7 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,7 @@ +--- +# Feel free to add content and custom Front Matter to this file. +# To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults + +layout: home +--- +# Docstrap