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

Upgrade openapi after subscriptions removal #1821

Merged
merged 17 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ updates:
directory: "/"
schedule:
interval: "daily"
ignore:
- dependency-name: "openapi-spec-validator"
labels:
- "bumpless"
- package-ecosystem: "github-actions"
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [5.0.1]
### Fixed
- Upgrade the `openapi-core`, `openapi-spec-validator`, and `jsonschema` packages to their latest versions. This is now possible thanks to the pre-release of [openapi-core v0.19.0a1](https://github.com/python-openapi/openapi-core/releases/tag/0.19.0a1), which fixes <https://github.com/python-openapi/openapi-core/issues/662>. Resolves <https://github.com/ASFHyP3/hyp3/issues/1193>.

## [5.0.0]
### Removed
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/hyp3_api/api-spec/job_parameters.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ components:
enum:
- {{ job_type }}
name:
$ref: "./openapi-spec.yml#components/schemas/name"
$ref: "./openapi-spec.yml#/components/schemas/name"
jtherrmann marked this conversation as resolved.
Show resolved Hide resolved
job_parameters:
$ref: "#/components/schemas/{{ job_type }}Parameters"

Expand Down
10 changes: 5 additions & 5 deletions apps/api/src/hyp3_api/api-spec/openapi-spec.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ paths:
- name: job_type
in: query
schema:
$ref: "./job_parameters.yml#components/schemas/job_type"
$ref: "./job_parameters.yml#/components/schemas/job_type"
- name: start_token
in: query
schema:
Expand Down Expand Up @@ -138,7 +138,7 @@ components:
quota:
$ref: "#/components/schemas/quota"
job_names:
$ref: "#components/schemas/job_names_list"
$ref: "#/components/schemas/job_names_list"

quota:
description: Containes the limit of jobs per month and the amount remaining for a user.
Expand Down Expand Up @@ -168,7 +168,7 @@ components:
minItems: 1
maxItems: 200
items:
$ref: "./job_parameters.yml#components/schemas/new_job"
$ref: "./job_parameters.yml#/components/schemas/new_job"

list_of_jobs:
type: array
Expand Down Expand Up @@ -254,9 +254,9 @@ components:
user_id:
$ref: "#/components/schemas/user_id"
job_type:
$ref: "./job_parameters.yml#components/schemas/job_type"
$ref: "./job_parameters.yml#/components/schemas/job_type"
job_parameters:
$ref: "./job_parameters.yml#components/schemas/job_parameters"
$ref: "./job_parameters.yml#/components/schemas/job_parameters"
request_time:
$ref: "#/components/schemas/datetime"
status_code:
Expand Down
85 changes: 37 additions & 48 deletions apps/api/src/hyp3_api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@
import yaml
from flask import abort, g, jsonify, make_response, redirect, render_template, request
from flask_cors import CORS
from openapi_core import OpenAPI
from openapi_core.contrib.flask.decorators import FlaskOpenAPIViewDecorator
from openapi_core.contrib.flask.handlers import FlaskOpenAPIErrorsHandler
from openapi_core.contrib.flask.views import FlaskOpenAPIView
from openapi_core.spec.shortcuts import create_spec
from openapi_core.validation.response.datatypes import ResponseValidationResult

from hyp3_api import app, auth, handlers
from hyp3_api.openapi import get_spec_yaml

api_spec_file = Path(__file__).parent / 'api-spec' / 'openapi-spec.yml'
api_spec_dict = get_spec_yaml(api_spec_file)
api_spec = create_spec(api_spec_dict)
api_spec = OpenAPI.from_dict(api_spec_dict)
CORS(app, origins=r'https?://([-\w]+\.)*asf\.alaska\.edu', supports_credentials=True)

AUTHENTICATED_ROUTES = ['/jobs', '/user']
Expand Down Expand Up @@ -68,7 +67,7 @@ def render_ui():


@app.errorhandler(404)
def error404(e):
def error404(_):
jtherrmann marked this conversation as resolved.
Show resolved Hide resolved
return handlers.problem_format(404, 'The requested URL was not found on the server.'
' If you entered the URL manually please check your spelling and try again.')

Expand All @@ -93,67 +92,57 @@ def default(self, o):
json.JSONEncoder.default(self, o)


class NonValidator:
def __init__(self, spec):
pass

def validate(self, res):
return ResponseValidationResult()


class ErrorHandler(FlaskOpenAPIErrorsHandler):
def __init__(self):
super().__init__()

@classmethod
def handle(cls, errors):
response = super().handle(errors)
def __call__(self, errors):
response = super().__call__(errors)
error = response.json['errors'][0]
return handlers.problem_format(error['status'], error['title'])


class Jobs(FlaskOpenAPIView):
def __init__(self, spec):
super().__init__(spec)
self.response_validator = NonValidator
self.openapi_errors_handler = ErrorHandler
app.json_encoder = CustomEncoder

openapi = FlaskOpenAPIViewDecorator(
api_spec,
response_cls=None,
errors_handler_cls=ErrorHandler,
)


def post(self):
return jsonify(handlers.post_jobs(request.get_json(), g.user))
@app.route('/jobs', methods=['POST'])
@openapi
def jobs_post():
return jsonify(handlers.post_jobs(request.get_json(), g.user))
jtherrmann marked this conversation as resolved.
Show resolved Hide resolved

def get(self, job_id):
if job_id is not None:
return jsonify(handlers.get_job_by_id(job_id))
parameters = request.openapi.parameters.query
start = parameters.get('start')
end = parameters.get('end')
return jsonify(handlers.get_jobs(

@app.route('/jobs', methods=['GET'])
@openapi
def jobs_get():
parameters = request.openapi.parameters.query
start = parameters.get('start')
end = parameters.get('end')
return jsonify(
handlers.get_jobs(
parameters.get('user_id') or g.user,
start.isoformat(timespec='seconds') if start else None,
end.isoformat(timespec='seconds') if end else None,
parameters.get('status_code'),
parameters.get('name'),
parameters.get('job_type'),
parameters.get('start_token'),
))


class User(FlaskOpenAPIView):
def __init__(self, spec):
super().__init__(spec)
self.response_validator = NonValidator
self.openapi_errors_handler = ErrorHandler
)
)

def get(self):
return jsonify(handlers.get_user(g.user))

@app.route('/jobs/<job_id>', methods=['GET'])
@openapi
def jobs_get_by_job_id(job_id):
return jsonify(handlers.get_job_by_id(job_id))

app.json_encoder = CustomEncoder

jobs_view = Jobs.as_view('jobs', api_spec)
app.add_url_rule('/jobs', view_func=jobs_view, methods=['GET'], defaults={'job_id': None})
app.add_url_rule('/jobs', view_func=jobs_view, methods=['POST'])
app.add_url_rule('/jobs/<job_id>', view_func=jobs_view, methods=['GET'])

user_view = User.as_view('user', api_spec)
app.add_url_rule('/user', view_func=user_view)
@app.route('/user', methods=['GET'])
@openapi
def user_get():
return jsonify(handlers.get_user(g.user))
2 changes: 1 addition & 1 deletion requirements-all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ flake8-import-order==0.18.2
flake8-blind-except==0.2.1
flake8-builtins==2.2.0
setuptools==69.0.3
openapi-spec-validator==0.4.0
openapi-spec-validator==0.7.1
cfn-lint==0.83.7
5 changes: 3 additions & 2 deletions requirements-apps-api.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
flask==2.2.5
Flask-Cors==4.0.0
jsonschema==4.17.3
openapi-core==0.14.5
jsonschema==4.20.0
# TODO convert this pin back to the normal format after the next PyPI release
openapi-core @ git+https://github.com/python-openapi/[email protected]
prance==23.6.21.0
PyJWT==2.8.0
requests==2.31.0
Expand Down
Loading