diff --git a/docs/adr/0001-record-architecture-decisions.md b/docs/adr/0001-record-architecture-decisions.md index c1fb92e..bafc453 100644 --- a/docs/adr/0001-record-architecture-decisions.md +++ b/docs/adr/0001-record-architecture-decisions.md @@ -26,6 +26,8 @@ We need to record the architectural decisions made on this project, since: We will document every architecture-level decision for `getting-started-inner-source` and its core modules with an [Architecture Decision Record][nygard-article-url]. These are a well structured, relatively lightweight way to capture architectural proposals. They can serve as an artifact for discussion, and remain as an enduring record of the context and motivation of past decisions. +### Architecture decision workflow + The workflow will be: 1. A community member creates an ADR document outlining an approach for a particular question or problem. The ADR has an initial status of "proposed." diff --git a/docs/developer-guide/README.md b/docs/developer-guide/README.md index 6fc96ae..83cb9db 100644 --- a/docs/developer-guide/README.md +++ b/docs/developer-guide/README.md @@ -2,6 +2,23 @@ > code This guide is for those who want to contribute code to `getting-started-inner-source`. This guide describes how to set up your development environment so that you can build and test `getting-started-inner-source`. +## Table of contents + + + +- [1. Recommended skills](#1-recommended-skills) +- [2. Development software](#2-development-software) +- [3. Getting the source code](#3-getting-the-source-code) +- [4. Installing dependencies](#4-installing-dependencies) +- [5. Building](#5-building) +- [6. Running tests](#6-running-tests) +- [7. Source code style guidelines](#7-source-code-style-guidelines) +- [8. DevSecOps](#8-devsecops) + + + + + ## 1. Recommended skills In order to work with `getting-started-inner-source` as a developer, we recommend you: diff --git a/docs/developer-guide/adr.md b/docs/developer-guide/adr.md index e69de29..fbe8384 100644 --- a/docs/developer-guide/adr.md +++ b/docs/developer-guide/adr.md @@ -0,0 +1,231 @@ +# Architecture Decision Records (ADRs) + +> Capture important architectural and design decisions—along with their context and consequences—for the benefit of future team members, as well as and external oversight. + +## Table of contents + + + +1. [Conventions used in this guide](#conventions-used-in-this-guide) +1. [Definition](#definition) +1. [Decision proposal workflow](#decision-proposal-workflow) +1. [Reevaluting previous decisions](#reevaluting-previous-decisions) +1. [References](#references) + + + + + +## Conventions used in this guide + +The requirement level keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" used in this document are to be interpreted as described in [RFC 2119 ![link-external][octicon-link-external]][rfc-2119]. + +## Definition + +> [![quote][octicon-quote]](#ref-thoughtworks-adr) Lightweight Architecture Decision Records is a technique for capturing important architectural decisions along with their context and consequences. We recommend storing these details in source control, instead of a wiki or website, as then they can provide a record that remains in sync with the code itself. For most projects, we see no reason why you wouldn't want to use this technique. [1] + +## Decision proposal workflow + +1. A community member (contributor) creates an ADR document outlining an approach for a particular question or problem. The ADR has an initial status of "proposed." + +2. The ADR contributor MUST submit a Merge Request (GitLab) or Pull Request (Bitbucket and GitHub) to initiate community review. + +1. The product team and technical steering group discuss the ADR. During this period, the ADR should be updated to reflect additional context, concerns raised, and proposed changes. + +1. Once consensus is reached, the ADR will be transitioned to either an "accepted" or "rejected" state. + +1. Only after an ADR is accepted should implementing code be committed to the `master` branch of the relevant project/module. + +## Reevaluting previous decisions + +If a decision is revisited and a different conclusion is reached: + +1. A new ADR should be created documenting the context and rationale for the change. + +2. The new ADR should reference the old one, and once the new one is accepted, the old one should (in its "status" section) MUST be updated to point to the new one. + +3. The old ADR _should not be removed_ or otherwise modified, _except_ for the annotation pointing to the new ADR. + +## References + + + +**[1]** _Technology Radar | Emerging Tech Trends for 2018 | ThoughtWorks._ (2018). _Thoughtworks.com._ Retrieved 26 June 2018, from + + + +[rfc-2119]: https://www.ietf.org/rfc/rfc2119.txt + + + +[octicon-alert]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/alert.svg +[octicon-arrow-down]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/arrow-down.svg +[octicon-arrow-left]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/arrow-left.svg +[octicon-arrow-right]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/arrow-right.svg +[octicon-arrow-small-down]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/arrow-small-down.svg +[octicon-arrow-small-left]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/arrow-small-left.svg +[octicon-arrow-small-right]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/arrow-small-right.svg +[octicon-arrow-small-up]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/arrow-small-up.svg +[octicon-arrow-up]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/arrow-up.svg +[octicon-beaker]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/beaker.svg +[octicon-bell]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/bell.svg +[octicon-bold]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/bold.svg +[octicon-book]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/book.svg +[octicon-bookmark]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/bookmark.svg +[octicon-briefcase]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/briefcase.svg +[octicon-broadcast]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/broadcast.svg +[octicon-browser]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/browser.svg +[octicon-bug]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/bug.svg +[octicon-calendar]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/calendar.svg +[octicon-check]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/check.svg +[octicon-checklist]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/checklist.svg +[octicon-chevron-down]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/chevron-down.svg +[octicon-chevron-left]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/chevron-left.svg +[octicon-chevron-right]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/chevron-right.svg +[octicon-chevron-up]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/chevron-up.svg +[octicon-circle-slash]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/circle-slash.svg +[octicon-circuit-board]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/circuit-board.svg +[octicon-clippy]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/clippy.svg +[octicon-clock]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/clock.svg +[octicon-cloud-download]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/cloud-download.svg +[octicon-cloud-upload]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/cloud-upload.svg +[octicon-code]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/code.svg +[octicon-comment-discussion]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/comment-discussion.svg +[octicon-comment]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/comment.svg +[octicon-credit-card]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/credit-card.svg +[octicon-dash]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/dash.svg +[octicon-dashboard]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/dashboard.svg +[octicon-database]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/database.svg +[octicon-desktop-download]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/desktop-download.svg +[octicon-device-camera-video]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/device-camera-video.svg +[octicon-device-camera]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/device-camera.svg +[octicon-device-desktop]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/device-desktop.svg +[octicon-device-mobile]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/device-mobile.svg +[octicon-diff-added]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/diff-added.svg +[octicon-diff-ignored]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/diff-ignored.svg +[octicon-diff-modified]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/diff-modified.svg +[octicon-diff-removed]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/diff-removed.svg +[octicon-diff-renamed]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/diff-renamed.svg +[octicon-diff]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/diff.svg +[octicon-ellipses]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/ellipses.svg +[octicon-ellipsis]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/ellipsis.svg +[octicon-eye]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/eye.svg +[octicon-file-binary]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-binary.svg +[octicon-file-code]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-code.svg +[octicon-file-directory]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-directory.svg +[octicon-file-media]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-media.svg +[octicon-file-pdf]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-pdf.svg +[octicon-file-submodule]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-submodule.svg +[octicon-file-symlink-directory]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-symlink-directory.svg +[octicon-file-symlink-file]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-symlink-file.svg +[octicon-file-text]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-text.svg +[octicon-file-zip]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file-zip.svg +[octicon-file]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/file.svg +[octicon-flame]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/flame.svg +[octicon-fold]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/fold.svg +[octicon-gear]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/gear.svg +[octicon-gift]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/gift.svg +[octicon-gist-secret]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/gist-secret.svg +[octicon-gist]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/gist.svg +[octicon-git-branch]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/git-branch.svg +[octicon-git-commit]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/git-commit.svg +[octicon-git-compare]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/git-compare.svg +[octicon-git-merge]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/git-merge.svg +[octicon-git-pull-request]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/git-pull-request.svg +[octicon-globe]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/globe.svg +[octicon-grabber]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/grabber.svg +[octicon-graph]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/graph.svg +[octicon-heart]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/heart.svg +[octicon-history]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/history.svg +[octicon-home]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/home.svg +[octicon-horizontal-rule]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/horizontal-rule.svg +[octicon-hubot]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/hubot.svg +[octicon-inbox]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/inbox.svg +[octicon-info]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/info.svg +[octicon-issue-closed]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/issue-closed.svg +[octicon-issue-opened]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/issue-opened.svg +[octicon-issue-reopened]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/issue-reopened.svg +[octicon-italic]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/italic.svg +[octicon-jersey]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/jersey.svg +[octicon-key]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/key.svg +[octicon-keyboard]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/keyboard.svg +[octicon-law]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/law.svg +[octicon-light-bulb]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/light-bulb.svg +[octicon-link-external]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/link-external.svg +[octicon-link]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/link.svg +[octicon-list-ordered]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/list-ordered.svg +[octicon-list-unordered]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/list-unordered.svg +[octicon-location]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/location.svg +[octicon-lock]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/lock.svg +[octicon-logo-gist]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/logo-gist.svg +[octicon-logo-github]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/logo-github.svg +[octicon-mail-read]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/mail-read.svg +[octicon-mail-reply]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/mail-reply.svg +[octicon-mail]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/mail.svg +[octicon-mark-github]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/mark-github.svg +[octicon-markdown]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/markdown.svg +[octicon-megaphone]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/megaphone.svg +[octicon-mention]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/mention.svg +[octicon-milestone]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/milestone.svg +[octicon-mirror]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/mirror.svg +[octicon-mortar-board]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/mortar-board.svg +[octicon-mute]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/mute.svg +[octicon-no-newline]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/no-newline.svg +[octicon-octoface]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/octoface.svg +[octicon-organization]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/organization.svg +[octicon-package]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/package.svg +[octicon-paintcan]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/paintcan.svg +[octicon-pencil]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/pencil.svg +[octicon-person]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/person.svg +[octicon-pin]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/pin.svg +[octicon-plug]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/plug.svg +[octicon-plus-small]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/plus-small.svg +[octicon-plus]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/plus.svg +[octicon-primitive-dot]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/primitive-dot.svg +[octicon-primitive-square]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/primitive-square.svg +[octicon-pulse]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/pulse.svg +[octicon-question]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/question.svg +[octicon-quote]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/quote.svg +[octicon-radio-tower]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/radio-tower.svg +[octicon-reply]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/reply.svg +[octicon-repo-clone]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/repo-clone.svg +[octicon-repo-force-push]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/repo-force-push.svg +[octicon-repo-forked]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/repo-forked.svg +[octicon-repo-pull]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/repo-pull.svg +[octicon-repo-push]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/repo-push.svg +[octicon-repo]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/repo.svg +[octicon-rocket]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/rocket.svg +[octicon-rss]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/rss.svg +[octicon-ruby]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/ruby.svg +[octicon-search]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/search.svg +[octicon-server]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/server.svg +[octicon-settings]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/settings.svg +[octicon-shield]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/shield.svg +[octicon-sign-in]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/sign-in.svg +[octicon-sign-out]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/sign-out.svg +[octicon-smiley]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/smiley.svg +[octicon-squirrel]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/squirrel.svg +[octicon-star]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/star.svg +[octicon-stop]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/stop.svg +[octicon-sync]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/sync.svg +[octicon-tag]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/tag.svg +[octicon-tasklist]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/tasklist.svg +[octicon-telescope]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/telescope.svg +[octicon-terminal]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/terminal.svg +[octicon-text-size]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/text-size.svg +[octicon-three-bars]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/three-bars.svg +[octicon-thumbsdown]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/thumbsdown.svg +[octicon-thumbsup]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/thumbsup.svg +[octicon-tools]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/tools.svg +[octicon-trashcan]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/trashcan.svg +[octicon-triangle-down]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/triangle-down.svg +[octicon-triangle-left]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/triangle-left.svg +[octicon-triangle-right]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/triangle-right.svg +[octicon-triangle-up]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/triangle-up.svg +[octicon-unfold]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/unfold.svg +[octicon-unmute]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/unmute.svg +[octicon-unverified]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/unverified.svg +[octicon-verified]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/verified.svg +[octicon-versions]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/versions.svg +[octicon-watch]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/watch.svg +[octicon-x]: https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/svg/x.svg diff --git a/docs/developer-guide/api.md b/docs/developer-guide/api.md index c8e7885..6ebf34c 100644 --- a/docs/developer-guide/api.md +++ b/docs/developer-guide/api.md @@ -7,10 +7,13 @@ - [1. Conventions used in this guide](#1-conventions-used-in-this-guide) -- [2. Resource Oriented Design](#2-resource-oriented-design) - * [2.1. Definitions](#21-definitions) +- [2. Standards compliance](#2-standards-compliance) +- [3. Resources, Collections, and URIs](#3-resources-collections-and-uris) + * [2.1. URI pathnames represent collections](#21-uri-pathnames-represent-collections) * [2.2. Methods](#22-methods) - * [2.3. URI paths are resource names](#23-uri-paths-are-resource-names) +- [Style guidelines](#style-guidelines) + * [Status codes](#status-codes) + * [Pagination, limit, and offset parameters](#pagination-limit-and-offset-parameters) - [3. Security](#3-security) - [4. Documentation](#4-documentation) @@ -22,11 +25,15 @@ The requirement level keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" used in this document are to be interpreted as described in [RFC 2119 ![link-external][octicon-link-external]][rfc-2119]. -## 2. Resource Oriented Design +## 2. Standards compliance -**We follow resource-oriented design.** Resource-oriented design consists of three core components: resources, collections, and URIs. +Standard | Description | Reference +:--------|:------------|:--------- +OpenAPI version 3.0.0 | A language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. | + +## 3. Resources, Collections, and URIs -### 2.1. Definitions +**We follow resource-oriented design.** Resource-oriented design consists of three core components: resources, collections, and URIs.
Resource
@@ -39,6 +46,48 @@ The requirement level keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL N
An identifier for a network location of a resource or collection
+### 2.1. URI pathnames represent collections + +URI paths MUST match the resources they represent. + +Given a resource of type `Person` (which inherits properties from the resource type `Party`): + +```json +[ + { + "partyId": "38c2443f-13d3-475e-891d-b6053bbc94a4", + "personName": { + "givenName": "Jonathon", + "familyName": "Nguyen", + "usages": [ + "Alias", + "Stage Name" + ], + "validFrom": "1994-02-01T06:00:00.000Z", + "validTo": null + } + } +] +``` + +Could be represented as: + +```http +GET /parties/:partyId +``` + +Where `:partyId` is a `field` input parameter that represents a unique identifier for resource of type `Party`. Consumers will replace this input parameter with a value, such as: + +```http +GET /parties/38c2443f-13d3-475e-891d-b6053bbc94a4 +``` + +Or: + +```http +GET /people/38c2443f-13d3-475e-891d-b6053bbc94a4 +``` + ### 2.2. Methods Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operations on resources and collections using HTTP request methods. @@ -53,13 +102,13 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat > ![info][octicon-info] We use a few more HTTP request methods, too, as you'll see below. -### 2.3. URI paths are resource names +**URI pathnames MUST match properties** of resources and collections. -1. **URI pathnames match properties** of resources and collections. +_Why:_ - _Why:_ +> ![info][octicon-info] This is a very well-known design to developers (your main API consumers). Apart from readability and ease of use, it allows us to write generic libraries and connectors without even knowing what the API is about. - > ⌦ This is a very well-known design to developers (your main API consumers). Apart from readability and ease of use, it allows us to write generic libraries and connectors without even knowing what the API is about. +## Style guidelines 1. **Use kebab-case** for URIs. @@ -67,34 +116,24 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat 1. **Use plural kebab-case for resource names** in URIs. -1. **Always use a plural nouns collections**, e.g., `/users`. +2. **Collections MUST be plural nouns**, e.g., `/users`. _Why:_ - > ⌦ Consistency and legibility. [read more...](https://apigee.com/about/blog/technology/restful-api-design-plural-nouns-and-concrete-names) + > ![info][octicon-info] Consistency and legibility. [read more...](https://apigee.com/about/blog/technology/restful-api-design-plural-nouns-and-concrete-names) -1. Always use a singular concept that starts with a collection and ends to an identifier: +3. **Select unique members in a collection with an identifier in the URI path** ```http /students/245743 /airports/kjfk ``` -1. Avoid URIs like this: - - ```http - GET /blogs/:blogId/posts/:postId/summary - ``` - - _Why:_ - - > ⌦ This is not pointing to a resource but to a property instead. You can pass the property as a parameter to trim your response. - 1. Keep verbs out of your resource URIs. _Why:_ - > ⌦ Because if you use a verb for each resource operation you soon will have a huge list of URIs and no consistent pattern which makes it difficult for developers to learn. Plus we use verbs for something else. + > ![info][octicon-info] Because if you use a verb for each resource operation you soon will have a huge list of URIs and no consistent pattern which makes it difficult for developers to learn. Plus we use verbs for something else. 1. Use verbs for non-resources. In this case, your API doesn't return any resources. Instead, you execute an operation and return the result. These **are not** CRUD (create, retrieve, update, and delete) operations: @@ -104,25 +143,25 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat _Why:_ - > ⌦ Because for CRUD we use HTTP methods on `resource` or `collection` URIs. The verbs we were talking about are actually `Controllers`. You usually don't develop many of these. [read more...](https://byrondover.github.io/post/restful-api-guidelines/#controller) + > ![info][octicon-info] Because for CRUD we use HTTP methods on `resource` or `collection` URIs. The verbs we were talking about are actually `Controllers`. You usually don't develop many of these. [read more...](https://byrondover.github.io/post/restful-api-guidelines/#controller) 1. The request body or response type is JSON then please follow `camelCase` for `JSON` property names to maintain the consistency. _Why:_ - > ⌦ This is a JavaScript project guideline, Where Programming language for generating JSON as well as Programming language for parsing JSON are assumed to be JavaScript. + > ![info][octicon-info] This is a JavaScript project guideline, Where Programming language for generating JSON as well as Programming language for parsing JSON are assumed to be JavaScript. 1. Even though a resource is a singular concept that is similar to an object instance or database record, you should not use your `table_name` for a resource name and `column_name` resource property. _Why:_ - > ⌦ Because your intention is to expose Resources, not your database schema details. + > ![info][octicon-info] Because your intention is to expose Resources, not your database schema details. 1. Again, only use nouns in your URI when naming your resources and don’t try to explain their functionality. _Why:_ - > ⌦ Only use nouns in your resource URIs, avoid endpoints like `/addNewUser` or `/updateUser` . Also avoid sending resource operations as a parameter. + > ![info][octicon-info] Only use nouns in your resource URIs, avoid endpoints like `/addNewUser` or `/updateUser` . Also avoid sending resource operations as a parameter. 1. Explain the CRUD functionalities using HTTP methods: @@ -142,7 +181,7 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat _Why:_ - > ⌦ This is a natural way to make resources explorable. + > ![info][octicon-info] This is a natural way to make resources explorable. > > _How:_ > @@ -164,7 +203,7 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat _Why:_ - > ⌦ When your APIs are public for other third parties, upgrading the APIs with some breaking change would also lead to breaking the existing products or services using your APIs. Using versions in your URI can prevent that from happening. [read more...](https://apigee.com/about/blog/technology/restful-api-design-tips-versioning) + > ![info][octicon-info] When your APIs are public for other third parties, upgrading the APIs with some breaking change would also lead to breaking the existing products or services using your APIs. Using versions in your URI can prevent that from happening. [read more...](https://apigee.com/about/blog/technology/restful-api-design-tips-versioning) 1. Response messages must be self-descriptive. A good error message response might look something like this: @@ -205,16 +244,17 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat _Why:_ - > ⌦ Developers depend on well-designed errors at the critical times when they are troubleshooting and resolving issues after the applications they've built using your APIs are in the hands of their users. + > ![info][octicon-info] Developers depend on well-designed errors at the critical times when they are troubleshooting and resolving issues after the applications they've built using your APIs are in the hands of their users. - --- +### Status codes - _![shield][octicon-shield] **Keep security exception messages as generic as possible.**_ For instance, instead of saying ‘incorrect password’, you can reply back saying ‘invalid username or password’ so that we don’t unknowingly inform user that username was indeed correct and only the password was incorrect. +1. Status codes represent resource request results. Status codes declare whether: - --- + - **Everything worked**, + - The **client app did something wrong**, or + - The **API did something wrong**. -1. Use only these 8 status codes to send with you response to describe whether **everything worked**, - The **client app did something wrong\*\* or The **API did something wrong\*\*. +2. Limit your API response results to eight (8) status codes. _Which ones:_ @@ -236,28 +276,51 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat _Why:_ - > ⌦ Most API providers use a small subset HTTP status codes. For example, the Google GData API uses only 10 status codes, Netflix uses 9, and Digg, only 8. Of course, these responses contain a body with additional information.There are over 70 HTTP status codes. However, most developers don't have all 70 memorized. So if you choose status codes that are not very common you will force application developers away from building their apps and over to wikipedia to figure out what you're trying to tell them. [read more...](https://apigee.com/about/blog/technology/restful-api-design-what-about-errors) + > ![info][octicon-info] Most API providers use a small subset HTTP status codes. For example, the Google GData API uses only 10 status codes, Netflix uses 9, and Digg, only 8. Of course, these responses contain a body with additional information. There are over 70 HTTP status codes. However, most developers don't have all 70 memorized. So if you choose status codes that are not very common you will force application developers away from building their apps and over to wikipedia to figure out what you're trying to tell them. [read more...](https://apigee.com/about/blog/technology/restful-api-design-what-about-errors) + +### Pagination, limit, and offset parameters 1. Provide total numbers of resources in your response. + 1. Accept `limit` and `offset` parameters. -1. The amount of data the resource exposes should also be taken into account. The API consumer doesn't always need the full representation of a resource.Use a fields query parameter that takes a comma separated list of fields to include: +1. **Use a `fields` query parameter that takes a comma separated list of resource `properties` to include.** + + > ```http + > GET /student?fields=id,name,age,class + > ``` + + _Why:_ + + > ![info][octicon-info] Your API consumers don't always need the full representation of a resource, nor the network latency associated with large `response` bodies. + +1. Avoid URIs nested resource properties in your URI path: ```http - GET /student?fields=id,name,age,class + GET /blogs/:blogId/posts/:postId/summary ``` + _Why:_ + + > ![info][octicon-info] This is not pointing to a resource but to a property instead. You can pass the property as a parameter to trim your response. + 1. Pagination, filtering, and sorting don’t need to be supported from start for all resources. Document those resources that offer filtering and sorting. ## 3. Security shield These are some basic security best practices. +--- + +_![shield][octicon-shield] **Keep security exception messages as generic as possible.**_ For example, if your API unsuccessfully tries to write in to a database, it should not display an error message that includes the user name it is using. + +--- + 1. Don't use basic authentication unless over a secure connection (HTTPS). Authentication tokens must not be transmitted in the URI: `GET /users/123?token=asdf....` _Why:_ - > ⌦ Because Token, or user ID and password are passed over the network as clear text (it is base64 encoded, but base64 is a reversible encoding), the basic authentication scheme is not secure. [read more...](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) + > ![info][octicon-info] Because Token, or user ID and password are passed over the network as clear text (it is base64 encoded, but base64 is a reversible encoding), the basic authentication scheme is not secure. [read more...](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) 1. Tokens must be transmitted using the Authorization header on every request: `Authorization: Bearer xxxxxx, Extra yyyyy`. @@ -269,33 +332,35 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat _Why:_ - > ⌦ To protect your APIs from bot threats that call your API thousands of times per hour. You should consider implementing rate limit early on. + > ![info][octicon-info] To protect your APIs from bot threats that call your API thousands of times per hour. You should consider implementing rate limit early on. 1. Setting HTTP headers appropriately can help to lock down and secure your web application. [read more...](https://github.com/helmetjs/helmet) 1. Your API should convert the received data to their canonical form or reject them. Return 400 Bad Request with details about any errors from bad or missing data. -1. All the data exchanged with the ReST API must be validated by the API. +2. All the data exchanged with the ReST API must be validated by the API. -1. Serialize your JSON. +2. Serialize your JSON. _Why:_ - > ⌦ A key concern with JSON encoders is preventing arbitrary JavaScript remote code execution within the browser... or, if you're using node.js, on the server. It's vital that you use a proper JSON serializer to encode user-supplied data properly to prevent the execution of user-supplied input on the browser. + > ![info][octicon-info] A key concern with JSON encoders is preventing arbitrary JavaScript remote code execution within the browser... or, if you're using node.js, on the server. It's vital that you use a proper JSON serializer to encode user-supplied data properly to prevent the execution of user-supplied input on the browser. 1. Validate the content-type and mostly use `application/*json` (Content-Type header). _Why:_ - > ⌦ For instance, accepting the `application/x-www-form-URIencoded` mime type allows the attacker to create a form and trigger a simple POST request. The server should never assume the Content-Type. A lack of Content-Type header or an unexpected Content-Type header should result in the server rejecting the content with a `4XX` response. + > ![info][octicon-info] For instance, accepting the `application/x-www-form-URIencoded` mime type allows the attacker to create a form and trigger a simple POST request. The server should never assume the Content-Type. A lack of Content-Type header or an unexpected Content-Type header should result in the server rejecting the content with a `4XX` response. ## 4. Documentation -1. **Fill the API section in the README for "API"**. +1. **Fill the API section in the README for "API"**. For large APIs, provide a link to comprehensive documentation. 1. **Authentication examples.** Describe API authentication methods with a code sample. -1. **URI structure.** Explaining The URI Structure (path only, no root URI) including The request type (Method). For each endpoint explain: +2. **Host information:** Prefer specifing hostnames using the [host-meta JSON schema ![external-link][octicon-link-external]][schema-host-meta-url]. + +1. **URI structure.** Explain the URI Structure (path only, no root URI) including The request type (Method). 1. **URI Params.** If URI Params exist, specify them in accordance with name mentioned in URI section: @@ -370,6 +435,7 @@ Our APIs perform [CRUD ![link-external][octicon-link-external]][crud-URI] operat [data-structures-URI]: https://en.wikipedia.org/wiki/Data_structure [modular-programming-URI]: https://en.wikipedia.org/wiki/Modular_programming [rfc-2119]: https://www.ietf.org/rfc/rfc2119.txt +[schema-host-meta-url]: http://json.schemastore.org/host-meta