BIO.RE
User

Remove Avatar

Clear the user's avatarUrl and delete the file from object storage in the background.

POST /api/v1/users/avatar/remove — 🔑 Bearer

Sets User.avatarUrl = null and deletes the avatar file from object storage in the background (fire-and-forget). Idempotent — calling it on a user with no avatar succeeds with no side effect on storage.

This is POST (not DELETE) because some clients / proxies strip bodies on DELETE. Treat it as the canonical "remove" verb for avatars.

Request

No body, no params.

HeaderRequiredNotes
Authorization: Bearer <accessToken>JWT from POST /auth/login

Response

200 OKSuccessOnlyResponseDto

{
  "success": true
}
FieldTypeNotes
successbooleanAlways true on 200

Errors

HTTPcode / i18nKeyReason
401(guard)Missing / invalid bearer token

Side effects

  1. Read current User.avatarUrl (to remember which file to delete).
  2. prisma.user.update({ avatarUrl: null }).
  3. Fire-and-forget: extract object-storage key from the previous URL and delete the file. Failures are logged, not surfaced.
  4. If avatarUrl was already null, no storage call is made — DB write is still issued (idempotent set).

Code samples

curl -X POST https://api.bio.re/api/v1/users/avatar/remove \
  -H "Authorization: Bearer $ACCESS_TOKEN"
async function removeAvatar(accessToken: string): Promise<void> {
  const res = await fetch('https://api.bio.re/api/v1/users/avatar/remove', {
    method: 'POST',
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  const json = await res.json();
  if (!res.ok || !json.success) {
    throw Object.assign(new Error(json?.error?.message ?? 'Remove avatar failed'), {
      code: json?.error?.code,
    });
  }
}
import { useMutation, useQueryClient } from '@tanstack/react-query';

export function useRemoveAvatar() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: async () => {
      const res = await fetch('/api/v1/users/avatar/remove', { method: 'POST' });
      const json = await res.json();
      if (!res.ok || !json.success) {
        throw Object.assign(new Error(json?.error?.message ?? 'Remove avatar failed'), {
          code: json?.error?.code,
          i18nKey: json?.error?.i18nKey,
        });
      }
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['users', 'profile'] });
      qc.invalidateQueries({ queryKey: ['auth', 'me'] });
    },
  });
}

Try it

POST
/api/v1/users/avatar/remove
AuthorizationBearer <token>

In: header

Response Body

application/json

application/json

curl -X POST "https://loading/api/v1/users/avatar/remove"
{
  "success": true
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Source

SourcePathLines
Controllerapps/api-core/src/modules/user/user.controller.ts81–88 (removeAvatar)
DTO (response)apps/api-core/src/common/dto/common-response.dto.tsSuccessOnlyResponseDto
Serviceapps/api-core/src/modules/user/user.service.ts114–135 (removeAvatar)
Object storage cleanupapps/api-core/src/modules/upload/upload.service.tsextractKeyFromUrl(), deleteFile()
Prisma modelpackages/prisma/prisma/schema.prismaUser.avatarUrl

On this page