diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..630e82e7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# https://editorconfig.org + +root = true + +[*] +indent_size = 2 +indent_style = space +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore index 8c6652cb..0a9095b3 100644 --- a/.gitignore +++ b/.gitignore @@ -79,7 +79,6 @@ dist # IDE / Editor .idea -.editorconfig # Service worker sw.* diff --git a/README.md b/README.md index 95402d89..3c14dbee 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,9 @@ When I wrote this, only God and I understood what I was doing. Now, only God kno # postwoman Postwoman -### 👽 API request builder by [Liyas Thomas](https://github.com/liyasthomas) +### API request builder + +**Start here: _[Story behind Postwoman](https://dev.to/liyasthomas/i-created-postwoman-an-online-open-source-api-request-builder-41md)_**

@@ -28,13 +30,74 @@ When I wrote this, only God and I understood what I was doing. Now, only God kno ### Features :sparkles: -:heart: **Lightweight and minimal**: Crafted with minimalistic UI design +:heart: **Lightweight**: Crafted with minimalistic UI design -:electric_plug: **Real-time demo**: Send requests and get response right away! + - Faster, lighter, cleaner, minimal & responsive -:robot: **VIBGYOR**: Neon combination of colors for background and foreground +:zap: **Real-time**: Send requests and get/copy responses right away! -:sparkles: **PWA**: Install as a PWA on your device +**Methods:** + - `GET` - Retrieve information about the REST API resource + - `HEAD` - Asks for a response identical to that of a GET request, but without the response body. + - `POST` - Create a REST API resource + - `PUT` - Update a REST API resource + - `DELETE` - Delete a REST API resource or related component + - `OPTIONS` - Describe the communication options for the target resource + - `PATCH` - Applies partial modifications to a REST API resource + +_History entries are synced with local session storage_ + +:rainbow: **VIBGYOR**: Neon combination background, foreground & accent colors - because customization === freedom :sparkles: + +**Customizations:** + - Dark and Light background themes + - Choose accent color + - Toggle multi-colored frames + +_Customized themes are also synced with local session storage_ + +:fire: **PWA**: Install as a **[PWA](https://developers.google.com/web/progressive-web-apps)** on your device + +**Features:** + - Instant loading with Service Workers + - Offline support + - Low RAM/memory and CPU usage + +:electric_plug: **Web Socket**: Establish full-duplex communication channels over a single TCP connection + + - Send and receive data + +:closed_lock_with_key: **Authentication**: Allows to identity the end user + +**Types:** + - None + - Basic authentication using username and password + - Token based authentication + +:loudspeaker: **Headers**: Describes the format the body of your request is being sent as + +:mailbox: **Parameters**: Use request parameters to set varying parts in simulated requests + +:page_with_curl: **Request Body**: Used to send and receive data via the REST API + +**Options:** + - Set content Type + - Toggle between RAW input and parameter list + +:wave: **Responses**: Contains the status line, headers and the message/response body + +_HTML responses have "Preview HTML" feature_ + +:alarm_clock: **History**: Request entries are synced with local session storage to reuse with a single click + +**Fields** + - Timestamp + - Method + - Status code + - URL + - Path + +_History entries can be deleted one-by-one or all together_ --- @@ -111,6 +174,7 @@ See the [CHANGELOG](CHANGELOG.md) file for details. ### Testing and Debugging * [Liyas Thomas](https://github.com/liyasthomas) +* ([contributors](https://github.com/liyasthomas/postwoman/graphs/contributors)) ### Contributors * [NBTX](https://github.com/NBTX) diff --git a/assets/css/styles.scss b/assets/css/styles.scss index 4774b393..000b63c9 100644 --- a/assets/css/styles.scss +++ b/assets/css/styles.scss @@ -20,16 +20,6 @@ $responsiveWidth: 720px; font-family: "Poppins", "Roboto", "Noto", sans-serif; } -@keyframes fadein { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - a { display: inline-flex; color: inherit; @@ -42,7 +32,6 @@ body { color: var(--fg-color); font-weight: 500; line-height: 1.5; - animation: fadein 0.2s; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; -webkit-user-select: none; @@ -56,6 +45,10 @@ h3 { font-weight: 700; } +h3.title { + margin: 4px; +} + header, footer { display: flex; @@ -65,20 +58,6 @@ footer { justify-content: space-between; } - -@media(max-width: $responsiveWidth){ - header { - display: block; - text-align: center; - - nav { - display: inline-flex; - margin-top: 20px; - } - } -} - - nav { a:not(:last-of-type) { margin-right: 15px; @@ -87,9 +66,9 @@ nav { body.sticky-footer footer { position: fixed; + right: 0; bottom: 0; left: 0; - right: 0; } .logo { @@ -105,6 +84,11 @@ button { font-weight: 700; font-size: 16px; cursor: pointer; + + &[disabled], &.disabled { + opacity: 0.7; + cursor: default; + } } fieldset { @@ -172,7 +156,15 @@ fieldset.purple legend { color: #C198FB; } -.collapsible.hidden { +fieldset.orange { + border-color: #F5A623; +} + +fieldset.orange legend { + color: #F5A623; +} + +.hidden { display: none; } @@ -183,8 +175,8 @@ textarea, pre { margin: 4px; padding: 8px 16px; - width: calc(100% - 8px); border-radius: 4px; + width: calc(100% - 8px); background-color: var(--bg-dark-color); color: var(--fg-color); font-weight: 700; @@ -196,14 +188,36 @@ pre { select, input, option { - height: 38px; + height: 41px; } input[type="checkbox"] { - width: initial; + display: none; - &, & + label { + &, + & + label { vertical-align: middle; + cursor: pointer; + + &:before { + content: "\2714"; + border: 2px solid var(--fg-color); + border-radius: 4px; + display: inline-flex; + height: 16px; + width: 16px; + align-items: center; + justify-content: center; + margin: 8px 8px 8px 0; + color: transparent; + transition: .2s; + } + } + + &:checked + label:before { + background-color: var(--ac-color); + border-color: var(--ac-color); + color: var(--act-color); } } @@ -211,7 +225,7 @@ input[type="checkbox"] { background-color: var(--err-color); } -.disabled { +.disabled, input[disabled] { background-color: var(--err-color); color: #b2b2b2; } @@ -234,18 +248,24 @@ ol li { flex-direction: column; flex-grow: 1; } -.flex-wrap{ + +.flex-wrap { display: flex; justify-content: space-between; -} -.btn-copy{ - padding: 6px 14px; - font-size: 11px; - margin-right: 15px; - + align-items: center; } @media (max-width: $responsiveWidth) { + header { + display: block; + text-align: center; + + nav { + display: inline-flex; + margin-top: 20px; + } + } + ul, ol { flex-direction: column; @@ -255,6 +275,10 @@ ol li { ol li { display: flex; } + + .hide-on-small-screen { + display: none; + } } #installPWA { @@ -281,6 +305,14 @@ ol li { background-color: #B71C1C; } +.missing-data-response { + background-color: #676767; +} + +.virtual-list::-webkit-scrollbar { + width: 0; +} + fieldset#history { .method-list-item { position: relative; @@ -293,3 +325,37 @@ fieldset#history { } } } + +.align-left { + text-align: left; +} + +.align-right { + text-align: right; +} + +#response-details-wrapper { + position: relative; + overflow: hidden; + border-radius: 4px; + margin: 4px; + + textarea { + width: 100%; + } + + #response-details { + margin: 0; + } + + .covers-response { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: white; + height: 100%; + width: 100%; + } +} diff --git a/components/settings/swatch.vue b/components/settings/swatch.vue index 262c718f..40f9bd1b 100644 --- a/components/settings/swatch.vue +++ b/components/settings/swatch.vue @@ -12,10 +12,11 @@ display: inline-block; vertical-align: middle; - padding: 8px 15px; - margin: 5px; + padding: 8px 16px; + margin: 4px; background-color: rgba(93, 93, 93, 0.2); border-radius: 4px; + cursor: pointer; &.active { background-color: rgba(93, 93, 93, 0.3); @@ -24,10 +25,10 @@ .preview { vertical-align: middle; display: inline-block; - width: 36px; - height: 36px; + width: 32px; + height: 32px; border-radius: 100%; - margin-right: 10px; + margin-right: 8px; position: relative; .activeTick { diff --git a/components/toggle.vue b/components/toggle.vue new file mode 100644 index 00000000..c02e950b --- /dev/null +++ b/components/toggle.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/layouts/default.vue b/layouts/default.vue index 7f439597..3d8273a6 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -3,55 +3,54 @@
-

Postwoman

+

+ Postwoman

API request builder

-
- -
- + diff --git a/nuxt.config.js b/nuxt.config.js index e3a904c3..b4f46aaf 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -86,7 +86,7 @@ export default { /* ** Customize the progress-bar color */ - loading: { color: '#88FB4F' }, + loading: { color: 'var(--ac-color)' }, /* ** Global CSS @@ -136,7 +136,9 @@ export default { return icons; })([48, 72, 96, 144, 192, 512]) } - }] + }], + + ['@nuxtjs/axios'] ], /* diff --git a/package-lock.json b/package-lock.json index a4a37c69..1886a6dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1527,6 +1527,17 @@ } } }, + "@nuxtjs/axios": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@nuxtjs/axios/-/axios-5.6.0.tgz", + "integrity": "sha512-Rl4nnudm+sSkMtgfSEAeA5bq6aFpbBoYVXLXWaDxfydslukRd2SdEDdGv0gHE7F/jtIw+JfptWDHCHnzuoO/Ng==", + "requires": { + "@nuxtjs/proxy": "^1.3.3", + "axios": "^0.19.0", + "axios-retry": "^3.1.2", + "consola": "^2.10.1" + } + }, "@nuxtjs/icon": { "version": "3.0.0-beta.16", "resolved": "https://registry.npmjs.org/@nuxtjs/icon/-/icon-3.0.0-beta.16.tgz", @@ -1557,6 +1568,15 @@ "@nuxtjs/pwa-utils": "3.0.0-beta.16" } }, + "@nuxtjs/proxy": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@nuxtjs/proxy/-/proxy-1.3.3.tgz", + "integrity": "sha512-ykpCUdOqPOH79mQG30QfWZmbRD8yjTD+TTSBbwow5GkROUQEtXw+HE+q6i+YFpuChvgJNbwVrXdZ3YmfXbZtTw==", + "requires": { + "consola": "^2.5.6", + "http-proxy-middleware": "^0.19.1" + } + }, "@nuxtjs/pwa": { "version": "3.0.0-beta.16", "resolved": "https://registry.npmjs.org/@nuxtjs/pwa/-/pwa-3.0.0-beta.16.tgz", @@ -2204,6 +2224,46 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, + "axios": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + } + } + }, + "axios-retry": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.1.2.tgz", + "integrity": "sha512-+X0mtJ3S0mmia1kTVi1eA3DAC+oWnT2A29g3CpkzcBPMT6vJm+hn/WiV9wPt/KXLHVmg5zev9mWqkPx7bHMovg==", + "requires": { + "is-retry-allowed": "^1.1.0" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -4058,6 +4118,11 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, "events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", @@ -4453,6 +4518,29 @@ } } }, + "follow-redirects": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.8.1.tgz", + "integrity": "sha512-micCIbldHioIegeKs41DoH0KS3AXfFzgS30qVkM6z/XOE/GJgvmsoc839NUqa1B9udYe9dQxgv7KFwng6+p/dw==", + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -5096,6 +5184,27 @@ "toidentifier": "1.0.0" } }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -5418,6 +5527,11 @@ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -8430,6 +8544,11 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", @@ -9997,6 +10116,11 @@ "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==" }, + "vue-virtual-scroll-list": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.4.2.tgz", + "integrity": "sha512-jcXl1cYDxGZX+aF9vsUauXWnUkXm8oQxnvLTJ8UMTmMxwzbmlHX7vs0xGDdEej91vJpBNrdNNseWPxboTvI+UA==" + }, "vuex": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.1.tgz", diff --git a/package.json b/package.json index 0230a2b4..fd6aec47 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,10 @@ "generate": "nuxt generate" }, "dependencies": { + "@nuxtjs/axios": "^5.6.0", "@nuxtjs/pwa": "^3.0.0-0", "nuxt": "^2.0.0", + "vue-virtual-scroll-list": "^1.4.2", "vuex-persist": "^2.0.1" }, "devDependencies": { diff --git a/pages/index.vue b/pages/index.vue index 135aa483..dbef71fe 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,34 +1,34 @@ - diff --git a/pages/settings.vue b/pages/settings.vue index bb34e09d..e528d79d 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -1,126 +1,197 @@ - \ No newline at end of file + } + + diff --git a/pages/websocket.vue b/pages/websocket.vue index cd371346..eb731ac2 100644 --- a/pages/websocket.vue +++ b/pages/websocket.vue @@ -1,48 +1,42 @@ - + diff --git a/store/postwoman.js b/store/postwoman.js index fb07b5d1..dcd07b9e 100644 --- a/store/postwoman.js +++ b/store/postwoman.js @@ -24,7 +24,21 @@ export const SETTINGS_KEYS = [ * to emphasise the different sections. * This setting allows that to be turned off. */ - "DISABLE_FRAME_COLORS" + "DISABLE_FRAME_COLORS", + + /** + * Whether or not requests should be proxied. + */ + "PROXY_ENABLED", + + /** + * The URL of the proxy to connect to for requests. + */ + "PROXY_URL", + /** + * The security key of the proxy. + */ + "PROXY_KEY" ]; export const state = () => ({ @@ -43,9 +57,9 @@ export const mutations = { // Add your settings key to the SETTINGS_KEYS array at the // top of the file. // This is to ensure that application settings remain documented. - if(!SETTINGS_KEYS.includes(key)) throw new Error("The settings key does not include the key " + key); + if(!SETTINGS_KEYS.includes(key)) throw new Error("The settings structure does not include the key " + key); state.settings[key] = value; } -}; \ No newline at end of file +};