loopbackio / loopbackio/loopback-next

Unsupproted Media Type Error with application/json-patch+json

Ouverte
#7,617 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

bug REST
Langage dominant
TypeScript
Étoiles
5.1k
Forks
1.1k
Merge moyen
2 j 21 h
PR mergées (30 j)
27

Description

Steps to reproduce

  1. Run application
  2. Send patch request with application/json-patch+json media type

Current Behavior

UnsupportedMediaTypeError: Content-type application/json-patch+json does not match [application/json]

Expected Behavior

I expect the application to accept application/json-patch+json media type

Link to reproduction sandbox

Work won't allow me to put code in sandbox.

Additional information

win32 x64 14.16.0
+-- @loopback/authentication@7.3.1
+-- @loopback/authentication-passport@3.2.1
+-- @loopback/boot@3.4.1
+-- @loopback/core@2.16.1
+-- @loopback/repository@3.7.0
+-- @loopback/rest@9.3.1
+-- @loopback/rest-explorer@3.3.1
+-- @loopback/security@0.5.1
+-- @loopback/service-proxy@3.2.1
+-- UNMET DEPENDENCY @opsdash/loopback-okta-auth@^0.0.1npm
+-- @raad/loopback-logging@2.0.1
+-- @raad/loopback-problems@1.0.1ERR! peer dep missing: eslint-plugin-spellcheck@^0.0.17, required by @raad/eslint-config-codestyle-typescript@5.0.5
npm+-- loopback-connector-mongodb@6.0.1
ERR! missing: @opsdash/loopback-okta-auth@^0.0.1, required by @opsdash/user-service@0.0.1

specific controller

  @patch('/users/me')
  @response(200, {
    description: 'User model instance',
    content: { 'application/json': { schema: getModelSchemaRef(User) } },
  })
  @authenticate(OKTA_AUTH_TOKEN_STRATEGY_NAME)
  async updateUser(
    @requestBody({
      description: 'User model instance',
      required: true,
      content: {
        'application/json-patch+json': {
          schema: {
            type: 'array',
            items: getModelSchemaRef(JsonPatch),
          },
        },
      },
    })
    patches: JsonPatch[],
  ): Promise<User> {
    let user = await this.userRepository.findOne({
      where: { key: this.userProfile.id },
    });

    if (!user) {
      throw new HttpErrors.NotFound();
    }

    await this.userRepository.jsonPatch(user, patches);

    user = await this.userRepository.findOne({
      where: { key: this.userProfile.id },
    });

    if (!user) {
      throw new HttpErrors.NotFound();
    }

    return user;
  }

JsonPatch model

import { Model, model, property } from '@loopback/repository';
import { JSONValue } from '@loopback/core';

@model()
export class JsonPatch extends Model {
  @property({
    type: 'string',
    required: true,
    jsonSchema: {
      enum: ['add', 'remove', 'replace', 'move', 'copy', 'test', '_get'],
    },
  })
  op: 'add' & 'remove' & 'replace' & 'move' & 'copy' & 'test' & '_get';

  @property({
    type: 'string',
    required: true,
  })
  path: string;

  @property({
    type: 'object',
  })
  value?: JSONValue;

  @property({
    type: 'string',
  })
  from?: string;

  constructor(data?: Partial<JsonPatch>) {
    super(data);
  }
}

export interface JsonPatchRelations {
  // describe navigational properties here
}

export type JsonPatchWithRelations = JsonPatch & JsonPatchRelations;

error stack

[2021-07-14T14:03:02.131Z] ERROR (UserService/4892 on CHRDEV42725):
    requestId: "RequestContext-QuzkmMDRTbiTuMkFzvMHAA-19"
    correlationId: "QuzkmMDRTbiTuMkFzvMHAA-20"
    event: "rest.sequence.actions.reject"
    err: {
      "type": "UnprocessableEntityError",
      "message": "The request body is invalid. See error object `details` property for more info.",
      "stack":
          UnprocessableEntityError: The request body is invalid. See error object `details` property for more info.
              at Object.invalidRequestBody (D:\Workspace\javascript\opsdash-services-test\opsdash-services\packages\user-service\node_modules\@loopback\rest\src\rest-http-error.ts:59:7)
              at validateValueAgainstSchema (D:\Workspace\javascript\opsdash-services-test\opsdash-services\packages\user-service\node_modules\@loopback\rest\src\validation\request-body.validator.ts:182:34)   
              at processTicksAndRejections (internal/process/task_queues.js:93:5)
              at Object.validateRequestBody (D:\Workspace\javascript\opsdash-services-test\opsdash-services\packages\user-service\node_modules\@loopback\rest\src\validation\request-body.validator.ts:75:3)     
              at buildOperationArguments (D:\Workspace\javascript\opsdash-services-test\opsdash-services\packages\user-service\node_modules\@loopback\rest\src\parser.ts:92:3)
      "code": "VALIDATION_FAILED",
      "details": [
        {
          "path": "/0/value",
          "code": "type",
          "message": "should be object",
          "info": {
            "type": "object"
          }
        },
        {
          "path": "/1/value",
          "code": "type",
          "message": "should be object",
          "info": {
            "type": "object"
          }
        },
        {
          "path": "/2/value",
          "code": "type",
          "message": "should be object",
          "info": {
            "type": "object"
          }
        }
      ],
      "status": 422,
      "statusCode": 422,
      "expose": true
    }
[2021-07-14T14:03:02.144Z] INFO (UserService/4892 on CHRDEV42725):
    requestId: "RequestContext-QuzkmMDRTbiTuMkFzvMHAA-19"
    correlationId: "QuzkmMDRTbiTuMkFzvMHAA-20"
    user: {
      "id": "00u14kjbo3IK5P8Fp5d7",
      "groups": []
    }
    req: {
      "method": "PATCH",
      "url": "/users/me",
      "query": {},
      "params": {},
      "headers": {
        "host": "localhost:8080",
        "connection": "keep-alive",
        "content-length": "171",
        "sec-ch-ua": "\" Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"91\", \"Chromium\";v=\"91\"",
        "authorization": "[Redacted]",
        "sec-ch-ua-mobile": "?0",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
        "content-type": "application/json-patch+json",
        "accept": "*/*",
        "origin": "http://localhost:3001",
        "sec-fetch-site": "same-site",
        "sec-fetch-mode": "cors",
        "sec-fetch-dest": "empty",
        "referer": "http://localhost:3001/",
        "accept-encoding": "gzip, deflate, br",
        "accept-language": "en-US,en;q=0.9",
        "x-correlation-id": "QuzkmMDRTbiTuMkFzvMHAA-20"
      },
      "remoteAddress": "::1",
      "remotePort": 63286
    }
    res: {
      "statusCode": 422,
      "headers": {
        "x-powered-by": "Express",
        "x-correlation-id": "QuzkmMDRTbiTuMkFzvMHAA-20",
        "access-control-allow-origin": "*",
        "access-control-allow-credentials": "true",
        "content-type": "application/problem+json; charset=utf-8",
        "content-length": "201",
        "etag": "W/\"c9-KXBlVP+3LvkN9OBVXa4YHIp4j2c\""
      }
    }
    duration: 156.0314
    event: "access"

Request body

[{"op":"add","path":"/learningStyle","value":"Intuitive"},{"op":"add","path":"/recognitionStyle","value":"Public"},{"op":"add","path":"/activityStyle","value":"Hands On"}]

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par l’opération @patch('/users/me') et sa déclaration de contenu @requestBody, puis reproduisez la requête en lisant @loopback/rest/src/validation/request-body.validator.ts et parser.ts à partir de la stack trace. C’est terminé lorsque la requête application/json-patch+json déclarée est traitée de manière cohérente et que le comportement de validation du corps de la requête signalé est couvert par un test approprié.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
nodejs, openapi, typescript
Domaine
api, backend
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
35/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.