loopbackio / loopbackio/loopback-next
Unsupproted Media Type Error with application/json-patch+json
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 5.1k
- Forks
- 1.1k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 27
Description
Steps to reproduce
- Run application
- 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"}]
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the @patch('/users/me') operation and its @requestBody content declaration, then reproduce the request while reading @loopback/rest/src/validation/request-body.validator.ts and parser.ts from the stack trace. Done means the declared application/json-patch+json request is handled consistently and the reported request-body validation behavior is covered by an appropriate test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nodejs, openapi, typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100