diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1db3f3eb..4645e0b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,29 +8,12 @@ on: - develop jobs: - lint: - runs-on: ubuntu-20.04 - strategy: - matrix: - php-version: ['8.0'] - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Use PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - tools: composer - extensions: openswoole-4.8.1 - coverage: none - - run: composer install --no-interaction --prefer-dist - - run: composer cs - static-analysis: runs-on: ubuntu-20.04 strategy: matrix: php-version: ['8.0'] + command: ['cs', 'stan', 'swagger:validate'] steps: - name: Checkout code uses: actions/checkout@v2 @@ -42,7 +25,7 @@ jobs: extensions: openswoole-4.8.1 coverage: none - run: composer install --no-interaction --prefer-dist - - run: composer stan + - run: composer ${{ matrix.command }} unit-tests: runs-on: ubuntu-20.04 diff --git a/.gitignore b/.gitignore index 32942a29..933c25ee 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ docs/swagger-ui* docs/mercure.html docker-compose.override.yml .phpunit.result.cache +docs/swagger/swagger-inlined.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aeca402..dcc88c9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this ### Fixed * [#1206](https://github.com/shlinkio/shlink/issues/1206) Fixed debugging of the docker image, so that it does not run the commands with `-q` when the `SHELL_VERBOSITY` env var has been provided. +* [#1254](https://github.com/shlinkio/shlink/issues/1254) Fixed examples in swagger docs. ## [2.9.3] - 2021-11-15 diff --git a/composer.json b/composer.json index 2926a1af..fedb863f 100644 --- a/composer.json +++ b/composer.json @@ -61,6 +61,7 @@ "symfony/string": "^5.4" }, "require-dev": { + "cebe/php-openapi": "^1.5", "devster/ubench": "^2.1", "dms/phpunit-arraysubset-asserts": "^0.3.0", "eaglewu/swoole-ide-helper": "dev-master", @@ -145,6 +146,8 @@ "@parallel test:unit:ci test:db:sqlite:ci", "@infect:ci" ], + "swagger:validate": "php-openapi validate docs/swagger/swagger.json", + "swagger:inline": "php-openapi inline docs/swagger/swagger.json docs/swagger/swagger-inlined.json", "clean:dev": "rm -f data/database.sqlite && rm -f config/params/generated_config.php" }, "scripts-descriptions": { @@ -170,6 +173,8 @@ "infect:ci:unit": "Checks unit tests quality applying mutation testing with existing reports and logs", "infect:ci:db": "Checks db tests quality applying mutation testing with existing reports and logs", "infect:test": "Runs unit and db tests, then checks tests quality applying mutation testing", + "swagger:validate": "Validates the swagger docs, making sure they fulfil the spec", + "swagger:inline": "Inlines swagger docs in a single file", "clean:dev": "Deletes artifacts which are gitignored and could affect dev env" }, "config": { diff --git a/docs/swagger/examples/short-url-invalid-args.json b/docs/swagger/examples/short-url-invalid-args.json new file mode 100644 index 00000000..d85a5eed --- /dev/null +++ b/docs/swagger/examples/short-url-invalid-args.json @@ -0,0 +1,9 @@ +{ + "value": { + "title": "Invalid data", + "type": "INVALID_ARGUMENT", + "detail": "Provided data is not valid", + "status": 400, + "invalidElements": ["maxVisits", "validSince"] + } +} diff --git a/docs/swagger/examples/short-url-not-found.json b/docs/swagger/examples/short-url-not-found.json new file mode 100644 index 00000000..74a5661c --- /dev/null +++ b/docs/swagger/examples/short-url-not-found.json @@ -0,0 +1,9 @@ +{ + "value": { + "detail":"No URL found with short code \"abc123\"", + "title":"Short URL not found", + "type": "INVALID_SHORTCODE", + "status": 404, + "shortCode": "abc123" + } +} diff --git a/docs/swagger/examples/tag-not-found.json b/docs/swagger/examples/tag-not-found.json new file mode 100644 index 00000000..46018121 --- /dev/null +++ b/docs/swagger/examples/tag-not-found.json @@ -0,0 +1,9 @@ +{ + "value": { + "detail": "Tag with name \"foo\" could not be found", + "title": "Tag not found", + "type": "TAG_NOT_FOUND", + "status": 404, + "tag": "foo" + } +} diff --git a/docs/swagger/paths/health.json b/docs/swagger/paths/health.json index 60d96ccc..8dc5e7da 100644 --- a/docs/swagger/paths/health.json +++ b/docs/swagger/paths/health.json @@ -13,16 +13,14 @@ "application/json": { "schema": { "$ref": "../definitions/Health.json" - } - } - }, - "examples": { - "application/json": { - "status": "pass", - "version": "1.16.0", - "links": { - "about": "https://shlink.io", - "project": "https://github.com/shlinkio/shlink" + }, + "example": { + "status": "pass", + "version": "2.10.0", + "links": { + "about": "https://shlink.io", + "project": "https://github.com/shlinkio/shlink" + } } } } @@ -33,21 +31,19 @@ "application/json": { "schema": { "$ref": "../definitions/Health.json" - } - } - }, - "examples": { - "application/json": { - "status": "fail", - "version": "1.16.0", - "links": { - "about": "https://shlink.io", - "project": "https://github.com/shlinkio/shlink" + }, + "example": { + "status": "fail", + "version": "2.10.0", + "links": { + "about": "https://shlink.io", + "project": "https://github.com/shlinkio/shlink" + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/json": { diff --git a/docs/swagger/paths/v1_short-urls.json b/docs/swagger/paths/v1_short-urls.json index a4643058..04afdd3a 100644 --- a/docs/swagger/paths/v1_short-urls.json +++ b/docs/swagger/paths/v1_short-urls.json @@ -117,79 +117,77 @@ } } } - } - } - }, - "examples": { - "application/json": { - "shortUrls": { - "data": [ - { - "shortCode": "12C18", - "shortUrl": "https://doma.in/12C18", - "longUrl": "https://store.steampowered.com", - "dateCreated": "2016-08-21T20:34:16+02:00", - "visitsCount": 328, - "tags": [ - "games", - "tech" - ], - "meta": { - "validSince": "2017-01-21T00:00:00+02:00", - "validUntil": null, - "maxVisits": 100 + }, + "example": { + "shortUrls": { + "data": [ + { + "shortCode": "12C18", + "shortUrl": "https://doma.in/12C18", + "longUrl": "https://store.steampowered.com", + "dateCreated": "2016-08-21T20:34:16+02:00", + "visitsCount": 328, + "tags": [ + "games", + "tech" + ], + "meta": { + "validSince": "2017-01-21T00:00:00+02:00", + "validUntil": null, + "maxVisits": 100 + }, + "domain": null, + "title": "Welcome to Steam", + "crawlable": false }, - "domain": null, - "title": "Welcome to Steam", - "crawlable": false - }, - { - "shortCode": "12Kb3", - "shortUrl": "https://doma.in/12Kb3", - "longUrl": "https://shlink.io", - "dateCreated": "2016-05-01T20:34:16+02:00", - "visitsCount": 1029, - "tags": [ - "shlink" - ], - "meta": { - "validSince": null, - "validUntil": null, - "maxVisits": null + { + "shortCode": "12Kb3", + "shortUrl": "https://doma.in/12Kb3", + "longUrl": "https://shlink.io", + "dateCreated": "2016-05-01T20:34:16+02:00", + "visitsCount": 1029, + "tags": [ + "shlink" + ], + "meta": { + "validSince": null, + "validUntil": null, + "maxVisits": null + }, + "domain": null, + "title": null, + "crawlable": false }, - "domain": null, - "title": null, - "crawlable": false - }, - { - "shortCode": "123bA", - "shortUrl": "https://example.com/123bA", - "longUrl": "https://www.google.com", - "dateCreated": "2015-10-01T20:34:16+02:00", - "visitsCount": 25, - "tags": [], - "meta": { - "validSince": "2017-01-21T00:00:00+02:00", - "validUntil": null, - "maxVisits": null - }, - "domain": "example.com", - "title": null, - "crawlable": false + { + "shortCode": "123bA", + "shortUrl": "https://example.com/123bA", + "longUrl": "https://www.google.com", + "dateCreated": "2015-10-01T20:34:16+02:00", + "visitsCount": 25, + "tags": [], + "meta": { + "validSince": "2017-01-21T00:00:00+02:00", + "validUntil": null, + "maxVisits": null + }, + "domain": "example.com", + "title": null, + "crawlable": false + } + ], + "pagination": { + "currentPage": 5, + "pagesCount": 12, + "itemsPerPage": 10, + "itemsInCurrentPage": 10, + "totalItems": 115 } - ], - "pagination": { - "currentPage": 5, - "pagesCount": 12, - "itemsPerPage": 10, - "itemsInCurrentPage": 10, - "totalItems": 115 } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { @@ -267,28 +265,26 @@ "application/json": { "schema": { "$ref": "../definitions/ShortUrl.json" - } - } - }, - "examples": { - "application/json": { - "shortCode": "12C18", - "shortUrl": "https://doma.in/12C18", - "longUrl": "https://store.steampowered.com", - "dateCreated": "2016-08-21T20:34:16+02:00", - "visitsCount": 0, - "tags": [ - "games", - "tech" - ], - "meta": { - "validSince": "2017-01-21T00:00:00+02:00", - "validUntil": null, - "maxVisits": 500 }, - "domain": null, - "title": null, - "crawlable": false + "example": { + "shortCode": "12C18", + "shortUrl": "https://doma.in/12C18", + "longUrl": "https://store.steampowered.com", + "dateCreated": "2016-08-21T20:34:16+02:00", + "visitsCount": 0, + "tags": [ + "games", + "tech" + ], + "meta": { + "validSince": "2017-01-21T00:00:00+02:00", + "validUntil": null, + "maxVisits": 500 + }, + "domain": null, + "title": null, + "crawlable": false + } } } }, @@ -326,15 +322,42 @@ "customSlug": { "type": "string", "description": "Provided custom slug when the error type is INVALID_SLUG" + }, + "domain": { + "type": "string", + "description": "The domain for which you were trying to create the new short URL" } } } ] + }, + "examples": { + "Invalid arguments": { + "$ref": "../examples/short-url-invalid-args.json" + }, + "Invalid long URL": { + "value": { + "title": "Invalid URL", + "type": "INVALID_URL", + "detail": "Provided URL foo is invalid. Try with a different one.", + "status": 400, + "url": "https://invalid-url.com" + } + }, + "Non-unique slug": { + "value": { + "title": "Invalid custom slug", + "type": "INVALID_SLUG", + "detail": "Provided slug \"my-slug\" is already in use.", + "status": 400, + "customSlug": "my-slug" + } + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v1_short-urls_shorten.json b/docs/swagger/paths/v1_short-urls_shorten.json index 90c3eda5..722476bb 100644 --- a/docs/swagger/paths/v1_short-urls_shorten.json +++ b/docs/swagger/paths/v1_short-urls_shorten.json @@ -49,35 +49,33 @@ "application/json": { "schema": { "$ref": "../definitions/ShortUrl.json" + }, + "example": { + "longUrl": "https://github.com/shlinkio/shlink", + "shortUrl": "https://doma.in/abc123", + "shortCode": "abc123", + "dateCreated": "2016-08-21T20:34:16+02:00", + "visitsCount": 0, + "tags": [ + "games", + "tech" + ], + "meta": { + "validSince": "2017-01-21T00:00:00+02:00", + "validUntil": null, + "maxVisits": 100 + }, + "domain": null, + "title": null, + "crawlable": false } }, "text/plain": { "schema": { "type": "string" - } - } - }, - "examples": { - "application/json": { - "longUrl": "https://github.com/shlinkio/shlink", - "shortUrl": "https://doma.in/abc123", - "shortCode": "abc123", - "dateCreated": "2016-08-21T20:34:16+02:00", - "visitsCount": 0, - "tags": [ - "games", - "tech" - ], - "meta": { - "validSince": "2017-01-21T00:00:00+02:00", - "validUntil": null, - "maxVisits": 100 }, - "domain": null, - "title": null, - "crawlable": false - }, - "text/plain": "https://doma.in/abc123" + "example": "https://doma.in/abc123" + } } }, "400": { @@ -86,26 +84,24 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "example": { + "title": "Invalid URL", + "type": "INVALID_URL", + "detail": "Provided URL foo is invalid. Try with a different one.", + "status": 400, + "url": "https://invalid-url.com" } }, "text/plain": { "schema": { "type": "string" - } + }, + "example": "INVALID_URL" } - }, - "examples": { - "application/problem+json": { - "title": "Invalid URL", - "type": "INVALID_URL", - "detail": "Provided URL foo is invalid. Try with a different one.", - "status": 400, - "url": "https://invalid-url.com" - }, - "text/plain": "INVALID_URL" } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { @@ -118,13 +114,6 @@ "type": "string" } } - }, - "examples": { - "application/problem+json": { - "error": "INTERNAL_SERVER_ERROR", - "message": "Unexpected error occurred" - }, - "text/plain": "INTERNAL_SERVER_ERROR" } } } diff --git a/docs/swagger/paths/v1_short-urls_{shortCode}.json b/docs/swagger/paths/v1_short-urls_{shortCode}.json index e37df965..eec1cec3 100644 --- a/docs/swagger/paths/v1_short-urls_{shortCode}.json +++ b/docs/swagger/paths/v1_short-urls_{shortCode}.json @@ -35,27 +35,25 @@ "application/json": { "schema": { "$ref": "../definitions/ShortUrl.json" - } - } - }, - "examples": { - "application/json": { - "shortCode": "12Kb3", - "shortUrl": "https://doma.in/12Kb3", - "longUrl": "https://shlink.io", - "dateCreated": "2016-05-01T20:34:16+02:00", - "visitsCount": 1029, - "tags": [ - "shlink" - ], - "meta": { - "validSince": "2017-01-21T00:00:00+02:00", - "validUntil": null, - "maxVisits": 100 }, - "domain": null, - "title": null, - "crawlable": false + "example": { + "shortCode": "12Kb3", + "shortUrl": "https://doma.in/12Kb3", + "longUrl": "https://shlink.io", + "dateCreated": "2016-05-01T20:34:16+02:00", + "visitsCount": 1029, + "tags": [ + "shlink" + ], + "meta": { + "validSince": "2017-01-21T00:00:00+02:00", + "validUntil": null, + "maxVisits": 100 + }, + "domain": null, + "title": null, + "crawlable": false + } } } }, @@ -64,12 +62,35 @@ "content": { "application/problem+json": { "schema": { - "$ref": "../definitions/Error.json" + "allOf": [ + { + "$ref": "../definitions/Error.json" + }, + { + "type": "object", + "required": ["shortCode"], + "properties": { + "shortCode": { + "type": "string", + "description": "The short code with which we tried to find the short URL" + }, + "domain": { + "type": "string", + "description": "The domain with which we tried to find the short URL" + } + } + } + ] + }, + "examples": { + "Not found": { + "$ref": "../examples/short-url-not-found.json" + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { @@ -129,27 +150,25 @@ "application/json": { "schema": { "$ref": "../definitions/ShortUrl.json" - } - } - }, - "examples": { - "application/json": { - "shortCode": "12Kb3", - "shortUrl": "https://doma.in/12Kb3", - "longUrl": "https://shlink.io", - "dateCreated": "2016-05-01T20:34:16+02:00", - "visitsCount": 1029, - "tags": [ - "shlink" - ], - "meta": { - "validSince": "2017-01-21T00:00:00+02:00", - "validUntil": null, - "maxVisits": 100 }, - "domain": null, - "title": "Shlink - The URL shortener", - "crawlable": false + "example": { + "shortCode": "12Kb3", + "shortUrl": "https://doma.in/12Kb3", + "longUrl": "https://shlink.io", + "dateCreated": "2016-05-01T20:34:16+02:00", + "visitsCount": 1029, + "tags": [ + "shlink" + ], + "meta": { + "validSince": "2017-01-21T00:00:00+02:00", + "validUntil": null, + "maxVisits": 100 + }, + "domain": null, + "title": "Shlink - The URL shortener", + "crawlable": false + } } } }, @@ -182,21 +201,49 @@ } } ] + }, + "examples": { + "Invalid arguments": { + "$ref": "../examples/short-url-invalid-args.json" + } } } } }, "404": { - "description": "No short URL was found for provided short code.", + "description": "No URL was found for provided short code.", "content": { "application/problem+json": { "schema": { - "$ref": "../definitions/Error.json" + "allOf": [ + { + "$ref": "../definitions/Error.json" + }, + { + "type": "object", + "required": ["shortCode"], + "properties": { + "shortCode": { + "type": "string", + "description": "The short code with which we tried to find the short URL" + }, + "domain": { + "type": "string", + "description": "The domain with which we tried to find the short URL" + } + } + } + ] + }, + "examples": { + "Not found": { + "$ref": "../examples/short-url-not-found.json" + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { @@ -247,30 +294,75 @@ "content": { "application/problem+json": { "schema": { - "$ref": "../definitions/Error.json" + "allOf": [ + { + "$ref": "../definitions/Error.json" + }, + { + "type": "object", + "required": ["shortCode", "threshold"], + "properties": { + "shortCode": { + "type": "string", + "description": "The short code with which we tried to find the short URL to delete" + }, + "domain": { + "type": "string", + "description": "The domain with which we tried to find the short URL to delete" + }, + "threshold": { + "type": "number", + "description": "The amount of visits currently configured as threshold to allow deleting short UYRLs or not" + } + } + } + ] + }, + "example": { + "title": "Cannot delete short URL", + "type": "INVALID_SHORTCODE_DELETION", + "detail": "Impossible to delete short URL with short code \"abc123\", since it has more than \"15\" visits.", + "status": 422, + "shortCode": "abc123", + "threshold": 15 } } - }, - "examples": { - "application/problem+json": { - "title": "Cannot delete short URL", - "type": "INVALID_SHORTCODE_DELETION", - "detail": "It is not possible to delete URL with short code \"abc123\" because it has reached more than \"15\" visits.", - "status": 422 - } } }, "404": { - "description": "No short URL was found for provided short code.", + "description": "No URL was found for provided short code.", "content": { "application/problem+json": { "schema": { - "$ref": "../definitions/Error.json" + "allOf": [ + { + "$ref": "../definitions/Error.json" + }, + { + "type": "object", + "required": ["shortCode"], + "properties": { + "shortCode": { + "type": "string", + "description": "The short code with which we tried to find the short URL" + }, + "domain": { + "type": "string", + "description": "The domain with which we tried to find the short URL" + } + } + } + ] + }, + "examples": { + "Not found": { + "$ref": "../examples/short-url-not-found.json" + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v1_short-urls_{shortCode}_tags.json b/docs/swagger/paths/v1_short-urls_{shortCode}_tags.json index 6ea642b0..645c6ef2 100644 --- a/docs/swagger/paths/v1_short-urls_{shortCode}_tags.json +++ b/docs/swagger/paths/v1_short-urls_{shortCode}_tags.json @@ -69,14 +69,6 @@ } } } - }, - "examples": { - "application/json": { - "tags": [ - "games", - "tech" - ] - } } }, "400": { @@ -99,7 +91,7 @@ } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/json": { diff --git a/docs/swagger/paths/v1_short-urls_{shortCode}_visits.json b/docs/swagger/paths/v1_short-urls_{shortCode}_visits.json index e5bbbe86..08a93b68 100644 --- a/docs/swagger/paths/v1_short-urls_{shortCode}_visits.json +++ b/docs/swagger/paths/v1_short-urls_{shortCode}_visits.json @@ -97,49 +97,47 @@ } } } - } - } - }, - "examples": { - "application/json": { - "visits": { - "data": [ - { - "referer": "https://twitter.com", - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0", - "visitLocation": null, - "potentialBot": false - }, - { - "referer": "https://t.co", - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "visitLocation": { - "cityName": "Cupertino", - "countryCode": "US", - "countryName": "United States", - "latitude": 37.3042, - "longitude": -122.0946, - "regionName": "California", - "timezone": "America/Los_Angeles" + }, + "example": { + "visits": { + "data": [ + { + "referer": "https://twitter.com", + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0", + "visitLocation": null, + "potentialBot": false }, - "potentialBot": false - }, - { - "referer": null, - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "some_web_crawler/1.4", - "visitLocation": null, - "potentialBot": true + { + "referer": "https://t.co", + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", + "visitLocation": { + "cityName": "Cupertino", + "countryCode": "US", + "countryName": "United States", + "latitude": 37.3042, + "longitude": -122.0946, + "regionName": "California", + "timezone": "America/Los_Angeles" + }, + "potentialBot": false + }, + { + "referer": null, + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "some_web_crawler/1.4", + "visitLocation": null, + "potentialBot": true + } + ], + "pagination": { + "currentPage": 5, + "pagesCount": 12, + "itemsPerPage": 10, + "itemsInCurrentPage": 10, + "totalItems": 115 } - ], - "pagination": { - "currentPage": 5, - "pagesCount": 12, - "itemsPerPage": 10, - "itemsInCurrentPage": 10, - "totalItems": 115 } } } @@ -151,11 +149,16 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "examples": { + "Short URL not found": { + "$ref": "../examples/short-url-not-found.json" + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v1_tags.json b/docs/swagger/paths/v1_tags.json index 8c3ada73..12cdef81 100644 --- a/docs/swagger/paths/v1_tags.json +++ b/docs/swagger/paths/v1_tags.json @@ -57,23 +57,47 @@ } } } - } - } - }, - "examples": { - "application/json": { - "tags": { - "data": [ - "games", - "php", - "shlink", - "tech" - ] + }, + "examples": { + "Without stats": { + "value": { + "tags": { + "data": [ + "games", + "php", + "shlink", + "tech" + ] + } + } + }, + "With stats": { + "value": { + "tags": { + "data": [ + "games", + "shlink" + ], + "stats": [ + { + "tag": "games", + "shortUrlsCount": 10, + "visitsCount": 521 + }, + { + "tag": "shlink", + "shortUrlsCount": 7, + "visitsCount": 1087 + } + ] + } + } + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { @@ -149,21 +173,9 @@ } } } - }, - "examples": { - "application/json": { - "tags": { - "data": [ - "games", - "php", - "shlink", - "tech" - ] - } - } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { @@ -228,6 +240,13 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "example": { + "title": "Invalid data", + "type": "INVALID_ARGUMENT", + "detail": "Provided data is not valid", + "status": 400, + "invalidElements": ["oldName", "newName"] } } } @@ -238,6 +257,12 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "example": { + "detail": "You are not allowed to rename tags", + "title": "Forbidden tag operation", + "type": "FORBIDDEN_OPERATION", + "status": 403 } } } @@ -248,6 +273,11 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "examples": { + "Tag not found": { + "$ref": "../examples/tag-not-found.json" + } } } } @@ -258,11 +288,19 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "example": { + "detail": "You cannot rename tag foo, because it already exists", + "title": "Tag conflict", + "type": "TAG_CONFLICT", + "status": 409, + "oldName": "bar", + "newName": "foo" } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { @@ -314,11 +352,17 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "example": { + "detail": "You are not allowed to delete tags", + "title": "Forbidden tag operation", + "type": "FORBIDDEN_OPERATION", + "status": 403 } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v2_domains.json b/docs/swagger/paths/v2_domains.json index d92677c1..7568c64a 100644 --- a/docs/swagger/paths/v2_domains.json +++ b/docs/swagger/paths/v2_domains.json @@ -53,51 +53,49 @@ } } } - } - } - }, - "examples": { - "application/json": { - "domains": { - "data": [ - { - "domain": "example.com", - "isDefault": true, - "redirects": { - "baseUrlRedirect": "https://example.com/my-landing-page", - "regular404Redirect": null, - "invalidShortUrlRedirect": "https://example.com/invalid-url" - } - }, - { - "domain": "aaa.com", - "isDefault": false, - "redirects": { - "baseUrlRedirect": null, - "regular404Redirect": null, - "invalidShortUrlRedirect": null - } - }, - { - "domain": "bbb.com", - "isDefault": false, - "redirects": { - "baseUrlRedirect": null, - "regular404Redirect": null, - "invalidShortUrlRedirect": "https://example.com/invalid-url" + }, + "example": { + "domains": { + "data": [ + { + "domain": "example.com", + "isDefault": true, + "redirects": { + "baseUrlRedirect": "https://example.com/my-landing-page", + "regular404Redirect": null, + "invalidShortUrlRedirect": "https://example.com/invalid-url" + } + }, + { + "domain": "aaa.com", + "isDefault": false, + "redirects": { + "baseUrlRedirect": null, + "regular404Redirect": null, + "invalidShortUrlRedirect": null + } + }, + { + "domain": "bbb.com", + "isDefault": false, + "redirects": { + "baseUrlRedirect": null, + "regular404Redirect": null, + "invalidShortUrlRedirect": "https://example.com/invalid-url" + } } + ], + "defaultRedirects": { + "baseUrlRedirect": "https://somewhere.com", + "regular404Redirect": null, + "invalidShortUrlRedirect": null } - ], - "defaultRedirects": { - "baseUrlRedirect": "https://somewhere.com", - "regular404Redirect": null, - "invalidShortUrlRedirect": null } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v2_domains_redirects.json b/docs/swagger/paths/v2_domains_redirects.json index 031e1d43..d4d4338c 100644 --- a/docs/swagger/paths/v2_domains_redirects.json +++ b/docs/swagger/paths/v2_domains_redirects.json @@ -55,15 +55,13 @@ "$ref": "../definitions/NotFoundRedirects.json" } ] + }, + "example": { + "baseUrlRedirect": "https://example.com/my-landing-page", + "regular404Redirect": null, + "invalidShortUrlRedirect": "https://example.com/invalid-url" } } - }, - "examples": { - "application/json": { - "baseUrlRedirect": "https://example.com/my-landing-page", - "regular404Redirect": null, - "invalidShortUrlRedirect": "https://example.com/invalid-url" - } } }, "400": { @@ -95,11 +93,18 @@ } } ] + }, + "example": { + "title": "Invalid data", + "type": "INVALID_ARGUMENT", + "detail": "Provided data is not valid", + "status": 400, + "invalidElements": ["domain", "invalidShortUrlRedirect"] } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v2_mercure-info.json b/docs/swagger/paths/v2_mercure-info.json index 24f7fb5f..a341573f 100644 --- a/docs/swagger/paths/v2_mercure-info.json +++ b/docs/swagger/paths/v2_mercure-info.json @@ -23,15 +23,13 @@ "application/json": { "schema": { "$ref": "../definitions/MercureInfo.json" + }, + "example": { + "mercureHubUrl": "https://example.com/.well-known/mercure", + "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTaGxpbmsiLCJpYXQiOjE1ODY2ODY3MzIsImV4cCI6MTU4Njk0NTkzMiwibWVyY3VyZSI6eyJzdWJzY3JpYmUiOltdfX0.P-519lgU7dFz0bbNlRG1CXyqugGbaHon4kw6fu4QBdQ", + "jwtExpiration": "2020-04-15T12:18:52+02:00" } } - }, - "examples": { - "application/json": { - "mercureHubUrl": "https://example.com/.well-known/mercure", - "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTaGxpbmsiLCJpYXQiOjE1ODY2ODY3MzIsImV4cCI6MTU4Njk0NTkzMiwibWVyY3VyZSI6eyJzdWJzY3JpYmUiOltdfX0.P-519lgU7dFz0bbNlRG1CXyqugGbaHon4kw6fu4QBdQ", - "jwtExpiration": "2020-04-15T12:18:52+02:00" - } } }, "501": { @@ -40,19 +38,17 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "example": { + "title": "Mercure integration not configured", + "type": "MERCURE_NOT_CONFIGURED", + "detail": "This Shlink instance is not integrated with a mercure hub.", + "status": 501 } } - }, - "examples": { - "application/json": { - "title": "Mercure integration not configured", - "type": "MERCURE_NOT_CONFIGURED", - "detail": "This Shlink instance is not integrated with a mercure hub.", - "status": 501 - } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v2_tags_{tag}_visits.json b/docs/swagger/paths/v2_tags_{tag}_visits.json index df1242f6..109cb1d0 100644 --- a/docs/swagger/paths/v2_tags_{tag}_visits.json +++ b/docs/swagger/paths/v2_tags_{tag}_visits.json @@ -94,49 +94,47 @@ } } } - } - } - }, - "examples": { - "application/json": { - "visits": { - "data": [ - { - "referer": "https://twitter.com", - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0", - "visitLocation": null, - "potentialBot": false - }, - { - "referer": "https://t.co", - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "visitLocation": { - "cityName": "Cupertino", - "countryCode": "US", - "countryName": "United States", - "latitude": 37.3042, - "longitude": -122.0946, - "regionName": "California", - "timezone": "America/Los_Angeles" + }, + "example": { + "visits": { + "data": [ + { + "referer": "https://twitter.com", + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0", + "visitLocation": null, + "potentialBot": false }, - "potentialBot": false - }, - { - "referer": null, - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "some_web_crawler/1.4", - "visitLocation": null, - "potentialBot": true + { + "referer": "https://t.co", + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", + "visitLocation": { + "cityName": "Cupertino", + "countryCode": "US", + "countryName": "United States", + "latitude": 37.3042, + "longitude": -122.0946, + "regionName": "California", + "timezone": "America/Los_Angeles" + }, + "potentialBot": false + }, + { + "referer": null, + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "some_web_crawler/1.4", + "visitLocation": null, + "potentialBot": true + } + ], + "pagination": { + "currentPage": 5, + "pagesCount": 12, + "itemsPerPage": 10, + "itemsInCurrentPage": 10, + "totalItems": 115 } - ], - "pagination": { - "currentPage": 5, - "pagesCount": 12, - "itemsPerPage": 10, - "itemsInCurrentPage": 10, - "totalItems": 115 } } } @@ -148,11 +146,16 @@ "application/problem+json": { "schema": { "$ref": "../definitions/Error.json" + }, + "examples": { + "Tag not found": { + "$ref": "../examples/tag-not-found.json" + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v2_visits.json b/docs/swagger/paths/v2_visits.json index 3c712b1f..ded6ac6b 100644 --- a/docs/swagger/paths/v2_visits.json +++ b/docs/swagger/paths/v2_visits.json @@ -28,19 +28,17 @@ "$ref": "../definitions/VisitStats.json" } } - } - } - }, - "examples": { - "application/json": { - "visits": { - "visitsCount": 1569874, - "orphanVisitsCount": 71345 + }, + "example": { + "visits": { + "visitsCount": 1569874, + "orphanVisitsCount": 71345 + } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/v2_visits_orphan.json b/docs/swagger/paths/v2_visits_orphan.json index ce52b197..03d56553 100644 --- a/docs/swagger/paths/v2_visits_orphan.json +++ b/docs/swagger/paths/v2_visits_orphan.json @@ -85,61 +85,59 @@ } } } - } - } - }, - "examples": { - "application/json": { - "visits": { - "data": [ - { - "referer": "https://twitter.com", - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0", - "visitLocation": null, - "potentialBot": false, - "visitedUrl": "https://doma.in", - "type": "base_url" - }, - { - "referer": "https://t.co", - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "visitLocation": { - "cityName": "Cupertino", - "countryCode": "US", - "countryName": "United States", - "latitude": 37.3042, - "longitude": -122.0946, - "regionName": "California", - "timezone": "America/Los_Angeles" + }, + "example": { + "visits": { + "data": [ + { + "referer": "https://twitter.com", + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0", + "visitLocation": null, + "potentialBot": false, + "visitedUrl": "https://doma.in", + "type": "base_url" }, - "potentialBot": false, - "visitedUrl": "https://doma.in/foo", - "type": "invalid_short_url" - }, - { - "referer": null, - "date": "2015-08-20T05:05:03+04:00", - "userAgent": "some_web_crawler/1.4", - "visitLocation": null, - "potentialBot": true, - "visitedUrl": "https://doma.in/foo/bar/baz", - "type": "regular_404" + { + "referer": "https://t.co", + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", + "visitLocation": { + "cityName": "Cupertino", + "countryCode": "US", + "countryName": "United States", + "latitude": 37.3042, + "longitude": -122.0946, + "regionName": "California", + "timezone": "America/Los_Angeles" + }, + "potentialBot": false, + "visitedUrl": "https://doma.in/foo", + "type": "invalid_short_url" + }, + { + "referer": null, + "date": "2015-08-20T05:05:03+04:00", + "userAgent": "some_web_crawler/1.4", + "visitLocation": null, + "potentialBot": true, + "visitedUrl": "https://doma.in/foo/bar/baz", + "type": "regular_404" + } + ], + "pagination": { + "currentPage": 5, + "pagesCount": 12, + "itemsPerPage": 10, + "itemsInCurrentPage": 10, + "totalItems": 115 } - ], - "pagination": { - "currentPage": 5, - "pagesCount": 12, - "itemsPerPage": 10, - "itemsInCurrentPage": 10, - "totalItems": 115 } } } } }, - "500": { + "default": { "description": "Unexpected error.", "content": { "application/problem+json": { diff --git a/docs/swagger/paths/{shortCode}_qr-code.json b/docs/swagger/paths/{shortCode}_qr-code.json index 04a88fd7..104860eb 100644 --- a/docs/swagger/paths/{shortCode}_qr-code.json +++ b/docs/swagger/paths/{shortCode}_qr-code.json @@ -60,6 +60,17 @@ "enum": ["L", "M", "Q", "H"], "default": "L" } + }, + { + "name": "roundBlockSize", + "in": "query", + "description": "Allows to disable block size rounding, which might reduce the readability of the QR code, but ensures no extra margin is added.", + "required": false, + "schema": { + "type": "string", + "enum": ["true", "false"], + "default": "false" + } } ], "responses": { diff --git a/docs/swagger/paths/{shortCode}_qr-code_{size}.json b/docs/swagger/paths/{shortCode}_qr-code_{size}.json index fb5dd33e..54c5152e 100644 --- a/docs/swagger/paths/{shortCode}_qr-code_{size}.json +++ b/docs/swagger/paths/{shortCode}_qr-code_{size}.json @@ -21,7 +21,7 @@ "name": "size", "in": "path", "description": "The size of the image to be returned.", - "required": false, + "required": true, "schema": { "type": "integer", "minimum": 50,