openapi: 3.0.3 info: title: Codever API description: | API supporting [Codever](https://www.codever.dev). Note and bookmark create/update requests allow at most 13 normalized unique tags. Supplied tags must be an array of nonempty strings; tags are trimmed, lowercased, and deduplicated in first-seen order before counting and persistence. Fourteen unique tags or malformed values return HTTP 400 ValidationError, without saving a partial selection. Bookmark minimum-tag and blocked-tag rules remain in force; note API tags remain optional. AI guidance strongly recommends at most 8 relevant tags where possible, not a separate validation limit. The tag policy is independent of MCP creation enablement. Legacy entries with more than 13 tags remain readable unchanged but must be corrected before an update can be saved; no migration or silent truncation is performed. contact: name: Adrian Matei url: https://github.com/adirochs email: ama@codepedia.org license: name: License MIT url: https://github.com/CodeverDotDev/codever/LICENSE version: 2.0.0 servers: - url: http://localhost:3000/api description: Local server for development - url: https://www.codever.dev/api description: Main (production) server tags: - name: root description: Used to mark the root endpoint - name: version description: Access to the project's version and gitSha1 - name: public-bookmarks description: Access to public bookmarks - name: personal-bookmarks description: Operations performed on personal bookmarks - name: user-data description: Operations performed on user data - name: helper description: Helper endpoints/operations - name: resource-sharing description: Owner-managed, revocable bookmark and note links paths: /: get: description: message with link to Swagger docs tags: - root responses: 200: description: message with link to Swagger docs content: {} /version: get: description: displays the current version of the project (from package.json) and the gitSha1 tags: - version responses: 200: description: OK content: application/json: schema: $ref: '#/components/schemas/Version' /public/bookmarks: get: summary: | Returns list of public bookmarks filtered with query parameters. `page` and `limit` query parameters are used for pagination - if missing default values are used. tags: - public-bookmarks description: | * if `q` param is present they are filtered by the query text contained in it. (takes precedence over `location`) * if `location` param is present returns a list with one **public** bookmark with that URL * else **defaults** to the latest added 100 public bookmarks > The list is empty if not public bookmarks returned for filter parameters: - $ref: "#/components/parameters/searchTextQueryParam" - $ref: "#/components/parameters/pageQueryParam" - $ref: "#/components/parameters/limitQueryParam" - $ref: "#/components/parameters/locationQueryParam" responses: 200: description: OK $ref: '#/components/responses/BookmarkListResponse' /public/bookmarks/shared/{token}: get: summary: Read a bookmark through an active share link tags: - resource-sharing security: [] parameters: - $ref: '#/components/parameters/shareTokenPathParam' responses: 200: description: Current bookmark content allowed for shared viewing headers: Cache-Control: schema: type: string example: no-store Referrer-Policy: schema: type: string example: no-referrer content: application/json: schema: $ref: '#/components/schemas/SharedBookmark' 404: $ref: '#/components/responses/NotFoundError' /public/notes/shared/{token}: get: summary: Read a note through an active share link tags: - resource-sharing security: [] parameters: - $ref: '#/components/parameters/shareTokenPathParam' responses: 200: description: Current note content allowed for shared viewing headers: Cache-Control: schema: type: string example: no-store Referrer-Policy: schema: type: string example: no-referrer content: application/json: schema: $ref: '#/components/schemas/SharedNote' 404: $ref: '#/components/responses/NotFoundError' /public/users/{userId}/profile: get: summary: returns public profile data (user profile & top public tags ) for user tags: - public-user-data parameters: - $ref: "#/components/parameters/userIdPathParam" - $ref: "#/components/parameters/limitQueryParam" responses: 200: description: OK content: application/json: schema: type: object properties: profile: $ref: '#/components/schemas/UserProfile' topUsedPublicTags: type: array items: $ref: '#/components/schemas/TagCount' /webpage-info/scrape: get: description: Returns web page info about the page scraped by `location`, `youtubeVideoId` or `stackoverflowQuestionId` operationId: get-webpage-info tags: - helper parameters: - name: location in: query description: url of the page scraped for data - **this takes precedence over the other query params if present** schema: type: string - name: youtubeVideoId in: query description: id of the youtube video - https://www.youtube.com/watch?v=**Emlc7mkZDQ4** schema: type: string - name: stackoverflowQuestionId in: query description: id of the question from stackoverflow - https://stackoverflow.com/questions/**51391080**/handling-errors-in-express-async-middleware schema: type: string responses: 200: description: contains details about the web page, youtube video or stackoverflow question content: application/json: schema: $ref: '#/components/schemas/WebpageInfo' 403: $ref: '#/components/responses/ForbiddenError' /personal/users/{userId}/share-links: get: summary: List the owner's active bookmark and note links tags: - resource-sharing parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: '#/components/parameters/pageQueryParam' - $ref: '#/components/parameters/limitQueryParam' responses: 200: description: Active links without bearer-token credentials headers: Cache-Control: schema: type: string example: no-store content: application/json: schema: $ref: '#/components/schemas/ShareLinkList' 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' /personal/users/{userId}/share-links/{resourceType}/{resourceId}: parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: '#/components/parameters/shareResourceTypePathParam' - $ref: '#/components/parameters/shareResourceIdPathParam' get: summary: Read the current sharing status for a bookmark or note tags: - resource-sharing responses: 200: description: Inactive status or the current active credential headers: Cache-Control: schema: type: string example: no-store content: application/json: schema: $ref: '#/components/schemas/ShareLinkStatus' 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 404: $ref: '#/components/responses/NotFoundError' post: summary: Explicitly create or reuse the current active share link description: | The request body must be empty. The token is a plaintext bearer credential and is returned only from this owner-scoped operation. tags: - resource-sharing responses: 200: description: Reused active link content: application/json: schema: $ref: '#/components/schemas/ActiveShareLink' 201: description: Newly created link content: application/json: schema: $ref: '#/components/schemas/ActiveShareLink' 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 404: $ref: '#/components/responses/NotFoundError' /personal/users/{userId}/share-links/{shareLinkId}: parameters: - $ref: '#/components/parameters/userIdPathParam' - name: shareLinkId in: path required: true schema: type: string delete: summary: Revoke one owned link generation tags: - resource-sharing responses: 204: description: Link revoked or already inactive headers: Cache-Control: schema: type: string example: no-store 401: $ref: '#/components/responses/UnauthorizedError' 404: $ref: '#/components/responses/NotFoundError' /personal/users/{userId}/bookmarks: get: description: | Returns list of user's bookmarks - might be filtered by query text (`q` with `limit`) > `location` > `orderBy parameters; The parameters precedence is shown via **>** `page` and `limit` query parameters are used for pagination - if missing default values are used. operationId: get-personal-bookmarks tags: - personal-bookmarks parameters: - $ref: "#/components/parameters/userIdPathParam" - $ref: "#/components/parameters/searchTextQueryParam" - $ref: "#/components/parameters/pageQueryParam" - $ref: "#/components/parameters/limitQueryParam" - $ref: "#/components/parameters/locationQueryParam" - name: orderBy in: query description: | It is considered in the abscence of `q` or `location` parameters Possible values: * MOST_LIKES - personal bookmarks most liked by the community * LAST_CREATED - personal bookmarks last added * MOST_USED - personal bookmarks the user (owner) clicked the most schema: type: string enum: [MOST_LIKES, LAST_CREATED, MOST_USED] responses: 200: description: list of user's bookmarks $ref: '#/components/responses/BookmarkListResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' post: description: Create new bookmark for user operationId: create-bookmark tags: - personal-bookmarks parameters: - $ref: '#/components/parameters/userIdPathParam' requestBody: description: Bookmark json data required: true content: application/json: schema: $ref: '#/components/schemas/Bookmark' examples: blog-article: value: name: Cleaner code in an Express REST API with unified error handling – CodepediaOrg location: https://www.codepedia.org/ama/cleaner-code-in-expressjs-rest-api-with-custom-error-handling language: en tags: [nodejs, error-handling, expressjs] publishedOn: 2019-12-02, sourceCodeURL: https://github.com/CodeverDotDev/codever-api description: Shows how you can make your backend ExpressJS REST API cleaner by using custom error handling middleware. Code snippets of before and after refactoring are presented to make the point descriptionHtml:

Shows how you can make your backend ExpressJS REST API cleaner by using custom error handling middleware. Code snippets of before and after refactoring are presented to make the point

userId: 4c617f2b-2bad-498b-a9c6-4e9a8c303798 public: true, lastAccessedAt: 2020-02-15T20:42:19.297Z likeCount: 0 stackoverflow-question: value: name: Create GUID / UUID in JavaScript? location: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript language: en tags: [javascript, guid, uuid] publishedOn: 2008-09-19 sourceCodeURL: description: UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDentifier), according to [RFC 4122](https://www.ietf.org/rfc/rfc4122.txt), are identifiers with a certain uniqueness guarantee.\n\nThe best way to generate them, is to follow implementation instructions in the said RFC, use one of the many community vetted open source implementations.\n\nA popular Open Source tool for working with UUIDs in JavaScript is [node-uuid](https://github.com/kelektiv/node-uuid)\n\nNote that just randomly generating the identifiers byte by byte, or character by character, will not give you the same guarantees as a conforming implementation. Also, very important, systems working with compliant UUIDs may choose not to accept randomly generated ones, and many open source validators will actually check for a valid structure.\n\nAn UUID must have this format:\n```\nxxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx\n```\nWhere the M and N positions may only have certain values. At this time, the only valid values for M are 1, 2, 3, 4 and 5, so randomly generating that position would make most results unacceptable. descriptionHtml:

UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDentifier), according to RFC 4122, are identifiers with a certain uniqueness guarantee.

\n

The best way to generate them, is to follow implementation instructions in the said RFC, use one of the many community vetted open source implementations.

\n

A popular Open Source tool for working with UUIDs in JavaScript is node-uuid

\n

Note that just randomly generating the identifiers byte by byte, or character by character, will not give you the same guarantees as a conforming implementation. Also, very important, systems working with compliant UUIDs may choose not to accept randomly generated ones, and many open source validators will actually check for a valid structure.

\n

An UUID must have this format:

\n
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx\n
\n

Where the M and N positions may only have certain values. At this time, the only valid values for M are 1, 2, 3, 4 and 5, so randomly generating that position would make most results unacceptable.

userId: 4c617f2b-2bad-498b-a9c6-4e9a8c303798 public: true lastAccessedAt: 2020-02-15T20:59:45.447Z likeCount: 0 stackoverflowQuestionId: 105034 youtube-video: value: name: Jake Archibald In The Loop - JSConf.Asia - 35min location: https://www.youtube.com/watch?v=cCOL7MC4Pl0 language: en tags: [javascript, event-loop, browser] publishedOn: 2018-02-09 sourceCodeURL: description: Have you ever had a bug where things were happening in the wrong order, or particular style changes were being ignored? Ever fixed that bug by wrapping a section of code in a setTimeout? Ever found that fix to be unreliable, and played around with the timeout number until it kinda almost always worked? \nThis talk looks at the browser's event loop, the thing that orchestrates the main thread of the browser, which includes JavaScript, events, and rendering. We'll look at the difference between tasks, microtasks, requestAnimationFrame, requestIdleCallback, and where events land. \nHopefully you'll never have to use setTimeout hacks again!\" descriptionHtml:

Have you ever had a bug where things were happening in the wrong order, or particular style changes were being ignored? Ever fixed that bug by wrapping a section of code in a setTimeout? Ever found that fix to be unreliable, and played around with the timeout number until it kinda almost always worked? \nThis talk looks at the browser's event loop, the thing that orchestrates the main thread of the browser, which includes JavaScript, events, and rendering. We'll look at the difference between tasks, microtasks, requestAnimationFrame, requestIdleCallback, and where events land. \nHopefully you'll never have to use setTimeout hacks again!\"

userId: 4c617f2b-2bad-498b-a9c6-4e9a8c303798 public: true lastAccessedAt: 2020-02-15T21:12:12.670Z likeCount: 0 youtubeVideoId: cCOL7MC4Pl0 responses: 201: description: Empty response, http status is relevant headers: location: description: resource url of the newly created bookmark schema: type: object content: {} 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 400: $ref: '#/components/responses/ValidationError' 409: description: | Conflict. It can be triggered either when trying to create a public bookmark that is already present or a bookmark with the location is already present for the user content: application/json: schema: $ref: '#/components/schemas/BasicErrorModel' x-codegen-request-body-name: body delete: description: Batch delete personal bookmarks, given query parameters operationId: delete-personal-bookmarks tags: - personal-bookmarks parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: '#/components/parameters/locationQueryParam' - in: query name: tag description: Private bookmarks with this tag will be batch deleted. It is considered in combination with the `type` param which needs to have the value `private` schema: type: string - in: query name: type schema: type: string enum: - private responses: 204: description: OK (No content) when bookmarks have been deleted content: {} 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' 500: $ref: '#/components/responses/InternalServerError' /personal/users/{userId}/bookmarks/suggested-tags: get: description: Returns suggested tags used in auto-completion when saving a bookmark operationId: get-suggested-tags-for-user tags: - personal-bookmarks parameters: - $ref: '#/components/parameters/userIdPathParam' responses: 200: description: OK content: application/json: schema: properties: tags: type: array items: type: string 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' /personal/users/{userId}/bookmarks/{bookmarkId}: get: description: Returns bookmark for user operationId: get-bookmark-for-user-by-id tags: - personal-bookmarks parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: '#/components/parameters/bookmarkIdPathParam' responses: 200: description: OK content: application/json: schema: $ref: '#/components/schemas/Bookmark' 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' 500: description: internal server error, when unknown server error is catched content: application/json: schema: $ref: '#/components/schemas/BasicErrorModel' put: description: (full) update existing bookmark of user operationId: update-bookmark tags: - personal-bookmarks parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: '#/components/parameters/bookmarkIdPathParam' requestBody: description: Complete bookmark to be updated content: application/json: schema: $ref: '#/components/schemas/Bookmark' required: true responses: 200: description: OK when operation successful and updated bookmark in body content: application/json: schema: $ref: '#/components/schemas/Bookmark' 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' 500: description: internal server error, when unknown server error is catched content: application/json: schema: $ref: '#/components/schemas/BasicErrorModel' x-codegen-request-body-name: body delete: description: deletes bookmark of user operationId: delete-bookmark tags: - personal-bookmarks parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: '#/components/parameters/bookmarkIdPathParam' responses: 204: description: OK (No content) when operation successful and bookmark was removed content: {} 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' 500: $ref: '#/components/responses/InternalServerError' /personal/users/{userId}: description: Operations that work on user data post: description: Creates user data operationId: create-user-data tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' requestBody: description: User data content: application/json: schema: $ref: '#/components/schemas/User' required: true responses: 201: description: OK when operation successful and updated user data content: application/json: schema: $ref: '#/components/schemas/User' get: description: Reads user data operationId: get-user-data tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' responses: 200: description: OK content: application/json: schema: $ref: '#/components/schemas/User' 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 500: $ref: '#/components/responses/InternalServerError' put: description: Updates user data operationId: update-user-data tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' requestBody: description: User data content: application/json: schema: $ref: '#/components/schemas/User' required: true responses: 200: description: OK content: application/json: schema: $ref: '#/components/schemas/User' 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' 500: $ref: '#/components/responses/InternalServerError' delete: description: delete user data operationId: delete-user-data tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' responses: 204: description: OK - No-content 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' 500: $ref: '#/components/responses/InternalServerError' /personal/users/{userId}/history: description: | Returns latest bookmarks accessed, created or updated by the user `page` and `limit` query parameters are used for pagination - if missing default values are used. get: description: Reads user data operationId: get-user-data-history tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: "#/components/parameters/pageQueryParam" - $ref: "#/components/parameters/limitQueryParam" responses: 200: description: OK $ref: '#/components/responses/BookmarkListResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' /personal/users/{userId}/home-tabs: patch: summary: Save the user's landing tab order operationId: update-user-home-tabs tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' requestBody: required: true content: application/json: schema: type: object required: - homeTabs properties: homeTabs: type: array minItems: 4 maxItems: 4 uniqueItems: true items: type: string enum: - feed - history - pinned - read-later responses: 200: description: The saved landing tab order content: application/json: schema: type: object required: - homeTabs properties: homeTabs: type: array items: type: string enum: - feed - history - pinned - read-later 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' /personal/users/{userId}/pinned: description: | Returns the user's pinned resources - bookmarks, notes, and collections mixed in the user's pinned order. Collections are returned without their contents. `page` and `limit` query parameters are used for pagination - if missing default values are used. get: description: Reads the user's pinned resources operationId: get-user-data-pinned tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: "#/components/parameters/pageQueryParam" - $ref: "#/components/parameters/limitQueryParam" responses: 200: description: OK $ref: '#/components/responses/PinnedResourcesResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' patch: description: Replaces the user's pinned entries with the provided typed entries operationId: update-user-data-pinned tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PinnedEntriesInput' responses: 200: description: OK content: application/json: schema: type: object properties: userDataPinnedUpdated: type: boolean 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' /personal/users/{userId}/favorites: description: | Returns bookmarks user added to **Favorites** `page` and `limit` query parameters are used for pagination - if missing default values are used. get: description: Reads user data deprecated: true operationId: get-user-data-favorites tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: "#/components/parameters/pageQueryParam" - $ref: "#/components/parameters/limitQueryParam" responses: 200: description: OK $ref: '#/components/responses/BookmarkListResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' patch: description: Adds or removes a private favorite for an accessible resource operationId: update-user-favorite tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FavoriteMutationInput' responses: 200: description: Updated favorite state content: application/json: schema: $ref: '#/components/schemas/FavoriteMutationResponse' 400: $ref: '#/components/responses/ValidationError' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' 500: $ref: '#/components/responses/InternalServerError' 503: description: Database service unavailable content: application/json: schema: $ref: '#/components/schemas/BasicErrorModel' /personal/users/{userId}/feed: description: | Returns bookmarks to be displayed on user feed (landing page) `page` and `limit` query parameters are used for pagination - if missing default values are used. get: description: Reads user data operationId: get-user-feed-bookmarks tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: "#/components/parameters/pageQueryParam" - $ref: "#/components/parameters/limitQueryParam" responses: 200: description: OK $ref: '#/components/responses/BookmarkListResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' /personal/users/{userId}/read-later: description: | Returns bookmarks the user added to **Read later** `page` and `limit` query parameters are used for pagination - if missing default values are used. get: description: Reads user data operationId: get-user-data-read-later tags: - user-data parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: "#/components/parameters/pageQueryParam" - $ref: "#/components/parameters/limitQueryParam" responses: 200: description: OK $ref: '#/components/responses/BookmarkListResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' /personal/users/{userId}/following/users: get: description: get the user profiles of then ones the `userId` is following operationId: get-follewed-users tags: - user-following parameters: - $ref: '#/components/parameters/userIdPathParam' responses: 200: description: OK $ref: '#/components/responses/UserDataProfilesResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' /personal/users/{userId}/followers: get: description: get the user profiles of `userId`'s followers operationId: get-followers tags: - user-following parameters: - $ref: '#/components/parameters/userIdPathParam' responses: 200: description: OK $ref: '#/components/responses/UserDataProfilesResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' 404: $ref: '#/components/responses/NotFoundError' /personal/users/{userId}/following/users/{followedUserId}: description: Adds `followedUserId` to the `following` list of `userId`, and `userId` to `followers` list of `followedUserId` patch: operationId: add-user-to-following tags: - user-following parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: '#/components/parameters/followedUserIdPathParam' responses: 200: description: OK $ref: '#/components/responses/UserDataResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' /personal/users/{userId}/unfollowing/users/{followedUserId}: description: Removes `followedUserId` from the `following` list of `userId`, and `userId` from the `followers` list of `followedUserId` patch: operationId: remove-user-from-following tags: - user-following parameters: - $ref: '#/components/parameters/userIdPathParam' - $ref: '#/components/parameters/followedUserIdPathParam' responses: 200: description: OK $ref: '#/components/responses/UserDataResponse' 401: $ref: '#/components/responses/UnauthorizedError' 403: $ref: '#/components/responses/ForbiddenError' components: schemas: ActiveShareLink: type: object required: - active - shareLinkId - resourceType - resourceId - createdAt - token properties: active: type: boolean enum: [true] shareLinkId: type: string resourceType: type: string enum: [bookmark, note] resourceId: type: string createdAt: type: string format: date-time token: type: string format: byte description: Plaintext bearer credential; treat as a secret. ShareLinkStatus: oneOf: - type: object required: [active] properties: active: type: boolean enum: [false] - $ref: '#/components/schemas/ActiveShareLink' ShareLinkList: type: object required: [items, page, limit, total] properties: items: type: array items: $ref: '#/components/schemas/ShareLinkListItem' page: type: integer limit: type: integer total: type: integer ShareLinkListItem: type: object required: - shareLinkId - resourceType - resourceId - title - public - createdAt properties: shareLinkId: type: string resourceType: type: string enum: [bookmark, note] resourceId: type: string title: type: string public: type: boolean createdAt: type: string format: date-time SharedBookmark: type: object description: Current bookmark content without owner or grant metadata. properties: _id: type: string type: type: string enum: [bookmark] name: type: string location: type: string description: type: string descriptionHtml: type: string tags: type: array items: type: string copyableFields: type: array items: type: object publishedOn: type: string format: date sourceCodeURL: type: string language: type: string youtubeVideoId: type: string stackoverflowQuestionId: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time SharedNote: type: object description: Current note content; notebook source is included only for notebook notes. properties: _id: type: string type: type: string enum: [note] title: type: string content: type: string contentType: type: string enum: [markdown, notebook] reference: type: string tags: type: array items: type: string copyableFields: type: array items: type: object notebookContent: type: string description: Included only for notebook notes. createdAt: type: string format: date-time updatedAt: type: string format: date-time Bookmark: required: - language - location - name - tags - userId type: object properties: _id: type: string name: type: string location: type: string language: type: string tags: type: array description: | Writes require at least one tag and at most 13 unique tags after trimming, lowercasing and deduplication in first-seen order. Empty/non-string values and tags starting with "awesome" are rejected. AI recommends at most 8 relevant tags where possible. No raw maxItems/uniqueItems constraint is applied because duplicate inputs are accepted and legacy reads are unchanged. x-max-normalized-items: 13 items: type: string description: type: string descriptionHtml: type: string updatedAt: type: string format: date-time createdAt: type: string format: date-time lastAccessedAt: type: string format: date-time publishedOn: type: string format: date public: type: boolean userId: type: string likeCount: type: number sourceCodeURL: type: string ownerVisitCount: type: number youtubeVideoId: type: string stackoverflowQuestionId: type: string UserProfile: properties: displayName: type: string summary: type: string websiteLink: type: string twitterLink: type: string githubLink: type: string linkedinLink: type: string Search: required: - text - searchDomain properties: text: type: string lastAccessedAt: type: string format: date-time searchDomain: type: string enum: - public - personal count: type: integer Following: properties: users: type: array items: type: string tags: type: array items: type: string PinnedEntry: type: object description: A reference to a pinned bookmark, note, or collection required: - type - id properties: type: type: string enum: - bookmark - note - collection id: type: string description: id of the pinned bookmark, note, or collection PinnedEntriesInput: type: object required: - pinned properties: pinned: type: array items: $ref: '#/components/schemas/PinnedEntry' FavoriteMutationInput: type: object required: - resourceType - resourceId - favorite properties: resourceType: type: string enum: - bookmark - note resourceId: type: string description: MongoDB ID of the bookmark or note favorite: type: boolean description: Whether the resource should be favorited FavoriteMutationResponse: type: object required: - resourceType - resourceId - favorite properties: resourceType: type: string enum: - bookmark - note resourceId: type: string favorite: type: boolean PinnedNote: type: object description: A pinned note properties: _id: type: string title: type: string content: type: string contentType: type: string enum: - markdown - notebook tags: type: array items: type: string userId: type: string public: type: boolean PinnedCollection: type: object description: A pinned collection returned without its contents required: - _id - type - name properties: _id: type: string type: type: string enum: - collection name: type: string color: type: string userId: type: string PinnedResource: description: A pinned bookmark, note, or collection, in the user's pinned order oneOf: - $ref: '#/components/schemas/Bookmark' - $ref: '#/components/schemas/PinnedNote' - $ref: '#/components/schemas/PinnedCollection' User: required: - userId properties: userId: type: string profile: $ref: '#/components/schemas/UserProfile' searches: type: array items: $ref: '#/components/schemas/Search' readLater: type: array items: type: string likes: type: array items: type: string watchedTags: type: array items: type: string pinned: type: array items: $ref: '#/components/schemas/PinnedEntry' favorites: type: array items: type: string favoriteNotes: type: array items: type: string history: type: array items: type: string homeTabs: type: array minItems: 4 maxItems: 4 uniqueItems: true items: type: string enum: - feed - history - pinned - read-later followers: type: array items: type: string following: $ref: '#/components/schemas/Following' UserDataProfile: required: - userId properties: userId: type: string profile: $ref: '#/components/schemas/UserProfile' TagCount: type: object required: - name - count properties: name: type: string count: type: integer description: how much many times the tag has been used in the specific context BasicErrorModel: type: object required: - httpStatus - message properties: httpStatus: type: integer message: type: string type: type: string description: specify error Type (e.g. 'MongoError') stack: type: string description: the stacktrace of the error - it is filled only in "development" mode ValidationErrorModel: allOf: - $ref: '#/components/schemas/BasicErrorModel' - type: object required: - validationErrors - httpStatus properties: httpStatus: type: integer enum: [400] validationErrors: type: array items: type: string WebpageInfo: type: object properties: title: type: string metaDescription: type: string tags: description: these are avaialble for youtube videos and stackoverflow questions type: array items: type: string publishedOn: type: string format: date Version: type: object required: - version - gitSha1 properties: version: type: string gitSha1: type: string parameters: shareTokenPathParam: name: token in: path required: true description: 43-character URL-safe bearer credential. schema: type: string pattern: '^[A-Za-z0-9_-]{43}$' shareResourceTypePathParam: name: resourceType in: path required: true schema: type: string enum: [bookmark, note] shareResourceIdPathParam: name: resourceId in: path required: true schema: type: string userIdPathParam: name: userId in: path description: keycloak user id required: true schema: type: string default: 4c617f2b-2bad-498b-a9c6-4e9a8c303798 followedUserIdPathParam: name: followedUserId in: path description: the id of the user to be following required: true schema: type: string bookmarkIdPathParam: name: bookmarkId in: path description: id of the bookmark required: true schema: type: string searchTextQueryParam: name: q in: query description: | search query (terms are separated by space). There are special filters available: * `lang:iso_language_code` - e.g. `lang:en` for English, `lang:es` for Spanish and `lang:de` for German bookmarks * `site:site_URL` - e.g. `site:codepedia.org` bookmarks only from website [www.codepedia.org](https://www.codepedia.org) * `userId:UUID-user` - to be used only when querying **public bookmarks** submitted by the user with `userId` * `private:only` - makes sense **only** when used for querying **personal bookmarks** schema: type: string examples: # Multiple examples german: value: 'lang:de' # Example value summary: Will look only for bookmarks in German site: value: 'site:codepedia.org' summary: Wille look only for bookmarks with the domain **codepedia.org** complex: value: 'exception handling [java] site:codepedia.org' summary: Wille look only for bookmarks with terms "exception" and "handling" tagged with "java" and the domain **codepedia.org** complex-private-only: value: 'exception handling [java] site:wiki.my-corporation.com private:only' summary: Same as above but only within **private** bookmarks pageQueryParam: name: page in: query description: | Pagination query param - it is used to skip results in combination with `limit` query param Defaults to **1** and in this case **no results are skipped** required: false schema: type: integer default: 1 format: int32 limitQueryParam: name: limit in: query description: Limits the number of returned results (used in combination with queryParam) required: false schema: type: integer default: 55 format: int32 locationQueryParam: name: location in: query description: location of the bookmark, usually an URL required: false schema: type: string securitySchemes: bearerAuth: # arbitrary name for the security scheme type: http scheme: bearer bearerFormat: JWT responses: BookmarkListResponse: description: List of bookmarks content: application/json: schema: type: array items: $ref: '#/components/schemas/Bookmark' PinnedResourcesResponse: description: List of pinned bookmarks, notes, and collections in the user's pinned order content: application/json: schema: type: array items: $ref: '#/components/schemas/PinnedResource' UserDataResponse: description: User data content: application/json: schema: $ref: '#/components/schemas/User' UserDataProfilesResponse: description: List of user profiles content: application/json: schema: type: array items: $ref: '#/components/schemas/UserDataProfile' ForbiddenError: description: Access token is missing or invalid UnauthorizedError: description: unauthorized (you need to have a valid token) and userId must match the subject in token content: application/json: schema: $ref: '#/components/schemas/BasicErrorModel' NotFoundError: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/BasicErrorModel' InternalServerError: description: Internal server error, when unknown server error is catched content: application/json: schema: $ref: '#/components/schemas/BasicErrorModel' ValidationError: description: Bad request, validation errors content: application/json: schema: $ref: '#/components/schemas/ValidationErrorModel' # 2) Apply the security globally to all operations security: - bearerAuth: [] # use the same name as above