]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - support/doc/api/openapi.yaml
more faithful error description in openapi spec
[github/Chocobozzz/PeerTube.git] / support / doc / api / openapi.yaml
index fd227353d91251ec3617a37178645ff73c2ec4eb..6e82864a0187ed7dfc0034d0d5e0518fe1f51ac4 100644 (file)
@@ -4,12 +4,12 @@ info:
   version: 3.2.0-rc.1
   contact:
     name: PeerTube Community
-    url: 'https://joinpeertube.org'
+    url: https://joinpeertube.org
   license:
     name: AGPLv3.0
-    url: 'https://github.com/Chocobozzz/PeerTube/blob/master/LICENSE'
+    url: https://github.com/Chocobozzz/PeerTube/blob/master/LICENSE
   x-logo:
-    url: 'https://joinpeertube.org/img/brand.png'
+    url: https://joinpeertube.org/img/brand.png
     altText: PeerTube Project Homepage
   description: |
     The PeerTube API is built on HTTP(S) and is RESTful. You can use your favorite
@@ -27,8 +27,8 @@ info:
     # Authentication
 
     When you sign up for an account on a PeerTube instance, you are given the possibility
-    to generate sessions on it, and authenticate there using a session token. Only __one
-    session token can currently be used at a time__.
+    to generate sessions on it, and authenticate there using an access token. Only __one
+    access token can currently be used at a time__.
 
     ## Roles
 
@@ -38,40 +38,58 @@ info:
     # Errors
 
     The API uses standard HTTP status codes to indicate the success or failure
-    of the API call. The body of the response will be JSON in the following
-    formats.
+    of the API call.
 
     ```
+    HTTP 1.1 404 Not Found
+    Content-Type: application/json
+
     {
-      "error": "Account not found" // error debug message
+      "errorCode": 1
+      "error": "Account not found"
     }
     ```
 
-    Validation errors benefit from a more detailed error type and return the HTTP `400 Bad Request` status code.
+    We provide error codes for [a growing number of cases](https://github.com/Chocobozzz/PeerTube/blob/develop/shared/models/server/server-error-code.enum.ts),
+    but it is still optional.
+
+    ### Validation errors
+
+    Each parameter is evaluated on its own against a set of rules before the route validator
+    proceeds with potential testing involving parameter combinations. Errors coming from Validation
+    errors appear earlier and benefit from a more detailed error type:
 
     ```
+    HTTP 1.1 400 Bad Request
+    Content-Type: application/json
+
     {
       "errors": {
-        "id": { // where 'id' is the name of the parameter concerned by the error.
-          "value": "a117eb-c6a9-4756-bb09-2a956239f", // value that triggered the error.
-          "msg": "Should have an valid id",  // error debug message
+        "id": { // 
+          "value": "a117eb-c6a9-4756-bb09-2a956239f",
+          "msg": "Should have a valid id",
           "param": "id",
-          "location": "params" // 'params', 'body', 'header', 'query' or 'cookies'
+          "location": "params"
         }
       }
     }
     ```
 
+    Where `id` is the name of the field concerned by the error, within the route definition.
+    `errors.<field>.location` can be either 'params', 'body', 'header', 'query' or 'cookies', and
+    `errors.<field>.value` reports the value that didn't pass validation whose `errors.<field>.msg`
+    is about.
+
     # Rate limits
 
     We are rate-limiting all endpoints of PeerTube's API. Custom values can be set by administrators:
 
-    | Endpoint                | Calls            | Time frame                |
-    |-------------------------|------------------|---------------------------|
-    | `/*`                    | 50               | 10 seconds                |
-    | `POST /users/token`     | 15               | 5 minutes                 |
-    | `POST /users/register`  | 2<sup>*</sup>    | 5 minutes                 |
-    | `POST /users/ask-send-verify-email` | 3    | 5 minutes                 |
+    | Endpoint (prefix: `/api/v1`) | Calls         | Time frame   |
+    |------------------------------|---------------|--------------|
+    | `/*`                         | 50            | 10 seconds   |
+    | `POST /users/token`          | 15            | 5 minutes    |
+    | `POST /users/register`       | 2<sup>*</sup> | 5 minutes    |
+    | `POST /users/ask-send-verify-email` | 3      | 5 minutes    |
 
     Depending on the endpoint, <sup>*</sup>failed requests are not taken into account. A service
     limit is announced by a `429 Too Many Requests` status code.
@@ -85,9 +103,33 @@ info:
     | `X-RateLimit-Remaining` | Number of remaining requests in the current time period    |
     | `X-RateLimit-Reset`     | Timestamp of end of current time period as UNIX timestamp  |
     | `Retry-After`           | Seconds to delay after the first `429` is received         |
+
+    # CORS
+
+    This API features [Cross-Origin Resource Sharing (CORS)](https://fetch.spec.whatwg.org/),
+    allowing cross-domain communication from the browser for some routes:
+    
+    | Endpoint                    |
+    |------------------------- ---|
+    | `/api/*`                    |
+    | `/download/*`               |
+    | `/lazy-static/*`            |
+    | `/live/segments-sha256/*`   |
+    | `/.well-known/webfinger`    |
+
+    In addition, all routes serving ActivityPub are CORS-enabled for all origins.
 externalDocs:
   url: https://docs.joinpeertube.org/api-rest-reference.html
 tags:
+  - name: Register
+    description: |
+      As a visitor, you can use this API to open an account (if registrations are open on
+      that PeerTube instance). As an admin, you should use the dedicated [User creation 
+      API](#operation/createUser) instead.
+  - name: Session
+    x-displayName: Login/Logout
+    description: |
+      Sessions deal with access tokens over time. Only __one session token can currently be used at a time__.
   - name: Accounts
     description: >
       Accounts encompass remote accounts discovered across the federation,
@@ -211,6 +253,10 @@ tags:
 
       For importing videos as your own, refer to [video imports](#operation/importVideo).
 x-tagGroups:
+  - name: Auth
+    tags:
+      - Register
+      - Session
   - name: Accounts
     tags:
       - Accounts
@@ -558,6 +604,7 @@ paths:
   /users:
     post:
       summary: Create a user
+      operationId: createUser
       security:
         - OAuth2:
           - admin
@@ -674,11 +721,92 @@ paths:
             schema:
               $ref: '#/components/schemas/UpdateUser'
         required: true
+
+  /oauth-clients/local:
+    get:
+      summary: Login prerequisite
+      description: You need to retrieve a client id and secret before [logging in](#operation/getOauthToken).
+      operationId: getOAuthClient
+      tags:
+        - Session
+      responses:
+        '200':
+          description: successful operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/OAuthClient'
+          links:
+            UseOAuthClientToLogin:
+              operationId: getOAuthToken
+              parameters:
+                client_id: '$response.body#/client_id'
+                client_secret: '$response.body#/client_secret'
+  /users/token:
+    post:
+      summary: Login
+      operationId: getOAuthToken
+      description: With your [client id and secret](#operation/getOAuthClient), you can retrieve an access and refresh tokens.
+      tags:
+        - Session
+      requestBody:
+        content:
+          application/x-www-form-urlencoded:
+            schema:
+              oneOf:
+                - $ref: '#/components/schemas/OAuthToken-password'
+                - $ref: '#/components/schemas/OAuthToken-refresh_token'
+              discriminator:
+                propertyName: grant_type
+                mapping:
+                  password: '#/components/schemas/OAuthToken-password'
+                  refresh_token: '#/components/schemas/OAuthToken-refresh_token'
+      responses:
+        '200':
+          description: successful operation
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  token_type:
+                    type: string
+                    example: Bearer
+                  access_token:
+                    type: string
+                    example: 90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0
+                    description: valid for 1 day
+                  refresh_token:
+                    type: string
+                    example: 2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7
+                    description: valid for 2 weeks
+                  expires_in:
+                    type: integer
+                    minimum: 0
+                    example: 14399
+                  refresh_token_expires_in:
+                    type: integer
+                    minimum: 0
+                    example: 1209600
+  /users/revoke-token:
+    post:
+      summary: Logout
+      description: Revokes your access token and its associated refresh token, destroying your current session.
+      operationId: revokeOAuthToken
+      tags:
+        - Session
+      security:
+        - OAuth2: []
+      responses:
+        '200':
+          description: successful operation
+
   /users/register:
     post:
       summary: Register a user
       tags:
         - Users
+        - Register
       responses:
         '204':
           description: successful operation
@@ -688,6 +816,47 @@ paths:
             schema:
               $ref: '#/components/schemas/RegisterUser'
         required: true
+  /users/{id}/verify-email:
+    post:
+      summary: Verify a user
+      description: |
+        Following a user registration, the new user will receive an email asking to click a link
+        containing a secret. 
+      tags:
+        - Users
+        - Register
+      parameters:
+        - $ref: '#/components/parameters/id'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                verificationString:
+                  type: string
+                  format: url
+                isPendingEmail:
+                  type: boolean
+              required:
+                - verificationString
+      responses:
+        '204':
+          description: successful operation
+        '403':
+          description: invalid verification string
+        '404':
+          description: user not found
+  /users/ask-send-verify-email:
+    post:
+      summary: Resend user verification link
+      tags:
+        - Users
+        - Register
+      responses:
+        '204':
+          description: successful operation
+
   /users/me:
     get:
       summary: Get my user information
@@ -1976,10 +2145,12 @@ paths:
                         - $ref: '#/components/schemas/Video/properties/id'
                     startAt:
                       type: integer
+                      format: seconds
                       description: Timestamp in the video that marks the beginning of the report
                       minimum: 0
                     endAt:
                       type: integer
+                      format: seconds
                       description: Timestamp in the video that marks the ending of the report
                       minimum: 0
                 comment:
@@ -2564,13 +2735,13 @@ paths:
               thumbnailfile:
                 contentType: image/jpeg
 
-  /video-playlists/{id}:
+  /video-playlists/{playlistId}:
     get:
       summary: Get a video playlist
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '200':
           description: successful operation
@@ -2589,7 +2760,7 @@ paths:
         '204':
           description: successful operation
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       requestBody:
         content:
           multipart/form-data:
@@ -2624,19 +2795,19 @@ paths:
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '204':
           description: successful operation
 
-  /video-playlists/{id}/videos:
+  /video-playlists/{playlistId}/videos:
     get:
       summary: 'List videos of a playlist'
       tags:
         - Videos
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '200':
           description: successful operation
@@ -2645,14 +2816,14 @@ paths:
               schema:
                 $ref: '#/components/schemas/VideoListResponse'
     post:
-      summary: 'Add a video in a playlist'
+      summary: Add a video in a playlist
       security:
         - OAuth2: []
       tags:
         - Videos
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '200':
           description: successful operation
@@ -2666,6 +2837,7 @@ paths:
                     properties:
                       id:
                         type: integer
+                        example: 2
       requestBody:
         content:
           application/json:
@@ -2673,19 +2845,22 @@ paths:
               type: object
               properties:
                 videoId:
-                  allOf:
+                  oneOf:
+                    - $ref: '#/components/schemas/Video/properties/uuid'
                     - $ref: '#/components/schemas/Video/properties/id'
                   description: Video to add in the playlist
                 startTimestamp:
                   type: integer
-                  description: Start the video at this specific timestamp (in seconds)
+                  format: seconds
+                  description: Start the video at this specific timestamp
                 stopTimestamp:
                   type: integer
-                  description: Stop the video at this specific timestamp (in seconds)
+                  format: seconds
+                  description: Stop the video at this specific timestamp
               required:
                 - videoId
 
-  /video-playlists/{id}/videos/reorder:
+  /video-playlists/{playlistId}/videos/reorder:
     post:
       summary: 'Reorder a playlist'
       security:
@@ -2693,7 +2868,7 @@ paths:
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '204':
           description: successful operation
@@ -2719,15 +2894,15 @@ paths:
                 - startPosition
                 - insertAfterPosition
 
-  /video-playlists/{id}/videos/{playlistElementId}:
+  /video-playlists/{playlistId}/videos/{playlistElementId}:
     put:
-      summary: 'Update a playlist element'
+      summary: Update a playlist element
       security:
         - OAuth2: []
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
         - $ref: '#/components/parameters/playlistElementId'
       responses:
         '204':
@@ -2740,18 +2915,20 @@ paths:
               properties:
                 startTimestamp:
                   type: integer
-                  description: 'Start the video at this specific timestamp (in seconds)'
+                  format: seconds
+                  description: Start the video at this specific timestamp
                 stopTimestamp:
                   type: integer
-                  description: 'Stop the video at this specific timestamp (in seconds)'
+                  format: seconds
+                  description: Stop the video at this specific timestamp
     delete:
-      summary: 'Delete an element from a playlist'
+      summary: Delete an element from a playlist
       security:
         - OAuth2: []
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
         - $ref: '#/components/parameters/playlistElementId'
       responses:
         '204':
@@ -2759,7 +2936,7 @@ paths:
 
   '/users/me/video-playlists/videos-exist':
     get:
-      summary: 'Check video exists in my playlists'
+      summary: Check video exists in my playlists
       security:
         - OAuth2: []
       tags:
@@ -2792,8 +2969,10 @@ paths:
                           type: integer
                         startTimestamp:
                           type: integer
+                          format: seconds
                         stopTimestamp:
                           type: integer
+                          format: seconds
 
   '/accounts/{name}/video-channels':
     get:
@@ -3984,6 +4163,13 @@ components:
         oneOf:
           - $ref: '#/components/schemas/id'
           - $ref: '#/components/schemas/UUIDv4'
+    playlistId:
+      name: playlistId
+      in: path
+      required: true
+      description: Playlist id
+      schema:
+        $ref: '#/components/schemas/VideoPlaylist/properties/id'
     playlistElementId:
       name: playlistElementId
       in: path
@@ -4193,17 +4379,18 @@ components:
       description: |
         Authenticating via OAuth requires the following steps:
         - Have an activated account
-        - [Generate](https://docs.joinpeertube.org/api-rest-getting-started) a
-        Bearer Token for that account at `/api/v1/users/token`
-        - Make authenticated requests, putting *Authorization: Bearer <token\>*
+        - [Generate] an access token for that account at `/api/v1/users/token`.
+        - Make requests with the *Authorization: Bearer <token\>* header
         - Profit, depending on the role assigned to the account
 
-        Note that the __access token is valid for 1 day__ and, and is given
+        Note that the __access token is valid for 1 day__ and is given
         along with a __refresh token valid for 2 weeks__.
+
+        [Generate]: https://docs.joinpeertube.org/api-rest-getting-started
       type: oauth2
       flows:
         password:
-          tokenUrl: 'https://peertube.example.com/api/v1/users/token'
+          tokenUrl: /api/v1/users/token
           scopes:
             admin: Admin scope
             moderator: Moderator scope
@@ -4225,14 +4412,16 @@ components:
       type: string
       description: immutable name of the user, used to find or mention its actor
       example: chocobozzz
-      pattern: '/^[a-z0-9._]{1,50}$/'
+      pattern: '/^[a-z0-9._]+$/'
       minLength: 1
       maxLength: 50
     usernameChannel:
       type: string
       description: immutable name of the channel, used to interact with its actor
       example: framasoft_videos
-      pattern: '/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.:]+$/'
+      pattern: '/^[a-zA-Z0-9\\-_.:]+$/'
+      minLength: 1
+      maxLength: 50
     password:
       type: string
       format: password
@@ -4447,8 +4636,10 @@ components:
           type: integer
         startTimestamp:
           type: integer
+          format: seconds
         stopTimestamp:
           type: integer
+          format: seconds
         video:
           nullable: true
           allOf:
@@ -4597,6 +4788,7 @@ components:
         duration:
           type: integer
           example: 1419
+          format: seconds
           description: duration of the video in seconds
         isLocal:
           type: boolean
@@ -5091,6 +5283,7 @@ components:
       properties:
         currentTime:
           type: integer
+          format: seconds
           description: timestamp within the video, in seconds
           example: 5
     ServerConfig:
@@ -5962,6 +6155,61 @@ components:
         - password
         - email
 
+    OAuthClient:
+      properties:
+        client_id:
+          type: string
+          pattern: /^[a-z0-9]$/
+          maxLength: 32
+          minLength: 32
+          example: v1ikx5hnfop4mdpnci8nsqh93c45rldf
+        client_secret:
+          type: string
+          pattern: /^[a-zA-Z0-9]$/
+          maxLength: 32
+          minLength: 32
+          example: AjWiOapPltI6EnsWQwlFarRtLh4u8tDt
+    OAuthToken-password:
+      allOf:
+        - $ref: '#/components/schemas/OAuthClient'
+        - type: object
+          properties:
+            grant_type:
+              type: string
+              enum:
+                - password
+                - refresh_token
+              default: password
+            username:
+              $ref: '#/components/schemas/User/properties/username'
+            password:
+              $ref: '#/components/schemas/password'
+      required:
+        - client_id
+        - client_secret
+        - grant_type
+        - username
+        - password
+    OAuthToken-refresh_token:
+      allOf:
+        - $ref: '#/components/schemas/OAuthClient'
+        - type: object
+          properties:
+            grant_type:
+              type: string
+              enum:
+                - password
+                - refresh_token
+              default: password
+            refresh_token:
+              type: string
+              example: 2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7
+      required:
+        - client_id
+        - client_secret
+        - grant_type
+        - refresh_token
+
     VideoChannel:
       properties:
         # GET/POST/PUT properties