def test_schema_validity(self):
     """Check to make sure that the Swagger schema specification is
     valid by running it through the online validator. If the schema
     is valid, the online validator will return 200 OK and an empty
     JSON response."""
     path = os.path.abspath(self.swagger_path)
     swagger_spec_validator.validate_spec_url('file://' + path)
예제 #2
0
    def test_swagger_validation(self):
        """Ensure our swagger spec matches swagger schema"""

        with tempfile.NamedTemporaryFile(
            prefix='swagger_test_',
            suffix='.json',
            delete=True,
        ) as temp_spec:
            temp_spec.write(self.client.get('/spec').data)
            temp_spec.seek(0)

            validate_spec_url("file:%s" % temp_spec.name)
예제 #3
0
from swagger_spec_validator import validate_spec_url
import sys

validate_spec_url(sys.argv[1])
"""Python Cookbook

Chapter 12, recipe 5 -- client.
"""

import urllib.request
import urllib.parse
import json

if __name__ == "__main__":

    try:
        from swagger_spec_validator import validate_spec_url
        validate_spec_url('http://127.0.0.1:5000/dealer/swagger.json')
        print("swagger.json is valid")
    except ImportError as ex:
        pass

    # 1. Get the OpenAPI specification.

    swagger_request = urllib.request.Request(
        url='http://127.0.0.1:5000/dealer/swagger.json',
        method="GET",
        headers={
            'Accept': 'application/json',
        })

    from pprint import pprint
    with urllib.request.urlopen(
            'http://127.0.0.1:5000/dealer/swagger.json') as response:
        swagger = json.loads(response.read().decode("utf-8"))
예제 #5
0
    def post(self, request, format=None):
        # Some docs:
        # Slack
        # Basic formatting: https://api.slack.com/docs/message-formatting
        generic_error_msg = _(
            'Something went wrong here... I will tell the developers and hopefully they will manage to fix this.'
        )
        not_existing_msg = _(
            'This information is not defined in the Swagger file. Sorry!')
        not_defined_msg = _(
            'This data is not part of the OpenAPI specifications: https://github.com/OAI/OpenAPI-Specification'
        )
        no_api_msg = _(
            'We do not have information about this API. Feel free to add it yourself!'
        )

        serializer = BotSerializer(data=request.data)
        output_data = {}

        if serializer.is_valid():
            # All the APIs
            queryset = Swagger.objects.all()

            # Parse some of the input from api.ai
            parameters = serializer.validated_data['result']['parameters']
            contexts = serializer.validated_data['result']['contexts']
            metadata = serializer.validated_data['result']['metadata']
            action = serializer.validated_data['result']['action']

            # Check what type of data we need to return

            # List all APIs
            ###############
            if action == 'api.list':
                api_list = queryset.values_list('name',
                                                flat=True).order_by('name')

                # Define buttons for Slack
                actions = []

                for api in api_list:
                    actions.append({
                        'name': api,
                        'text': api,
                        'value': _('Use {0}').format(api),
                    })

                attachments = {
                    'text':
                    _('Which API you want to know more about? Here are top APIs:'
                      ),
                    'fallback':
                    generic_error_msg,
                    'callback_id':
                    'api_list',
                    'actions':
                    actions,
                }
                attachments_list = {
                    'text':
                    _('We have these APIs:\n{0}\nIf you want to know more about a certain API, just tell me you want to *use* that one.\nYou can also *create* a new API if you have a URL to a valid Swagger file.'
                      ).format('\n'.join(api_list)),
                    'attachments': [
                        attachments,
                    ],
                }
                data_response = {
                    'slack': attachments_list,
                }

                output_data['data'] = data_response

                output_data['displayText'] = _(
                    'We have these APIs:\n{0}\nIf you want to know more about a certain API, just tell me you want to *use* that one.\nYou can also *create* a new API if you have a URL to a valid Swagger file.'
                ).format('\n'.join(api_list))

            # Add a new API
            ###############
            elif action == 'api.create':
                try:
                    # TODO
                    # Bugfix
                    # we lose the http(s):// from Slack input
                    # verify and add it if necessary

                    # This is ugly - no way out to get a serializer field name
                    # with a dot in the name
                    request_url = request.data['result']['contexts'][0][
                        'parameters']['url.original']
                    if url_is_alive(request_url):
                        url = request_url
                    elif url_is_alive('https://' + request_url):
                        url = 'https://' + request_url
                    elif url_is_alive('http://' + request_url):
                        url = 'http://' + request_url

                    else:
                        output_data['displayText'] = _(
                            '{0} - This is an invalid URL!').format(
                                request_url)

                    # # Do we have a valid URL?
                    # validate_url = URLValidator()
                    # try:
                    #     validate_url(parameters['url'])
                    #     url = parameters['url']
                    # # The http got stripped out
                    # except ValidationError:
                    #     try:
                    #         validate_url('http://{0}'.format(parameters['url']))
                    #         url = 'http://{0}'.format(parameters['url'])
                    #     except ValidationError:
                    #         output_data['displayText'] = _('This is an invalid URL!')

                    if (url):
                        # API with same name exists
                        if (queryset.filter(name=parameters['api'])):
                            output_data['displayText'] = _(
                                'An API with this name already exists!')
                        # API with same URL exists
                        elif (queryset.filter(swaggerfile=url)):
                            output_data['displayText'] = _(
                                'An API pointing to this URL already exists!')
                        # Create new API
                        else:
                            # Validate the URL that it is a Swagger 2.0 file
                            try:
                                # Validate the JSON file. Will throw an exception
                                # if the file is not valid
                                validate_spec_url(url)
                                # Create new API
                                Swagger.objects.create(
                                    name=parameters['api'],
                                    swaggerfile=url,
                                )
                                output_data['displayText'] = _(
                                    'New API added, thanks!')
                            except:
                                output_data['displayText'] = _(
                                    'This is not a valid Swagger 2.0 file.')
                except KeyError:
                    output_data['displayText'] = _(
                        'I need a name and URL pointing to a OpenAPI json specification in order to create a new API.'
                    )

            # Information about specific API
            ################################
            elif action == 'api.info':
                try:
                    api = self.get_api(parameters, contexts)
                    parser = self.get_parser(api)
                    # Do we have a request for generic information of this API?
                    if parameters['data'] in info_fields:
                        try:
                            output_data['displayText'] = _(
                                'Here is the *{0}* you asked for *{1}*:\n{2}'
                            ).format(
                                parameters['data'],
                                api,
                                parser.specification['info'][
                                    parameters['data']],
                            )
                        except:
                            output_data['displayText'] = not_existing_msg

                    # Do we have Swagger object fields?
                    elif parameters['data'] in swagger_fields:
                        try:
                            output_data['displayText'] = _(
                                'Here is the *{0}* you asked for *{1}*:\n{2}'
                            ).format(parameters['data'], api,
                                     parser.specification[parameters['data']])
                        except:
                            output_data['displayText'] = not_existing_msg

                    # Some general data about the API
                    elif parameters['data'] in general_data:
                        # List all the paths
                        # TODO
                        # Add buttons
                        if parameters['data'] == 'paths':
                            paths = parser.paths.keys()
                            if (paths):
                                # Define buttons for Slack
                                actions = []

                                for path in paths:
                                    actions.append({
                                        'name':
                                        path,
                                        'text':
                                        path,
                                        'value':
                                        _('Explain path {0}').format(path),
                                    })

                                attachments = {
                                    'text':
                                    _('Which path you want to know more about? Here are the top paths:'
                                      ),
                                    'fallback':
                                    generic_error_msg,
                                    'callback_id':
                                    'paths',
                                    'actions':
                                    actions,
                                }
                                attachments_list = {
                                    'text':
                                    _('Here is a *list of paths* defined:\n{0}'
                                      ).format('\n'.join(paths)),
                                    'attachments': [
                                        attachments,
                                    ],
                                }
                                data_response = {
                                    'slack': attachments_list,
                                }

                                output_data['data'] = data_response

                                output_data['displayText'] = _(
                                    'Here is the *{0}* you asked for *{1}*:\n{2}'
                                ).format(parameters['data'], api,
                                         '\n'.join(paths))
                            else:
                                output_data['displayText'] = _(
                                    'There are no paths defined in this OpenAPI specification.'
                                )

                        # List all the operations
                        elif parameters['data'] == 'operations':
                            operations = parser.operation.keys()
                            if (operations):
                                # Define buttons for Slack
                                actions = []

                                for operation in operations:
                                    actions.append({
                                        'name':
                                        operation,
                                        'text':
                                        operation,
                                        'value':
                                        _('Explain operation {0}').format(
                                            operation),
                                    })

                                attachments = {
                                    'text':
                                    _('Which operation you want to know more about? Here are the top operations:'
                                      ),
                                    'fallback':
                                    generic_error_msg,
                                    'callback_id':
                                    'operations',
                                    'actions':
                                    actions,
                                }
                                attachments_list = {
                                    'text':
                                    _('Here is a *list of operations* defined:\n{0}'
                                      ).format('\n'.join(operations)),
                                    'attachments': [
                                        attachments,
                                    ],
                                }
                                data_response = {
                                    'slack': attachments_list,
                                }

                                output_data['data'] = data_response

                                output_data['displayText'] = _(
                                    'Here is the *{0}* you asked for *{1}*:\n{2}'
                                ).format(parameters['data'], api,
                                         '\n'.join(operations))
                            else:
                                output_data['displayText'] = _(
                                    'There are no operations defined in this OpenAPI specification.'
                                )

                        # List all the objects
                        elif parameters['data'] == 'definitions':
                            definitions = parser.specification[
                                'definitions'].keys()
                            if (definitions):
                                # Define buttons for Slack
                                actions = []

                                for definition in definitions:
                                    actions.append({
                                        'name':
                                        definition,
                                        'text':
                                        definition,
                                        'value':
                                        _('Explain object {0}').format(
                                            definition),
                                    })

                                attachments = {
                                    'text':
                                    _('Which object you want to know more about? Here are top objects:'
                                      ),
                                    'fallback':
                                    generic_error_msg,
                                    'callback_id':
                                    'object_definitions',
                                    'actions':
                                    actions,
                                }
                                attachments_list = {
                                    'text':
                                    _('Here is a *list of objects* defined:\n{0}'
                                      ).format('\n'.join(definitions)),
                                    'attachments': [
                                        attachments,
                                    ],
                                }
                                data_response = {
                                    'slack': attachments_list,
                                }

                                output_data['data'] = data_response

                                # And display text
                                output_data['displayText'] = '\n'.join(
                                    definitions)
                            else:
                                # And display text
                                output_data['displayText'] = _(
                                    'No objects are defined in this OpenAPI specification.'
                                )

                    # No idea what they want...
                    # TODO: start logging these so we can analyze
                    else:
                        output_data['displayText'] = not_defined_msg

                except ObjectDoesNotExist:
                    output_data['displayText'] = no_api_msg
                # except Exception:
                #     output_data['displayText'] = generic_error_msg
                except Exception as e:
                    output_data['displayText'] = str(e)
            # Object definitions for specific API
            #####################################
            elif action == 'api.object-definition':
                try:
                    # TODO
                    # Give an example can be added explicitly
                    api = self.get_api(parameters, contexts)
                    parser = self.get_parser(api)
                    # Sometimes the keys are stored in lower or titlecase.
                    # We deal with that.
                    if (parameters['object']
                            in parser.specification['definitions']):
                        definition = parser.specification['definitions'][
                            parameters['object']]
                    elif (parameters['object'].lower()
                          in parser.specification['definitions']):
                        definition = parser.specification['definitions'][
                            parameters['object'].lower()]
                    else:
                        definition = parser.specification['definitions'][
                            parameters['object'].title()]

                    # Are there linked operations to this object?
                    # TODO
                    # Follow-up on https://github.com/OAI/OpenAPI-Specification/issues/1097
                    # Now comes a dirty and messy method filled with assumptions
                    # But it's the best we can do so far

                    # 1. Check for schema references to the object
                    # 1.1 parameters
                    # (Pdb) parser.paths['/v2/pet']['put']['parameters']['body']['schema']['$ref']
                    # parser.paths[path][method]['parameters']['body']['schema']['$ref']
                    # Loop through every path, method
                    # 1.2 Response
                    # (Pdb) parser.paths['/v2/pet/{petId}']['get']['responses']['200']['schema']['$ref']
                    # parser.paths[path][method]['responses'][status-code]['schema']['$ref']
                    # Loop through every path, method, status-code
                    # result: '#/definitions/<object>' - regex
                    # 2. Check for tags using the same name
                    # (Pdb) parser.operation['getInventory'][2]
                    # parser.operation[operation][2]
                    # Loop through operations
                    # 'store'
                    # 3. Check for paths containing the same name - regex
                    # 4. Check for operations containing the same name - regex

                    operations = []

                    for path in parser.specification['paths']:
                        for method in parser.specification['paths'][path]:
                            # Sometimes we don't have the operationID defined
                            # Show method and path instead
                            if ('operationId' in parser.specification['paths']
                                [path][method]):
                                operation = {
                                    'type':
                                    'operation',
                                    'value':
                                    parser.specification['paths'][path][method]
                                    ['operationId'],
                                }
                            else:
                                operation = {
                                    'type':
                                    'path',
                                    'value':
                                    _('{0} {1}').format(
                                        method.upper(),
                                        path,
                                    ),
                                }

                            # Do we have tags referencing the object?
                            if ('tags' in parser.specification['paths'][path]
                                [method]):
                                if (parameters['object'].lower() in [
                                        tag.lower() for tag in
                                        parser.specification['paths'][path]
                                    [method]['tags']
                                ]):
                                    operation['path'] = path
                                    operation['method'] = method
                                    operations.append(operation)
                                    break

                            # Do we have the name of the object in the path somewhere?
                            if (parameters['object'].lower() in path):
                                operation['path'] = path
                                operation['method'] = method
                                operations.append(operation)
                                break

                            # Do we have the name of the object in the operation name somewhere?
                            if (parameters['object'].lower() in operation):
                                operation['path'] = path
                                operation['method'] = method
                                operations.append(operation)
                                break

                            # Do we have input parameters referencing the object? e.g. PUT or POST methods
                            if ('parameters' in parser.specification['paths']
                                [path][method]):
                                for parameter in parser.specification['paths'][
                                        path][method]['parameters']:
                                    # Regex the object out
                                    try:
                                        match = re.match(
                                            r'#/definitions/(\w+)',
                                            parameter['schema']['$ref'])
                                        # Does the object match the input from user?
                                        if (match and match.group(1).lower() ==
                                                parameters['object'].lower()):
                                            operation['path'] = path
                                            operation['method'] = method
                                            operations.append(operation)
                                            break
                                    except Exception:
                                        pass

                            # Do we have responses referencing the object? e.g. GET methods
                            if ('responses' in parser.specification['paths']
                                [path][method]):
                                try:
                                    for status_code in parser.specification[
                                            'paths'][path][method][
                                                'responses']:
                                        if ('schema' in parser.specification[
                                                'paths'][path][method]
                                            ['responses'][status_code]):
                                            # In case of a list of objects
                                            if ('items' in parser.
                                                    specification['paths']
                                                [path][method]['responses']
                                                [status_code]['schema']):
                                                match = re.match(
                                                    r'#/definitions/(\w+)',
                                                    parser.
                                                    specification['paths']
                                                    [path][method]['responses']
                                                    [status_code]['schema']
                                                    ['items']['$ref'])
                                                # Does the object match the input from user?
                                                if (match and
                                                        match.group(1).lower()
                                                        == parameters['object']
                                                        .lower()):
                                                    operation['path'] = path
                                                    operation[
                                                        'method'] = method
                                                    operations.append(
                                                        operation)
                                                    break
                                            # In case of a single item
                                            else:
                                                match = re.match(
                                                    r'#/definitions/(\w+)',
                                                    parser.specification[
                                                        'paths'][path][method]
                                                    ['responses'][status_code]
                                                    ['schema']['$ref'])
                                                # Does the object match the input from user?
                                                if (match and
                                                        match.group(1).lower()
                                                        == parameters['object']
                                                        .lower()):
                                                    operation['path'] = path
                                                    operation[
                                                        'method'] = method
                                                    operations.append(
                                                        operation)
                                                    break

                                except Exception:
                                    pass

                    if (operations and definition):
                        # Define buttons for Slack
                        actions = []

                        for operation in operations:
                            actions.append({
                                'name':
                                operation['value'],
                                'text':
                                operation['value'],
                                'value':
                                _('Explain {0} {1}').format(
                                    operation['type'],
                                    operation['value'] if operation['type']
                                    == 'operation' else operation['path']),
                            })

                        attachments = {
                            'text':
                            _('Which operation you want to know more about? Here are top operations:'
                              ),
                            'fallback':
                            generic_error_msg,
                            'callback_id':
                            'object_definition',
                            'actions':
                            actions,
                        }
                        attachments_list = {
                            'text':
                            _('Here is the object definition for *{0}*:\n{1}\n\nI also found these operations linked to it:\n{2}'
                              ).format(
                                  parameters['object'],
                                  pprint.pformat(definition),
                                  '\n'.join(operation['value']
                                            for operation in operations),
                              ),
                            'attachments': [
                                attachments,
                            ],
                        }
                        data_response = {
                            'slack': attachments_list,
                        }

                        output_data['data'] = data_response

                        # And display text
                        output_data['displayText'] = '\n'.join(
                            operation['value'] for operation in operations)
                    elif (definition):
                        output_data['displayText'] = _(
                            'Here is the object definition for *{0}*:\n{1}'
                        ).format(
                            parameters['object'],
                            pprint.pformat(definition),
                        )
                except KeyError:
                    output_data['displayText'] = not_defined_msg

                except ObjectDoesNotExist:
                    output_data['displayText'] = no_api_msg

            # Operation definitions for specific API
            ########################################
            elif action == 'api.operation':
                try:
                    api = self.get_api(parameters, contexts)
                    parser = self.get_parser(api)
                    try:
                        output_data['displayText'] = _(
                            'Here is the operation definition for *{0}*:\n{1}'
                        ).format(
                            parameters['operation'],
                            pprint.pformat(
                                parser.operation[parameters['operation']]),
                        )
                    except KeyError:
                        output_data['displayText'] = not_defined_msg

                except ObjectDoesNotExist:
                    output_data['displayText'] = no_api_msg

            # Path info for specific API
            ############################
            elif action == 'api.path':
                try:
                    api = self.get_api(parameters, contexts)
                    parser = self.get_parser(api)
                    try:
                        # TODO
                        # This is a dirty dirty fix because due to a bug
                        # in api.ai, the leading / gets stripped
                        # Occasionally check if this is resolved
                        # https://discuss.api.ai/t/slashes-are-removed/5595
                        if parameters['path'] in parser.paths:
                            path = parameters['path']
                        elif '/' + parameters['path'] in parser.paths:
                            path = '/' + parameters['path']
                        elif parser.base_path + '/' + parameters[
                                'path'] in parser.paths:
                            path = parser.base_path + '/' + parameters['path']

                        output_data['displayText'] = _(
                            'Here is the path definition for *{0}*:\n{1}'
                        ).format(
                            path,
                            pprint.pformat(parser.paths[path]),
                        )

                        output_data['displayText'] = pprint.pformat(
                            parser.paths[path])

                    except KeyError:
                        output_data['displayText'] = not_defined_msg
                    except Exception:
                        output_data['displayText'] = generic_error_msg

                except ObjectDoesNotExist:
                    output_data['displayText'] = no_api_msg
                except Exception:
                    output_data['displayText'] = generic_error_msg

# TODO
# "securityDefinitions"
# "securityDefinitions":{
#    "petstore_auth":{
#       "type":"oauth2",
#       "authorizationUrl":"http://petstore.swagger.io/oauth/dialog",
#       "flow":"implicit",
#       "scopes":{
#          "write:pets":"modify pets in your account",
#          "read:pets":"read your pets"
#       }
#    },
#    "api_key":{
#       "type":"apiKey",
#       "name":"api_key",
#       "in":"header"
#    }

# Fallback response
###################

# We have no idea what this intent is...
            else:
                output_data['displayText'] = not_defined_msg

            # For now duplicate the display text and speech
            output_data['speech'] = output_data['displayText']
            serializer = BotResponseSerializer(output_data)
            return Response(serializer.data, status=HTTP_200_OK)
        else:
            return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
예제 #6
0
def test_swagger(api_url):
    """Test for swagger doc."""
    assert not validate_spec_url('{0}/api/v1.0/spec'.format(api_url))
#!/usr/bin/env python
import sys

from swagger_spec_validator import validate_spec_url
from swagger_spec_validator.common import SwaggerValidationError
from jsonschema import ValidationError

DEFAULT_SWAGGER_SPEC_LOCATION = '/mnt/swagger.json'

if __name__ == '__main__':
    spec = DEFAULT_SWAGGER_SPEC_LOCATION
    if len(sys.argv) > 1:
        spec = sys.argv[1]
    try:
        validate_spec_url(f'file://{spec}')
    except SwaggerValidationError as e:
        arg = e.args[1].args[1]
        while True:
            _, e = e.args
            if isinstance(e, ValidationError):
                print(e)
                sys.exit(1)
예제 #8
0
 def test_schema_validity(self):
     """Validate the schema using swagger_spec_validator."""
     path = os.path.abspath(self.swagger_path)
     swagger_spec_validator.validate_spec_url('file://' + path)
예제 #9
0
# from bs4 import BeautifulSoup as Soup
# import python_jsonschema_objects as jsob
from typing import List, Set, Dict, Any
import requests
# import requests_cache
import json
import config
from collections import namedtuple
from swagger_spec_validator import validate_spec_url

# requests_cache.install_cache('api_live_cache')
session = requests.session()
url1: str = f'https://{config.servername}/doc/api'
print(f'{url1}/api-docs')
validate_spec_url(f'{url1}')

# h = session.get(f'{url1}/api-docs.json').json()

# resource_urls: List[str] = [f'{url1}{method["path"]}' for method in h['apis']]

# api_data: Dict = {}
# for resource in resource_urls:
#     parser = prance.ResolvingParser(resource)
#     doc: Dict = session.get(resource).json()
#     fname: str = resource.split('/')[-1]
#     with open(f'./api_docs/{fname}', 'w') as g:
#         g.write(json.dumps(doc, indent=4))
#     print(json.dumps(doc, indent=4))
#     # pyjsob = jsob.ObjectBuilder(doc)
#     # ns = pyjsob.build_classes()
#     # method = ns.api
예제 #10
0
def validateSwagger(url):
    testAPIBasePath = "{}/test/api".format(url)
    validate_spec_url(testAPIBasePath + '/swagger.json')