-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parsing a Problem Document from JSON #20
Comments
@sazzer Thanks for using the package. Could you please explain what and how you would expect to use it? Would you be willing to send a PR? |
@sazzer I think https://github.com/badgateway/ketting#introduction can do this for you. |
It can - I improved the TypeScript support for that exact code myself.
However, Ketting is designed for working with Hypermedia APIs, and it's a
bit wasteful to use it for APIs that are *not* hypermedia in nature. Often
if you want to work with such an API, you're better off just using
something like Axios (or Fetch, from the browser).
Cheers
…On Sun, 11 Apr 2021 at 21:15, Alexander Zeitler ***@***.***> wrote:
@sazzer <https://github.com/sazzer> I think
https://github.com/badgateway/ketting#introduction can do this for you.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#20 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAQEGGOBHBI6TYQKZIMBJTTIH7MVANCNFSM4VC73FHA>
.
|
@sazzer You can follow the progress for a parser: https://github.com/PDMLab/http-problem-details-parser Looking forward to your feedback. |
I'm using this library on the frontend in a couple projects. This is how I'm handling them (I'm not using it on the backend, which is PHP in my case) class Api {
get(url, queryParams = []) {
let urlWithParams = url + params(queryParams);
return this.handleProblem(fetch(urlWithParams, {
credentials: 'same-origin',
method: 'GET',
mode: 'same-origin',
cache: 'no-cache',
}));
}
/**
* @param {Promise} result
* @return {Promise}
*/
handleProblem = (result) => {
return new Promise(((resolve, reject) => {
result.then((response) => {
// If the data returned is a problem
if (response.headers.get("content-type") === "application/problem+json" ) {
const clonedResponse = response.clone();
response.json()
.then((json) => {
// If we didn't request the problem's actual URL
if (json.type && response.url !== json.type) {
const extensions = json.extensions || null;
const problem = new ProblemDocument(json, extensions);
reject(problem);
} else {
resolve(clonedResponse);
}
})
.catch((error) => {
log('json error', error);
reject(error)
});
} else {
resolve(response);
}
}).catch((error) => {
log('unknown fetch error', error);
reject(error);
});
}));
};
} Obviously that code is snipped from a larger project, but it might help someone else. |
I should add that to get this library working on the front-end, if you're using webpack >= v5, you need to shim the Webpack removed it's nodejs polyfills in v5 so you need to install the module.exports = {
// ...
resolve: {
fallback: {
"url": require.resolve("native-url")
}
}
}; If this project is planning true front-end support (and it would be great to have it) it would make sense to use the WHATWG url api instead. |
@robincafolla thanks for showing your use case. Right now I'm experimenting with parsing and trying to understand what is required. So given this HTTP 400 problem detail repsonse, {
"type": "https://example.net/validation-error",
"status": 400,
"title": "Your request parameters didn't validate.",
"instance": "https://example.net/account/logs/123",
"invalid-params": [
{
"name": "age",
"reason": "must be a positive integer"
},
{
"name": "color",
"reason": "must be 'green', 'red' or 'blue'"
}
]
} you could do this: const problemDocument = fromJSON(status400JSON) This would give you the typed representation of the problem according to RFC7807 but without the extension As the type is not On the client side we could then map the extension I'm thinking of something like this (it's in the PR linked in my previous comment): const mappers: HttpProblemExtensionMapper[] = [
{
type: 'https://example.net/validation-error',
map: (object: any) =>
new ProblemDocumentExtension({
'invalid-params': object['invalid-params']
})
}
]
const problemDocument = fromJSON(status400JSON, mappers) This would give us the document as shown above but including the extension. So the idea is to have mappers for known extension schemas. I'm also thinking about if it could make sense to have types for the specific problem documents like this: type ValidationProblemDocument = ProblemDocument & {
type: 'https://example.net/validation-error'
'invalid-params': {
name: string
reason: string
}[]
} No we could have type guards to make evaluating the documents a bit more type safe in our code: function isValidationProblemDocument(
value: unknown
): value is ValidationProblemDocument {
const x = value as ProblemDocument
return x.type === 'https://example.net/validation-error'
}
if (isValidationProblemDocument(document)) {
document['invalid-params'].length.should.equal(2)
} That way we can even get IntelliSense for But I'm also thinking about if it's a good idea to go that far. I wonder if it wouldn't be better to have our own error types living in the client and one could just map the HTTP problems to our client errors. |
This package works great for the server-side, but it would be great if it were usable on the client-side as well by being able to parse an incoming JSON document into a
ProblemDocument
, complete with access to any extension values in a safe manner.Cheers
The text was updated successfully, but these errors were encountered: