Skip to content

Add error handling to the API blueprint. - #40

Open
scolby33 wants to merge 18 commits into
developfrom
error-handling
Open

Add error handling to the API blueprint.#40
scolby33 wants to merge 18 commits into
developfrom
error-handling

Conversation

@scolby33

@scolby33 scolby33 commented Aug 7, 2018

Copy link
Copy Markdown
Owner

Will close #25.

@scolby33
scolby33 requested a review from cthoyt August 7, 2018 09:20
@codecov

codecov Bot commented Aug 7, 2018

Copy link
Copy Markdown

Codecov Report

Merging #40 into develop will increase coverage by 8.82%.
The diff coverage is 24.27%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop      #40      +/-   ##
===========================================
+ Coverage     42.9%   51.73%   +8.82%     
===========================================
  Files           20       21       +1     
  Lines          825      893      +68     
  Branches        75       79       +4     
===========================================
+ Hits           354      462     +108     
+ Misses         461      418      -43     
- Partials        10       13       +3
Impacted Files Coverage Δ
src/ocspdash/models.py 77.14% <ø> (ø) ⬆️
src/ocspdash/web/app.py 86.66% <100%> (+86.66%) ⬆️
src/ocspdash/web/blueprints/api.py 29.52% <12.32%> (+29.52%) ⬆️
src/ocspdash/web/exceptions.py 43.75% <43.75%> (ø)
src/ocspdash/manager.py 63.08% <50%> (+0.75%) ⬆️
src/ocspdash/web/extension.py 93.33% <66.66%> (+93.33%) ⬆️
src/ocspdash/web/admin.py 43.75% <0%> (+43.75%) ⬆️
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4472751...fcfdcee. Read the comment docs.

@cthoyt cthoyt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Overall looks good!

Requires lots more unit testing, though. And having everything go through 400 makes it tricky to pick out that the right error comes at the right time (besides doing string checking)

Comment thread src/ocspdash/web/blueprints/api.py Outdated
prepared_result_dicts = (_prepare_result_dictionary(result_data)
for result_data in claims[OCSP_RESULTS_JWT_CLAIM])
try:
prepared_result_dicts = (_prepare_result_dictionary(result_data)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Come on, use proper spacing :)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

What did I do wrong here?

Comment thread src/ocspdash/web/blueprints/api.py Outdated
except (KeyError, ValueError):
abort(HTTPStatus.BAD_REQUEST, 'invalid result data')

# TODO: can this raise an exception? I think yes if there's a constraint broken on the DB when commit is called()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

catch an integrity error then

Comment thread src/ocspdash/web/blueprints/api.py Outdated
n = request.args.get('n', type=int, default=10) # TODO make configurable at app level
if n > 10:
abort(400, 'n too large, max is 10') # TODO get the max config value here too
abort(HTTPStatus.BAD_REQUEST, 'n too large, max is 10') # TODO get the max config value here too

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is there a wrapper for aborting on 400?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

No, the flask docs have things like abort(404). It is annoying to be so much wordier with HTTPStatus.BAD_REQUEST but I think that's better than a "magic" number even if most everyone knows it.

Comment thread src/ocspdash/web/blueprints/api.py Outdated
invite_token = b64decode(claims['token'])
except KeyError:
abort(HTTPStatus.BAD_REQUEST, "'token' missing from claims")
except binascii.Error:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

that's an awful name for an error

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

I take what the stdlib provides.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

namespaces, those are a honking good thing

@scolby33

scolby33 commented Aug 7, 2018

Copy link
Copy Markdown
Owner Author

I agree so many 400's is not the best, but none of the other error codes seem to fit better.

One thing I have seen is returning JSON errors like (for Pushover, for example):

{
  "user": "invalid",
  "errors": [
    "user identifier is invalid"
  ],
  "status": 0,
  "request": "5042853c-402d-4a18-abcb-168734a801de"
}

Despite them having a list of errors, I don't think I ever saw a response with more than one there.

@cthoyt

cthoyt commented Aug 7, 2018

Copy link
Copy Markdown
Collaborator

You can return json and give it a non-200 error

@scolby33

scolby33 commented Aug 8, 2018

Copy link
Copy Markdown
Owner Author

Well, gonna try this now http://flask.pocoo.org/docs/1.0/patterns/apierrors/

- Add client_session and client_function fixtures to create Flask test clients and rollback the db between tests
- Add get_db staticmethod to OCSPSQLAlchemy class
- Add the ability to pass session_options into the flask-sqlalchemy SQLAlchemy constructor from the create_application function
  so the test fixtures can take control of rollbacks.
- Add stub test to start using the test client.
Comment thread tests/conftest.py
logger.debug('rolling back transaction from function for web client')
transaction.rollback()


Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@cthoyt if you can figure out how to reduce the repetition between manager_session and client_session and between manager_function and client_function that'd be swell.

But that's not your real homework.

Comment thread tests/conftest.py
transaction.rollback()


# TODO: fixture to pre-fill DB with some stuff for the client to test on

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@cthoyt this is the real homework.

Something that takes in a client and spits out the same client with a db with a bunch of stuff in it.

It'd be cool if it didn't get rolled back, but that might be a huge pain so whatever works.

@scolby33 scolby33 changed the title Add error handling to /register API endpoint. Add error handling to the API blueprint. Aug 8, 2018
cthoyt added 4 commits August 8, 2018 18:34
Scoped sessions act like sessions... why don't they just inherit from them?!?
The SQLAlchemy class takes a none, so you can pass it none (unless i'm an idiot and none means something special)
@scolby33 not sure where you want this, but here's the idea with making some test data
Comment thread src/ocspdash/manager.py
location = self.get_location_by_selector(selector)
if location is None:
raise Exception(f'location not found for selector: {selector}')
raise ValueError(f'invalid invite token')

@scolby33 scolby33 Aug 8, 2018

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No, since it doesn't mean your code has been designed wrong, but rather you have to deal with the reality that someone else is going to stick weird shit inside as the invite token.

Now, the next exception checking for the expiration of the pubkey might be different, but raising an exception actually makes the logic for using this function much better. Overall, I like this design and I think it does what it's supposed to in an elegant way. Lots of helpful/useful errors for bad situations where the program should stop seems good to me.

except jwt.JWTError:
abort(HTTPStatus.BAD_REQUEST, 'malformed JWT')
except jwt.JWTError as e:
raise InvalidUsage(f'failed to decode JWT: {str(e)}')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

you could also do

raise InvalidUsage('failed to decode JWT') from e

unless the point of this was to get all of that information in the string

except ValueError as e:
raise InvalidUsage(f'failed to process invite: {str(e)}')

return '', HTTPStatus.NO_CONTENT

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I still don't like returning no content... why don't you have it send back some information about the location that's been registered?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

201 Created specifies you should return the URL of the created entity but there is no URL for the location.

What would you want to return? The location name? I was originally just jsonifying the location, but there's some fields that probably shouldn't be returned and going down the road of to_json and safe_to_json screams bad to me.

- Use app configuration for default and maximum manifest size
- Handle integrity error when inserting payload
- Also add raising of integrity errors to documentation
- make secret key more secret
@cthoyt

cthoyt commented Aug 31, 2018

Copy link
Copy Markdown
Collaborator

yo whats going on with this PR

@cthoyt

cthoyt commented Oct 7, 2018

Copy link
Copy Markdown
Collaborator

BUMP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve error checking in Flask web application

2 participants