Skip to content
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

feat: openapi schema for user admin #4146

Merged
merged 10 commits into from
Jul 6, 2023
Merged

feat: openapi schema for user admin #4146

merged 10 commits into from
Jul 6, 2023

Conversation

kwasniew
Copy link
Contributor

@kwasniew kwasniew commented Jul 5, 2023

About the changes

Full OpenAPI spec for user-admin controller.

  • This should be around 100-200 LOC. 1k lines is from the snapshot test.
  • Removed all working schemas from the meta schema exception list
  • adding 400 when body or query/path params are validated, 401 always, 403 when ADMIN is required, 404 when resource may not exist
  • fixing a few 500 when id was not a number, those should be 400 errors
  • making BadDataError reflect incorrect data in body or params
  • making user roles being number or string explicit. When creating/updating a user we can specify both and we return what you specified. When reading a user we always return a number.

Important files

Discussion points

@vercel
Copy link

vercel bot commented Jul 5, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
unleash-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 5, 2023 3:07pm
unleash-monorepo-frontend ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 5, 2023 3:07pm

@@ -16,7 +16,7 @@ class BadDataError extends UnleashError {
errors?: [ValidationErrorDescription, ...ValidationErrorDescription[]],
) {
const topLevelMessage =
'Request validation failed: your request body contains invalid data' +
'Request validation failed: your request body or params contain invalid data' +
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we throw this error when query or path params are incorrect so the error message should be more generic

description: 'An Unleash user after creation',
required: ['id'],
properties: {
...userSchema.properties,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as user schema but it returns either number or string for the role name depending on what was in the create/update request

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user schema hasn't changed because this schema was added

@@ -192,7 +192,7 @@ class UserService {

const exists = await this.store.hasUser({ username, email });
if (exists) {
throw new Error('User already exists');
throw new BadDataError('User already exists');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error was 500, BadDataError is 400

}

async deleteUser(req: IAuthRequest, res: Response): Promise<void> {
const { user, params } = req;
const { id } = params;
if (!Number.isInteger(Number(id))) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously it was 500, not it is 400

if (!Number.isInteger(Number(id))) {
throw new BadDataError('User id should be an integer');
}
const normalizedRootRole = Number.isInteger(Number(rootRole))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openapi coerces root role to string on number | string union so we need to coerce it back to number if possible

type: 'number',
description:
"The role to assign to the user. Can be either the role's ID or its unique name.",
oneOf: [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oneOf with integer or string + coercion: true in our openapi lib causes rootRole to always be a string. We need to compensate for it in the controller by coercing back

@sjaanus
Copy link
Contributor

sjaanus commented Jul 5, 2023

Also enable strictSchemaValidation in user-admin e2e test to validate all of this.

Copy link
Contributor

@thomasheartman thomasheartman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good to me overall! 💯 Got a few questions and minor typo fixes that I'd like to have addressed, though, but I trust you to take that into account before merging.

src/lib/routes/admin-api/user-admin.ts Outdated Show resolved Hide resolved
Comment on lines +210 to +218
parameters: [
{
name: 'q',
description:
'The pattern to search in the username or email',
schema: { type: 'string' },
in: 'query',
},
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need to type this somehow (you might not), then you could look into using the FromQueryParams method and putting it in its own file (similar to how we do it in src/lib/openapi/spec/export-query-parameters.ts). I'm not sure whether that's necessary here. As long as it shows up correctly in the output schema, I'm happy 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied this pattern from other places where it was done inline. It does show up in the swagger UI and works fine :)

@@ -256,8 +318,13 @@ export default class UserAdminController extends Controller {
openApiService.validPath({
tags: ['Users'],
operationId: 'updateUser',
summary: 'Update a user',
description: 'Updates use with new fields',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all fields required? Are non-submitted fields ignored? In other words: does this act more like a "true PUT" or a "PATCH"? It'd be good to mention that in the description.

src/lib/routes/admin-api/user-admin.ts Outdated Show resolved Hide resolved
Comment on lines 462 to 540
201,
200,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we change this from a 201 to a 200?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think one of our validators was complaining that 201 should have a Location header

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that sounds about right. You should add one: respondWithValidation takes an optional last parameter called headers. You can add it in there, pointing to the newly created user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I found the location header setting pattern in other parts of the code. Our schema was lying before with 200 and the code was returning 201. Let's stick to 201 in both

kwasniew and others added 4 commits July 5, 2023 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

3 participants