Closed HasanAshab closed 5 months ago
Hi, thx for the suggestion. This would be a nice feature indeed.
For this, I'd need to parse the Validators/*.ts (like we already do with the models) so this should be easy enough. Unfortunately, I don't have the time, but PRs are more than welcome.
For now, you can use the only() or without() notations. Based on your schema, I suppose you have a model User, that has an email and passwor field. You can use <User>.only(email, password)
or if the Validator has more fields, you can also use <User>.without(avatar)
.
Recently, i got work. so please anyone reading this issue, contribute if you can
Thanks in advance
@HasanAshab You can however start working on this one if you'd like π
, or do you think that the only()
and without()
notations are sufficient enough, so I can close it?
Not sure, but I will start on it in some weeks Inshaallah :)
May Allah bless you and give you the strength and patience π
I can implement this by traversing validator properties but can't parse from text data π . It's pretty complex
maybe the validatior has some method that returns a nicer object that can be easily parsed, in combination with dynamic imports using eval()
.
thinking of smth like this
const v = eval(import exampleValidator from currentfile.ts).then()
v.toJson()
hopefully something existsv.validate(null)
and hope that the object can be constructed from the error outputsOh, I got the map
@ad-on-is
const v = eval(import exampleValidator from currentfile.ts).then()
This line cause
SyntaxError: Cannot use import statement outside a module
What about something like
const validatorsDir = pkgJson.imports['#validators/*']
const paths = await AutoSwagger.default.getFiles(validatorsDir)
for(let path of paths) {
path = path
.replace('.ts', '')
.replace('#validators', validatorsDir)
const validators = await import(path)
console.log(validators)
}
@HasanAshab My example was just pseudo-code π , but yeah something along these lines looks good.
@ad-on-is I can make schema from vine schema. But found no way to make from compiled validators :/
I'm not familiar with vinejs, but what do you get if you try to validate purposely wrong data? do you get any useful structure?
validator.validate(null)
Great! I can extract required field names from error obj
[
{ message: 'email field is required', rule: 'required',
field: 'email'
},
{
message: 'username field is required',
rule: 'required', field: 'username'
},
{ message: 'password field is required',
rule: 'required',
field: 'password' }
]
And also can extract their types by trying with all data types one by one.
But the problem is how to extract optional fields? have any Idea?
by trying with all data types one by one.
I think this might be too dirty and spaghetti. Is there a cleaner solution?
Does the validator provide any other useful methods or fields? does it provide the schema maybe?
The validator don't save schema as prop when its compiled. Also found no cleaner solution.
Take a look on VineValidator
Yeah... I've been looking into it for the past few hours, and there's really no way to get to the schema itself.
I think the only way is to parse everything between vine.compile()
since you already got that working
// β
supported
vine.compile(vine.object({}))
// β not supported
const schema = vine.object({})
vine.compile(schema)
What do you think?
Edit: I also tried playing with the custom error reporter, but with no luck.
But it may be quite difficult to parse raw text between vine.compile().
This may not work for some edge cases. Also dynamic validators would not be supported.
You're right. I guess we might ditch this one after all, since it's technically impossible.
Or, as a final resort, I could ask the folks at adonisJS, whether they could provide a toJSON()
function to the compiled validator, so we could get the map.
Yeah please ask, I will wait for toJSON() to be added :)
https://github.com/adonisjs/core/discussions/4480
Fingers crossed! π€π»
@HasanAshab
Nice, now that we get a toJSON()
, I'd suggest the following implementation.
// autoswagger.ts
// -----------------------------
private async getSchemas() {
let schemas = {
Any: {
description: "Any JSON object not defined as schema",
},
};
schemas = {
...schemas,
...(await this.getInterfaces()),
...(await this.getModels()),
...(await this.getValidators()), // convert the validator.toJSON() to the same format as models/interfaces do
};
return schemas;
}
private async getValidators() {
/*
- read files
- use ValidatorParser for parsing
- return something like this
{exampleValidator: {
type: "object",
properties: this.validatorParser.parse(dataFromFile)
description: "Validator"
},
otherValidator: {
type: "object",
properties: this.validatorParser.parse(datafromFile)
description: "Validator"
}
}
*/
}
// parser.ts
// -----------------------------
export class ValidatorParser {
// do your magic here
}
And the jsdoc notation should than work automatically with something like this
/* @requestBody <exampleValidator>
I got it :) π
Oh, one more thing. Do you think it would be easy enough to get the errors of the validator as a response body?
Example (pseudo-code)
/**
* @create
* @requestBody <exampleValidator>
* @responseBody 200 - <User>
* @responseBody 422 - <exampleValidator.error>
*/
async create() {}
end then do something like this
let errors = []
try {
exampleValidator.validate({})
}catch(e) {
errors = e.message
}
Thats good idea! I can generate multiple error response schemas from a validator, but does AutoSwagger supports multiple schema on same status code??
No it does not support it, but I think it's sufficient enough just to have the schema of the error response as it is always the same.
Okay and how can we know the exact type of literal?
async index() {
try {
await testValidator.validate({
name: 'John Doe',
email: '',
})
} catch (e) {
console.log(e.messages)
}
return {
hello: 'world',
}
}
This is what I get as an output of console.log(e.messages)
[
{
message: 'The boing field must be defined',
rule: 'required',
field: 'boing'
},
{
message: 'The title field must be defined',
rule: 'required',
field: 'title'
},
{
message: 'The slug field must be defined',
rule: 'required',
field: 'slug'
},
{
message: 'The description field must be defined',
rule: 'required',
field: 'description'
}
]
Done! Nothing more is needed, just so everyone reading the docs knows, "oh ok, if I provide an invalid request-body, I'll get this kind of format as an error". You know what I mean? No need to be more complex here.
Yeah, I got it.
The error object has also a status
and code
property. If you like, you can use them too.
If someone uses @responseBody 400 - <exampleValidator.error>
but the status of the error is 422. It's okey to overwrite the status provided by the developer, since this is AutoSwagger π
See schema types there is literal type for string, number, etc. Now how to know the exact type?
If someone uses
@responseBody 400 - <exampleValidator.error>
but the status of the error is 422. It's okey to overwrite the status provided by the developer, since this is AutoSwagger π
I think we should respect the status provided by developer as he may customized response on exception handler, am I right?
See schema types there is literal type for string, number, etc. Now how to know the exact type?
oh, that's what you mean by literal
Hmm.. I'm not exactly sure, but refs['ref1://1'].validator should be a function and hopefully provide more info.
If someone uses
@responseBody 400 - <exampleValidator.error>
but the status of the error is 422. It's okey to overwrite the status provided by the developer, since this is AutoSwagger πI think we should respect the status provided by developer as he may customized response on exception handler, am I right?
Yes, you're right. The devs should be responsible for setting a proper status code, in case they override it in the controller or elsewhere.
How can I play around vinejs latest commit
How can I play around vinejs latest commit
I just did pnpm i https://github.com/vinejs/vine#develop
and it seems to work. No need to use a specific commit, just the develop branch is sufficient
Oh, thanks :)
any progress on this?
Happy to help with testing this on big code base.
Hey @HasanAshab, how is it going with this one? Any progress?
@ad-on-is @vithalreddy Sorry guys. I just migrated to Django :/.
If anybody can, please contribute π
@HasanAshab ... all good, no pressure π
would you mind pushing a PR, with the state you currently have, so I or someone else can pick up where you left off
I have no statable state. I just played with .toJSON() and some planning written on paper π
Oh ok... I thought you were much further, with the dynamic imports, etc...
Hi ! Unfortunately I can't help but I'll love to have this feature so I give you some strength ! Thanks btw for this package !
This feature would indeed be really cool, and I would not mind giving it a go. However there seems to be an issue with the toJSON of the vine validators: all primary types are considered literal. That means strings, numbers, booleans, enums etc are marked as "type": "literal" in the json returned.
@antoninpire How did you get the latest vine working? or did they merge it into main?
@ad-on-is I think they merged it into main, I didn't have to use a specific branch, the toJSON method was there
@antoninpire Ooh cool, I will give it a shot then.
Fixed in 3.45.0. I tried to do my best here. Feel free to test and report any issues or feedback.
Usage as always...
testValidator.ts
export const testValidator = vine.compile(
vine.object({
boing: vine.object({
blub: vine.string(),
}),
title: vine.string().minLength(10).maxLength(80),
mail: vine.string().email(),
someArr: vine.array(vine.string()),
somebool: vine.boolean(),
complArray: vine.array(
vine.object({
best: vine.string(),
test: vine.array(
vine.object({
final: vine.string(),
})
),
})
),
enumChoice: vine.enum(['foo', 'bar']),
description: vine.string().trim().escape(),
data: vine.object({
bar: vine.number().max(10).min(5),
arr: vine.array(vine.number().min(10).max(20)),
regex: vine.string().regex(/^[a-z]+$/),
baz: vine.enum(['foo', 'bar']).nullable(),
opts: vine.string().optional(),
}),
})
)
... and then...
@requestBody <testValidator>
Awesome! Thanks a lot
Hello,
I am currently working on a project using AdonisJS and I am using the
adonis-autoswagger
package to generate Swagger documentation for my API. I have noticed that whileadonis-autoswagger
provides a lot of flexibility and control over the generated documentation, it does not currently support generating Swagger request bodies directly from validator classes.This limitation has led to some redundancy in our codebase, as we have to manually define the structure of the request body in both the validator class and the Swagger documentation. This not only increases the maintenance effort but also makes the code harder to understand and manage. This will keep our docs sync the code base
I believe that adding support for generating Swagger request bodies directly from validator classes would greatly enhance the usability and efficiency of
adonis-autoswagger
. It would allow us to define the structure of the request body in one place (the validator class), and then automatically generate the corresponding Swagger documentation.Here's a rough idea of how this could work:
In this example, the
LoginValidator
class defines the structure of the request body. We could then use this information to automatically generate the corresponding Swagger documentation for the/login
endpoint.I would appreciate if you could consider this feature request and let me know if there are any plans to implement it in the future. Alternatively, I would be happy to contribute to the development of this feature if you need help.
Thank you for considering this request.
Best regards, Hasan Ashab