diff --git a/.gitignore b/.gitignore index aebab397..2a7fb730 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.lock vendor/ .env data/database.sqlite +docs/swagger-ui diff --git a/docs/swagger.json b/docs/swagger.json deleted file mode 100644 index b3b7a5c5..00000000 --- a/docs/swagger.json +++ /dev/null @@ -1,448 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "Shlink", - "description": "Shlink, the self-hosted URL shortener", - "version": "1.2.0" - }, - "schemes": [ - "https" - ], - "basePath": "/rest", - "produces": [ - "application/json" - ], - - "paths": { - "/v1/authenticate": { - "post": { - "description": "Performs an authentication", - "parameters": [ - { - "name": "apiKey", - "in": "formData", - "description": "The API key to authenticate with", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "The authentication worked.", - "schema": { - "type": "object", - "properties": { - "token": { - "type": "string", - "description": "The authentication token that needs to be sent in the Authorization header" - } - } - } - }, - "400": { - "description": "An API key was not provided.", - "schema": { - "$ref": "#/definitions/Error" - } - }, - "401": { - "description": "The API key is incorrect, is disabled or has expired.", - "schema": { - "$ref": "#/definitions/Error" - } - }, - "500": { - "description": "Unexpected error.", - "schema": { - "$ref": "#/definitions/Error" - } - } - } - } - }, - "/v1/short-codes": { - "get": { - "description": "Returns the list of short codes", - "parameters": [ - { - "name": "page", - "in": "query", - "description": "The page to be displayed. Defaults to 1", - "required": false, - "type": "integer" - }, - { - "name": "searchTerm", - "in": "query", - "description": "A query used to filter results by searching for it on the longUrl and shortCode fields. (Since v1.3.0)", - "required": false, - "type": "string" - }, - { - "name": "tags", - "in": "query", - "description": "A list of tags used to filter the resultset. Only short URLs tagged with at least one of the provided tags will be returned. (Since v1.3.0)", - "required": false, - "type": "array", - "schema": { - "items": { - "type": "string" - } - } - }, - { - "name": "orderBy", - "in": "query", - "description": "The field from which you want to order the result. (Since v1.3.0)", - "enum": [ - "originalUrl", - "shortCode", - "dateCreated", - "visits" - ], - "required": false, - "type": "string" - }, - { - "$ref": "#/parameters/Authorization" - } - ], - "responses": { - "200": { - "description": "The list of short URLs", - "schema": { - "type": "object", - "properties": { - "shortUrls": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/ShortUrl" - } - }, - "pagination": { - "$ref": "#/definitions/Pagination" - } - } - } - } - } - }, - "500": { - "description": "Unexpected error.", - "schema": { - "$ref": "#/definitions/Error" - } - } - } - }, - "post": { - "description": "Creates a new short code", - "parameters": [ - { - "name": "longUrl", - "in": "formData", - "description": "The URL to parse", - "required": true, - "type": "string" - }, - { - "name": "tags", - "in": "formData", - "description": "The URL to parse", - "required": false, - "type": "array", - "items": { - "type": "string" - } - }, - { - "$ref": "#/parameters/Authorization" - } - ], - "responses": { - "200": { - "description": "The result of parsing the long URL", - "schema": { - "type": "object", - "properties": { - "longUrl": { - "type": "string", - "description": "The original long URL that has been parsed" - }, - "shortUrl": { - "type": "string", - "description": "The generated short URL" - }, - "shortCode": { - "type": "string", - "description": "the short code that is being used in the short URL" - } - } - } - }, - "400": { - "description": "The long URL was not provided or is invalid.", - "schema": { - "$ref": "#/definitions/Error" - } - }, - "500": { - "description": "Unexpected error.", - "schema": { - "$ref": "#/definitions/Error" - } - } - } - } - }, - "/v1/short-codes/{shortCode}": { - "get": { - "description": "Get the long URL behind a short code.", - "parameters": [ - { - "name": "shortCode", - "in": "path", - "type": "string", - "description": "The short code to resolve.", - "required": true - }, - { - "$ref": "#/parameters/Authorization" - } - ], - "responses": { - "200": { - "description": "The long URL behind a short code.", - "schema": { - "type": "object", - "properties": { - "longUrl": { - "type": "string", - "description": "The original long URL behind the short code." - } - } - } - }, - "400": { - "description": "Provided shortCode does not match the character set currently used by the app to generate short codes.", - "schema": { - "$ref": "#/definitions/Error" - } - }, - "404": { - "description": "No URL was found for provided short code.", - "schema": { - "$ref": "#/definitions/Error" - } - }, - "500": { - "description": "Unexpected error.", - "schema": { - "$ref": "#/definitions/Error" - } - } - } - } - }, - "/v1/short-codes/{shortCode}/visits": { - "get": { - "description": "Get the list of visits on provided short code.", - "parameters": [ - { - "name": "shortCode", - "in": "path", - "type": "string", - "description": "The shortCode from which we want to get the visits.", - "required": true - }, - { - "$ref": "#/parameters/Authorization" - } - ], - "responses": { - "200": { - "description": "List of visits.", - "schema": { - "type": "object", - "properties": { - "visits": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/Visit" - } - } - } - } - } - } - }, - "404": { - "description": "The short code does not belong to any short URL.", - "schema": { - "$ref": "#/definitions/Error" - } - }, - "500": { - "description": "Unexpected error.", - "schema": { - "$ref": "#/definitions/Error" - } - } - } - } - }, - "/v1/short-codes/{shortCode}/tags": { - "put": { - "description": "Edit the tags on provided short code.", - "parameters": [ - { - "name": "shortCode", - "in": "path", - "type": "string", - "description": "The shortCode in which we want to edit tags.", - "required": true - }, - { - "name": "tags", - "in": "formData", - "type": "array", - "items": { - "type": "string" - }, - "description": "The list of tags to set to the short URL.", - "required": true - }, - { - "$ref": "#/parameters/Authorization" - } - ], - "responses": { - "200": { - "description": "List of tags.", - "schema": { - "type": "object", - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "description": "The request body does not contain a \"tags\" param with array type.", - "schema": { - "$ref": "#/definitions/Error" - } - }, - "404": { - "description": "No short URL was found for provided short code.", - "schema": { - "$ref": "#/definitions/Error" - } - }, - "500": { - "description": "Unexpected error.", - "schema": { - "$ref": "#/definitions/Error" - } - } - } - } - } - }, - - "definitions": { - "ShortUrl": { - "type": "object", - "properties": { - "shortCode": { - "type": "string", - "description": "The short code for this short URL." - }, - "originalUrl": { - "type": "string", - "description": "The original long URL." - }, - "dateCreated": { - "type": "string", - "format": "date-time", - "description": "The date in which the short URL was created in ISO format." - }, - "visitsCount": { - "type": "integer", - "description": "The number of visits that this short URL has recieved." - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "A list of tags applied to this short URL" - } - } - }, - "Visit": { - "type": "object", - "properties": { - "referer": { - "type": "string" - }, - "date": { - "type": "string", - "format": "date-time" - }, - "remoteAddr": { - "type": "string" - }, - "userAgent": { - "type": "string" - } - } - }, - "Error": { - "type": "object", - "properties": { - "code": { - "type": "string", - "description": "A machine unique code" - }, - "message": { - "type": "string", - "description": "A human-friendly error message" - } - } - }, - "Pagination": { - "type": "object", - "properties": { - "currentPage": { - "type": "integer", - "description": "The number of current page being displayed." - }, - "pagesCount": { - "type": "integer", - "description": "The total number of pages that can be displayed." - } - } - } - }, - - "parameters": { - "Authorization": { - "name": "Authorization", - "in": "header", - "description": "The authorization token with Bearer type", - "required": true, - "type": "string" - } - } -} diff --git a/docs/swagger/definitions/Error.json b/docs/swagger/definitions/Error.json new file mode 100644 index 00000000..3585227d --- /dev/null +++ b/docs/swagger/definitions/Error.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "A machine unique code" + }, + "message": { + "type": "string", + "description": "A human-friendly error message" + } + } +} diff --git a/docs/swagger/definitions/Pagination.json b/docs/swagger/definitions/Pagination.json new file mode 100644 index 00000000..e9b731ef --- /dev/null +++ b/docs/swagger/definitions/Pagination.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "currentPage": { + "type": "integer", + "description": "The number of current page being displayed." + }, + "pagesCount": { + "type": "integer", + "description": "The total number of pages that can be displayed." + } + } +} diff --git a/docs/swagger/definitions/ShortUrl.json b/docs/swagger/definitions/ShortUrl.json new file mode 100644 index 00000000..6b1750b8 --- /dev/null +++ b/docs/swagger/definitions/ShortUrl.json @@ -0,0 +1,29 @@ +{ + "type": "object", + "properties": { + "shortCode": { + "type": "string", + "description": "The short code for this short URL." + }, + "originalUrl": { + "type": "string", + "description": "The original long URL." + }, + "dateCreated": { + "type": "string", + "format": "date-time", + "description": "The date in which the short URL was created in ISO format." + }, + "visitsCount": { + "type": "integer", + "description": "The number of visits that this short URL has recieved." + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of tags applied to this short URL" + } + } +} diff --git a/docs/swagger/definitions/Visit.json b/docs/swagger/definitions/Visit.json new file mode 100644 index 00000000..8e0bc944 --- /dev/null +++ b/docs/swagger/definitions/Visit.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "properties": { + "referer": { + "type": "string" + }, + "date": { + "type": "string", + "format": "date-time" + }, + "remoteAddr": { + "type": "string" + }, + "userAgent": { + "type": "string" + } + } +} diff --git a/docs/swagger/endpoints/v1_authenticate.json b/docs/swagger/endpoints/v1_authenticate.json new file mode 100644 index 00000000..d7828f52 --- /dev/null +++ b/docs/swagger/endpoints/v1_authenticate.json @@ -0,0 +1,46 @@ +{ + "post": { + "description": "Performs an authentication", + "parameters": [ + { + "name": "apiKey", + "in": "formData", + "description": "The API key to authenticate with", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "The authentication worked.", + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "The authentication token that needs to be sent in the Authorization header" + } + } + } + }, + "400": { + "description": "An API key was not provided.", + "schema": { + "$ref": "../definitions/Error.json" + } + }, + "401": { + "description": "The API key is incorrect, is disabled or has expired.", + "schema": { + "$ref": "../definitions/Error.json" + } + }, + "500": { + "description": "Unexpected error.", + "schema": { + "$ref": "../definitions/Error.json" + } + } + } + } +} diff --git a/docs/swagger/endpoints/v1_short-codes.json b/docs/swagger/endpoints/v1_short-codes.json new file mode 100644 index 00000000..27448d4d --- /dev/null +++ b/docs/swagger/endpoints/v1_short-codes.json @@ -0,0 +1,138 @@ +{ + "get": { + "description": "Returns the list of short codes", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "The page to be displayed. Defaults to 1", + "required": false, + "type": "integer" + }, + { + "name": "searchTerm", + "in": "query", + "description": "A query used to filter results by searching for it on the longUrl and shortCode fields. (Since v1.3.0)", + "required": false, + "type": "string" + }, + { + "name": "tags", + "in": "query", + "description": "A list of tags used to filter the resultset. Only short URLs tagged with at least one of the provided tags will be returned. (Since v1.3.0)", + "required": false, + "type": "array", + "schema": { + "items": { + "type": "string" + } + } + }, + { + "name": "orderBy", + "in": "query", + "description": "The field from which you want to order the result. (Since v1.3.0)", + "enum": [ + "originalUrl", + "shortCode", + "dateCreated", + "visits" + ], + "required": false, + "type": "string" + }, + { + "$ref": "../parameters/Authorization.json" + } + ], + "responses": { + "200": { + "description": "The list of short URLs", + "schema": { + "type": "object", + "properties": { + "shortUrls": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "../definitions/ShortUrl.json" + } + }, + "pagination": { + "$ref": "../definitions/Pagination.json" + } + } + } + } + } + }, + "500": { + "description": "Unexpected error.", + "schema": { + "$ref": "../definitions/Error.json" + } + } + } + }, + "post": { + "description": "Creates a new short code", + "parameters": [ + { + "name": "longUrl", + "in": "formData", + "description": "The URL to parse", + "required": true, + "type": "string" + }, + { + "name": "tags", + "in": "formData", + "description": "The URL to parse", + "required": false, + "type": "array", + "items": { + "type": "string" + } + }, + { + "$ref": "../parameters/Authorization.json" + } + ], + "responses": { + "200": { + "description": "The result of parsing the long URL", + "schema": { + "type": "object", + "properties": { + "longUrl": { + "type": "string", + "description": "The original long URL that has been parsed" + }, + "shortUrl": { + "type": "string", + "description": "The generated short URL" + }, + "shortCode": { + "type": "string", + "description": "the short code that is being used in the short URL" + } + } + } + }, + "400": { + "description": "The long URL was not provided or is invalid.", + "schema": { + "$ref": "../definitions/Error.json" + } + }, + "500": { + "description": "Unexpected error.", + "schema": { + "$ref": "../definitions/Error.json" + } + } + } + } +} diff --git a/docs/swagger/endpoints/v1_short-codes_{shortCode}.json b/docs/swagger/endpoints/v1_short-codes_{shortCode}.json new file mode 100644 index 00000000..1a24dcf5 --- /dev/null +++ b/docs/swagger/endpoints/v1_short-codes_{shortCode}.json @@ -0,0 +1,49 @@ +{ + "get": { + "description": "Get the long URL behind a short code.", + "parameters": [ + { + "name": "shortCode", + "in": "path", + "type": "string", + "description": "The short code to resolve.", + "required": true + }, + { + "$ref": "../parameters/Authorization.json" + } + ], + "responses": { + "200": { + "description": "The long URL behind a short code.", + "schema": { + "type": "object", + "properties": { + "longUrl": { + "type": "string", + "description": "The original long URL behind the short code." + } + } + } + }, + "400": { + "description": "Provided shortCode does not match the character set currently used by the app to generate short codes.", + "schema": { + "$ref": "../definitions/Error.json" + } + }, + "404": { + "description": "No URL was found for provided short code.", + "schema": { + "$ref": "../definitions/Error.json" + } + }, + "500": { + "description": "Unexpected error.", + "schema": { + "$ref": "../definitions/Error.json" + } + } + } + } +} diff --git a/docs/swagger/endpoints/v1_short-codes_{shortCode}_tags.json b/docs/swagger/endpoints/v1_short-codes_{shortCode}_tags.json new file mode 100644 index 00000000..8ff67199 --- /dev/null +++ b/docs/swagger/endpoints/v1_short-codes_{shortCode}_tags.json @@ -0,0 +1,61 @@ +{ + "put": { + "description": "Edit the tags on provided short code.", + "parameters": [ + { + "name": "shortCode", + "in": "path", + "type": "string", + "description": "The shortCode in which we want to edit tags.", + "required": true + }, + { + "name": "tags", + "in": "formData", + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of tags to set to the short URL.", + "required": true + }, + { + "$ref": "../parameters/Authorization.json" + } + ], + "responses": { + "200": { + "description": "List of tags.", + "schema": { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "description": "The request body does not contain a \"tags\" param with array type.", + "schema": { + "$ref": "../definitions/Error.json" + } + }, + "404": { + "description": "No short URL was found for provided short code.", + "schema": { + "$ref": "../definitions/Error.json" + } + }, + "500": { + "description": "Unexpected error.", + "schema": { + "$ref": "../definitions/Error.json" + } + } + } + } +} diff --git a/docs/swagger/endpoints/v1_short-codes_{shortCode}_visits.json b/docs/swagger/endpoints/v1_short-codes_{shortCode}_visits.json new file mode 100644 index 00000000..3b416eb0 --- /dev/null +++ b/docs/swagger/endpoints/v1_short-codes_{shortCode}_visits.json @@ -0,0 +1,50 @@ +{ + "get": { + "description": "Get the list of visits on provided short code.", + "parameters": [ + { + "name": "shortCode", + "in": "path", + "type": "string", + "description": "The shortCode from which we want to get the visits.", + "required": true + }, + { + "$ref": "../parameters/Authorization.json" + } + ], + "responses": { + "200": { + "description": "List of visits.", + "schema": { + "type": "object", + "properties": { + "visits": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "../definitions/Visit.json" + } + } + } + } + } + } + }, + "404": { + "description": "The short code does not belong to any short URL.", + "schema": { + "$ref": "../definitions/Error.json" + } + }, + "500": { + "description": "Unexpected error.", + "schema": { + "$ref": "../definitions/Error.json" + } + } + } + } +} diff --git a/docs/swagger/parameters/Authorization.json b/docs/swagger/parameters/Authorization.json new file mode 100644 index 00000000..54386de6 --- /dev/null +++ b/docs/swagger/parameters/Authorization.json @@ -0,0 +1,7 @@ +{ + "name": "Authorization", + "in": "header", + "description": "The authorization token with Bearer type", + "required": true, + "type": "string" +} diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json new file mode 100644 index 00000000..bdc3c023 --- /dev/null +++ b/docs/swagger/swagger.json @@ -0,0 +1,33 @@ +{ + "swagger": "2.0", + "info": { + "title": "Shlink", + "description": "Shlink, the self-hosted URL shortener", + "version": "1.2.0" + }, + "schemes": [ + "https" + ], + "basePath": "/rest", + "produces": [ + "application/json" + ], + + "paths": { + "/v1/authenticate": { + "$ref": "endpoints/v1_authenticate.json" + }, + "/v1/short-codes": { + "$ref": "endpoints/v1_short-codes.json" + }, + "/v1/short-codes/{shortCode}": { + "$ref": "endpoints/v1_short-codes_{shortCode}.json" + }, + "/v1/short-codes/{shortCode}/visits": { + "$ref": "endpoints/v1_short-codes_{shortCode}_visits.json" + }, + "/v1/short-codes/{shortCode}/tags": { + "$ref": "endpoints/v1_short-codes_{shortCode}_tags.json" + } + } +}