Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
api
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
cubicweb
cubes
api
Commits
4c7d4fc241a7
Commit
4c7d4fc241a7
authored
2 years ago
by
Arnaud Vergnet
Browse files
Options
Downloads
Patches
Plain Diff
feat: improve error handling
parent
2af675c2fd36
No related branches found
Branches containing commit
No related tags found
Tags containing commit
1 merge request
!7
feat: use pyramid decorators and rework error handling
Pipeline
#132569
passed
2 years ago
Stage: lint
Stage: tests
Changes
3
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
cubicweb_api/httperrors.py
+6
-0
6 additions, 0 deletions
cubicweb_api/httperrors.py
cubicweb_api/request_params.py
+7
-6
7 additions, 6 deletions
cubicweb_api/request_params.py
cubicweb_api/routes.py
+63
-26
63 additions, 26 deletions
cubicweb_api/routes.py
with
76 additions
and
32 deletions
cubicweb_api/httperrors.py
+
6
−
0
View file @
4c7d4fc2
from
pyramid.httpexceptions
import
exception_response
import
json
import
logging
log
=
logging
.
getLogger
(
__name__
)
def
get_http_error
(
code
:
int
,
title
:
str
,
message
:
str
,
data
:
dict
=
None
):
error
=
exception_response
(
code
)
...
...
@@ -16,4 +20,6 @@
},
}
)
log
.
debug
(
f
"
Encountered an HTTP error:
{
error
.
status
}
"
)
log
.
debug
(
f
"
Error content:
{
error
.
text
}
"
)
return
error
This diff is collapsed.
Click to expand it.
cubicweb_api/request_params.py
+
7
−
6
View file @
4c7d4fc2
from
json
import
JSONDecodeError
from
marshmallow
import
Schema
,
ValidationError
from
dataclasses
import
dataclass
from
marshmallow.validate
import
Length
from
dataclasses
import
dataclass
,
field
from
pyramid.request
import
Request
from
cubicweb_api.httperrors
import
get_http_error
...
...
@@ -22,8 +23,8 @@
@dataclass
(
frozen
=
True
)
class
RqlParams
:
query
:
str
params
:
str
query
:
str
=
field
(
metadata
=
dict
(
validate
=
Length
(
min
=
1
)))
params
:
dict
=
field
(
metadata
=
dict
(
required
=
False
,
load_default
=
{}))
@dataclass
(
frozen
=
True
)
...
...
@@ -34,8 +35,8 @@
@dataclass
(
frozen
=
True
)
class
TransactionParams
:
uuid
:
str
uuid
:
str
=
field
(
metadata
=
dict
(
validate
=
Length
(
min
=
32
)))
@dataclass
(
frozen
=
True
)
class
TransactionExecuteParams
(
TransactionParams
):
...
...
@@ -38,6 +39,6 @@
@dataclass
(
frozen
=
True
)
class
TransactionExecuteParams
(
TransactionParams
):
query
:
str
params
:
str
query
:
str
=
field
(
metadata
=
dict
(
validate
=
Length
(
min
=
1
)))
params
:
dict
=
field
(
metadata
=
dict
(
required
=
False
,
load_default
=
{}))
This diff is collapsed.
Click to expand it.
cubicweb_api/routes.py
+
63
−
26
View file @
4c7d4fc2
...
...
@@ -17,7 +17,7 @@
from
enum
import
Enum
from
typing
import
Union
from
cubicweb
import
AuthenticationError
from
cubicweb
import
AuthenticationError
,
QueryError
from
cubicweb.pyramid.core
import
CubicWebPyramidRequest
from
cubicweb.schema_exporters
import
JSONSchemaExporter
from
cubicweb.server.repository
import
Repository
...
...
@@ -21,6 +21,8 @@
from
cubicweb.pyramid.core
import
CubicWebPyramidRequest
from
cubicweb.schema_exporters
import
JSONSchemaExporter
from
cubicweb.server.repository
import
Repository
from
rql
import
RQLException
from
yams
import
ValidationError
,
UnknownType
from
pyramid.config
import
Configurator
from
pyramid.request
import
Request
from
pyramid.view
import
view_config
...
...
@@ -24,4 +26,5 @@
from
pyramid.config
import
Configurator
from
pyramid.request
import
Request
from
pyramid.view
import
view_config
from
pyramid.httpexceptions
import
HTTPError
import
logging
...
...
@@ -27,4 +30,5 @@
import
logging
import
traceback
from
cubicweb_api.api_transaction
import
ApiTransactionsRepository
from
cubicweb_api.httperrors
import
get_http_error
...
...
@@ -79,4 +83,37 @@
)
def
print_exception
(
e
:
Exception
):
traceback
.
print_exception
(
type
(
e
),
e
,
e
.
__traceback__
)
def
view_exception_handler
(
func
):
"""
Use it as a decorator for any pyramid view to catch AuthenticationError to raise HTTP 401
and any other leftover exceptions to raise HTTP 500.
:param func: The pyramid view function
:return:
"""
def
request_wrapper
(
request
:
Request
):
try
:
return
func
(
request
)
except
HTTPError
as
e
:
return
e
except
AuthenticationError
as
e
:
print_exception
(
e
)
return
get_http_error
(
401
,
e
.
__class__
.
__name__
,
str
(
e
))
except
Exception
as
e
:
print_exception
(
e
)
# Do not return error content as it could lead to security leaks
raise
get_http_error
(
500
,
"
ServerError
"
,
"
The server encountered an error. Please contact support.
"
,
)
return
request_wrapper
@cw_view_config
(
route_name
=
ApiRoutes
.
schema
,
request_method
=
"
GET
"
)
...
...
@@ -82,2 +119,3 @@
@cw_view_config
(
route_name
=
ApiRoutes
.
schema
,
request_method
=
"
GET
"
)
@view_exception_handler
def
schema_route
(
request
:
Request
):
...
...
@@ -83,3 +121,4 @@
def
schema_route
(
request
:
Request
):
# TODO block this if we are not connected and anon is disabled
repo
=
get_cw_repo
(
request
)
exporter
=
JSONSchemaExporter
()
...
...
@@ -84,12 +123,7 @@
repo
=
get_cw_repo
(
request
)
exporter
=
JSONSchemaExporter
()
try
:
exported_schema
=
exporter
.
export_as_dict
(
repo
.
schema
)
except
Exception
as
e
:
log
.
error
(
e
)
raise
get_http_error
(
400
,
e
.
__class__
.
__name__
,
str
(
e
))
else
:
return
exported_schema
exported_schema
=
exporter
.
export_as_dict
(
repo
.
schema
)
return
exported_schema
@cw_view_config
(
route_name
=
ApiRoutes
.
rql
)
...
...
@@ -93,8 +127,9 @@
@cw_view_config
(
route_name
=
ApiRoutes
.
rql
)
@view_exception_handler
def
rql_route
(
request
:
Request
):
schema
=
class_schema
(
RqlParams
)()
request_params
:
RqlParams
=
get_request_params
(
request
,
schema
)
query
=
request_params
.
query
params
=
request_params
.
params
...
...
@@ -96,9 +131,7 @@
def
rql_route
(
request
:
Request
):
schema
=
class_schema
(
RqlParams
)()
request_params
:
RqlParams
=
get_request_params
(
request
,
schema
)
query
=
request_params
.
query
params
=
request_params
.
params
if
not
query
:
raise
get_http_error
(
400
,
"
ValidationError
"
,
"
Query should not be empty.
"
)
try
:
result
=
get_cw_request
(
request
).
execute
(
query
,
params
)
...
...
@@ -103,3 +136,7 @@
try
:
result
=
get_cw_request
(
request
).
execute
(
query
,
params
)
except
(
RQLException
,
QueryError
,
ValidationError
,
UnknownType
)
as
e
:
print_exception
(
e
)
raise
get_http_error
(
400
,
e
.
__class__
.
__name__
,
str
(
e
))
else
:
return
result
.
rows
...
...
@@ -105,7 +142,4 @@
return
result
.
rows
except
Exception
as
e
:
log
.
error
(
e
)
raise
get_http_error
(
400
,
e
.
__class__
.
__name__
,
str
(
e
))
@cw_view_config
(
route_name
=
ApiRoutes
.
login
)
...
...
@@ -109,6 +143,7 @@
@cw_view_config
(
route_name
=
ApiRoutes
.
login
)
@view_exception_handler
def
login_route
(
request
:
Request
):
schema
=
class_schema
(
LoginParams
)()
request_params
:
LoginParams
=
get_request_params
(
request
,
schema
)
...
...
@@ -135,6 +170,7 @@
@cw_view_config
(
route_name
=
ApiRoutes
.
transaction_begin
)
@view_exception_handler
def
transaction_begin_route
(
request
:
Request
):
transactions
=
get_cw_repo
(
request
).
api_transactions
user
=
get_cw_request
(
request
).
user
...
...
@@ -142,9 +178,10 @@
@cw_view_config
(
route_name
=
ApiRoutes
.
transaction_execute
)
@view_exception_handler
def
transaction_execute_route
(
request
:
Request
):
transactions
=
get_cw_repo
(
request
).
api_transactions
schema
=
class_schema
(
TransactionExecuteParams
)()
params
:
TransactionExecuteParams
=
get_request_params
(
request
,
schema
)
try
:
result
=
transactions
[
params
.
uuid
].
execute
(
params
.
query
,
params
.
params
)
...
...
@@ -145,7 +182,11 @@
def
transaction_execute_route
(
request
:
Request
):
transactions
=
get_cw_repo
(
request
).
api_transactions
schema
=
class_schema
(
TransactionExecuteParams
)()
params
:
TransactionExecuteParams
=
get_request_params
(
request
,
schema
)
try
:
result
=
transactions
[
params
.
uuid
].
execute
(
params
.
query
,
params
.
params
)
except
(
RQLException
,
QueryError
,
ValidationError
,
UnknownType
)
as
e
:
print_exception
(
e
)
raise
get_http_error
(
400
,
e
.
__class__
.
__name__
,
str
(
e
))
else
:
return
result
.
rows
...
...
@@ -151,7 +192,4 @@
return
result
.
rows
except
Exception
as
e
:
log
.
error
(
e
)
raise
get_http_error
(
400
,
e
.
__class__
.
__name__
,
str
(
e
))
@cw_view_config
(
route_name
=
ApiRoutes
.
transaction_commit
)
...
...
@@ -155,6 +193,7 @@
@cw_view_config
(
route_name
=
ApiRoutes
.
transaction_commit
)
@view_exception_handler
def
transaction_commit_route
(
request
:
Request
):
transactions
=
get_cw_repo
(
request
).
api_transactions
schema
=
class_schema
(
TransactionParams
)()
...
...
@@ -162,5 +201,9 @@
uuid
=
params
.
uuid
try
:
commit_result
=
transactions
[
uuid
].
commit
()
except
(
RQLException
,
QueryError
,
ValidationError
,
UnknownType
)
as
e
:
print_exception
(
e
)
raise
get_http_error
(
400
,
e
.
__class__
.
__name__
,
str
(
e
))
else
:
transactions
[
uuid
].
rollback
()
return
commit_result
...
...
@@ -165,8 +208,5 @@
transactions
[
uuid
].
rollback
()
return
commit_result
except
Exception
as
e
:
log
.
error
(
e
)
raise
get_http_error
(
400
,
e
.
__class__
.
__name__
,
str
(
e
))
@cw_view_config
(
route_name
=
ApiRoutes
.
transaction_rollback
)
...
...
@@ -170,8 +210,9 @@
@cw_view_config
(
route_name
=
ApiRoutes
.
transaction_rollback
)
@view_exception_handler
def
transaction_rollback_route
(
request
:
Request
):
transactions
=
get_cw_repo
(
request
).
api_transactions
schema
=
class_schema
(
TransactionParams
)()
params
:
TransactionParams
=
get_request_params
(
request
,
schema
)
uuid
=
params
.
uuid
...
...
@@ -173,15 +214,11 @@
def
transaction_rollback_route
(
request
:
Request
):
transactions
=
get_cw_repo
(
request
).
api_transactions
schema
=
class_schema
(
TransactionParams
)()
params
:
TransactionParams
=
get_request_params
(
request
,
schema
)
uuid
=
params
.
uuid
try
:
rollback_result
=
transactions
[
uuid
].
rollback
()
transactions
.
end_transaction
(
uuid
)
return
rollback_result
except
Exception
as
e
:
log
.
error
(
e
)
raise
get_http_error
(
400
,
e
.
__class__
.
__name__
,
str
(
e
))
rollback_result
=
transactions
[
uuid
].
rollback
()
transactions
.
end_transaction
(
uuid
)
return
rollback_result
@cw_view_config
(
route_name
=
ApiRoutes
.
help
,
request_method
=
"
GET
"
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment