APIGateway: get_export() (#5844)
This commit is contained in:
parent
6e7d3ec938
commit
173e1549c0
@ -5,6 +5,7 @@ import re
|
||||
import responses
|
||||
import requests
|
||||
import time
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
from openapi_spec_validator import validate_spec
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
@ -19,6 +20,7 @@ from moto.core import BaseBackend, BackendDict, BaseModel, CloudFormationModel
|
||||
from .utils import create_id, to_path
|
||||
from moto.core.utils import path_url
|
||||
from .exceptions import (
|
||||
BadRequestException,
|
||||
ConflictException,
|
||||
DeploymentNotFoundException,
|
||||
ApiKeyNotFoundException,
|
||||
@ -1572,6 +1574,42 @@ class APIGatewayBackend(BaseBackend):
|
||||
self.put_rest_api(api.id, api_doc, fail_on_warnings=fail_on_warnings)
|
||||
return api
|
||||
|
||||
def export_api(self, rest_api_id: str, export_type: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Not all fields are implemented yet.
|
||||
The export-type is currently ignored - we will only return the 'swagger'-format
|
||||
"""
|
||||
try:
|
||||
api = self.get_rest_api(rest_api_id)
|
||||
except RestAPINotFound:
|
||||
raise StageNotFoundException
|
||||
if export_type not in ["swagger", "oas30"]:
|
||||
raise BadRequestException(f"No API exporter for type '{export_type}'")
|
||||
now = datetime.now().strftime("%Y-%m-%dT%H:%m:%S")
|
||||
resp: Dict[str, Any] = {
|
||||
"swagger": "2.0",
|
||||
"info": {"version": now, "title": api.name},
|
||||
"host": f"{api.id}.execute-api.{self.region_name}.amazonaws.com",
|
||||
"basePath": "/",
|
||||
"schemes": ["https"],
|
||||
"paths": {},
|
||||
"definitions": {"Empty": {"type": "object", "title": "Empty Schema"}},
|
||||
}
|
||||
for res in api.resources.values():
|
||||
path = res.get_path()
|
||||
resp["paths"][path] = {}
|
||||
for method_type, method in res.resource_methods.items():
|
||||
resp["paths"][path][method_type] = {
|
||||
"produces": ["application/json"],
|
||||
"responses": {},
|
||||
}
|
||||
for code, _ in method.method_responses.items():
|
||||
resp["paths"][path][method_type]["responses"][code] = {
|
||||
"description": f"{code} response",
|
||||
"schema": {"$ref": "#/definitions/Empty"},
|
||||
}
|
||||
return resp
|
||||
|
||||
def get_rest_api(self, function_id: str) -> RestAPI:
|
||||
rest_api = self.apis.get(function_id)
|
||||
if rest_api is None:
|
||||
@ -1610,6 +1648,27 @@ class APIGatewayBackend(BaseBackend):
|
||||
for (path, resource_doc) in sorted(
|
||||
api_doc["paths"].items(), key=lambda x: x[0]
|
||||
):
|
||||
# We may want to create a path like /store/inventory
|
||||
# Ensure that /store exists first, so we can use it as a parent
|
||||
ancestors = path.split("/")[
|
||||
1:-1
|
||||
] # skip first (empty), skip last (child) - only process ancestors
|
||||
direct_parent = ""
|
||||
parent_id = self.apis[function_id].get_resource_for_path("/").id
|
||||
for a in ancestors:
|
||||
res = self.apis[function_id].get_resource_for_path(
|
||||
direct_parent + "/" + a
|
||||
)
|
||||
if res is None:
|
||||
res = self.create_resource(
|
||||
function_id=function_id,
|
||||
parent_resource_id=parent_id,
|
||||
path_part=a,
|
||||
)
|
||||
parent_id = res.id
|
||||
direct_parent = direct_parent + "/" + a
|
||||
|
||||
# Now that we know all ancestors are created, create the resource itself
|
||||
parent_path_part = path[0 : path.rfind("/")] or "/"
|
||||
parent_resource_id = (
|
||||
self.apis[function_id].get_resource_for_path(parent_path_part).id
|
||||
|
@ -429,6 +429,22 @@ class APIGatewayResponse(BaseResponse):
|
||||
self.backend.delete_stage(function_id, stage_name)
|
||||
return 202, {}, "{}"
|
||||
|
||||
def export(self, request: Any, full_url: str, headers: Dict[str, str]) -> TYPE_RESPONSE: # type: ignore[return]
|
||||
self.setup_class(request, full_url, headers)
|
||||
url_path_parts = self.path.split("/")
|
||||
rest_api_id = url_path_parts[-5]
|
||||
export_type = url_path_parts[-1]
|
||||
|
||||
body = self.backend.export_api(rest_api_id, export_type)
|
||||
|
||||
now = body["info"]["version"]
|
||||
filename = f"swagger_{now}Z.json"
|
||||
headers = {
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Disposition": f'attachment; filename="{filename}"',
|
||||
}
|
||||
return 200, headers, json.dumps(body).encode("utf-8")
|
||||
|
||||
def integrations(self, request: Any, full_url: str, headers: Dict[str, str]) -> TYPE_RESPONSE: # type: ignore[return]
|
||||
self.setup_class(request, full_url, headers)
|
||||
url_path_parts = self.path.split("/")
|
||||
|
@ -14,6 +14,7 @@ url_paths = {
|
||||
"{0}/restapis/(?P<function_id>[^/]+)/stages$": response.restapis_stages,
|
||||
"{0}/tags/arn:aws:apigateway:(?P<region_name>[^/]+)::/restapis/(?P<function_id>[^/]+)/stages/(?P<stage_name>[^/]+)/?$": response.restapis_stages_tags,
|
||||
"{0}/restapis/(?P<function_id>[^/]+)/stages/(?P<stage_name>[^/]+)/?$": response.stages,
|
||||
"{0}/restapis/(?P<function_id>[^/]+)/stages/(?P<stage_name>[^/]+)/exports/(?P<export_type>[^/]+)/?$": response.export,
|
||||
"{0}/restapis/(?P<function_id>[^/]+)/deployments$": response.deployments,
|
||||
"{0}/restapis/(?P<function_id>[^/]+)/deployments/(?P<deployment_id>[^/]+)/?$": response.individual_deployment,
|
||||
"{0}/restapis/(?P<function_id>[^/]+)/resources/(?P<resource_id>[^/]+)/?$": response.resource_individual,
|
||||
|
@ -1,5 +1,5 @@
|
||||
from typing import Dict, Tuple, TypeVar
|
||||
from typing import Dict, Tuple, TypeVar, Union
|
||||
|
||||
|
||||
TYPE_RESPONSE = Tuple[int, Dict[str, str], str]
|
||||
TYPE_RESPONSE = Tuple[int, Dict[str, str], Union[str, bytes]]
|
||||
TYPE_IF_NONE = TypeVar("TYPE_IF_NONE")
|
||||
|
819
tests/test_apigateway/resources/petstore-swagger-v3.yaml
Normal file
819
tests/test_apigateway/resources/petstore-swagger-v3.yaml
Normal file
@ -0,0 +1,819 @@
|
||||
openapi: 3.0.2
|
||||
servers:
|
||||
- url: /v3
|
||||
info:
|
||||
description: |-
|
||||
This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
|
||||
Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
|
||||
You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
|
||||
|
||||
Some useful links:
|
||||
- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
|
||||
- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
|
||||
version: 1.0.17
|
||||
title: Swagger Petstore - OpenAPI 3.0
|
||||
termsOfService: 'http://swagger.io/terms/'
|
||||
contact:
|
||||
email: apiteam@swagger.io
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
|
||||
tags:
|
||||
- name: pet
|
||||
description: Everything about your Pets
|
||||
externalDocs:
|
||||
description: Find out more
|
||||
url: 'http://swagger.io'
|
||||
- name: store
|
||||
description: Access to Petstore orders
|
||||
externalDocs:
|
||||
description: Find out more about our store
|
||||
url: 'http://swagger.io'
|
||||
- name: user
|
||||
description: Operations about user
|
||||
paths:
|
||||
/pet:
|
||||
post:
|
||||
tags:
|
||||
- pet
|
||||
summary: Add a new pet to the store
|
||||
description: Add a new pet to the store
|
||||
operationId: addPet
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'405':
|
||||
description: Invalid input
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
requestBody:
|
||||
description: Create a new pet in the store
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
put:
|
||||
tags:
|
||||
- pet
|
||||
summary: Update an existing pet
|
||||
description: Update an existing pet by Id
|
||||
operationId: updatePet
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Pet not found
|
||||
'405':
|
||||
description: Validation exception
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
requestBody:
|
||||
description: Update an existent pet in the store
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
/pet/findByStatus:
|
||||
get:
|
||||
tags:
|
||||
- pet
|
||||
summary: Finds Pets by status
|
||||
description: Multiple status values can be provided with comma separated strings
|
||||
operationId: findPetsByStatus
|
||||
parameters:
|
||||
- name: status
|
||||
in: query
|
||||
description: Status values that need to be considered for filter
|
||||
required: false
|
||||
explode: true
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- available
|
||||
- pending
|
||||
- sold
|
||||
default: available
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'400':
|
||||
description: Invalid status value
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
/pet/findByTags:
|
||||
get:
|
||||
tags:
|
||||
- pet
|
||||
summary: Finds Pets by tags
|
||||
description: >-
|
||||
Multiple tags can be provided with comma separated strings. Use tag1,
|
||||
tag2, tag3 for testing.
|
||||
operationId: findPetsByTags
|
||||
parameters:
|
||||
- name: tags
|
||||
in: query
|
||||
description: Tags to filter by
|
||||
required: false
|
||||
explode: true
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'400':
|
||||
description: Invalid tag value
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
'/pet/{petId}':
|
||||
get:
|
||||
tags:
|
||||
- pet
|
||||
summary: Find pet by ID
|
||||
description: Returns a single pet
|
||||
operationId: getPetById
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
description: ID of pet to return
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Pet not found
|
||||
security:
|
||||
- api_key: []
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
post:
|
||||
tags:
|
||||
- pet
|
||||
summary: Updates a pet in the store with form data
|
||||
description: ''
|
||||
operationId: updatePetWithForm
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
description: ID of pet that needs to be updated
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
- name: name
|
||||
in: query
|
||||
description: Name of pet that needs to be updated
|
||||
schema:
|
||||
type: string
|
||||
- name: status
|
||||
in: query
|
||||
description: Status of pet that needs to be updated
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'405':
|
||||
description: Invalid input
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
delete:
|
||||
tags:
|
||||
- pet
|
||||
summary: Deletes a pet
|
||||
description: ''
|
||||
operationId: deletePet
|
||||
parameters:
|
||||
- name: api_key
|
||||
in: header
|
||||
description: ''
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
- name: petId
|
||||
in: path
|
||||
description: Pet id to delete
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'400':
|
||||
description: Invalid pet value
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
'/pet/{petId}/uploadImage':
|
||||
post:
|
||||
tags:
|
||||
- pet
|
||||
summary: uploads an image
|
||||
description: ''
|
||||
operationId: uploadFile
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
description: ID of pet to update
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
- name: additionalMetadata
|
||||
in: query
|
||||
description: Additional Metadata
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiResponse'
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
requestBody:
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
/store/inventory:
|
||||
get:
|
||||
tags:
|
||||
- store
|
||||
summary: Returns pet inventories by status
|
||||
description: Returns a map of status codes to quantities
|
||||
operationId: getInventory
|
||||
x-swagger-router-controller: OrderController
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: integer
|
||||
format: int32
|
||||
security:
|
||||
- api_key: []
|
||||
/store/order:
|
||||
post:
|
||||
tags:
|
||||
- store
|
||||
summary: Place an order for a pet
|
||||
description: Place a new order in the store
|
||||
operationId: placeOrder
|
||||
x-swagger-router-controller: OrderController
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
'405':
|
||||
description: Invalid input
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
'/store/order/{orderId}':
|
||||
get:
|
||||
tags:
|
||||
- store
|
||||
summary: Find purchase order by ID
|
||||
x-swagger-router-controller: OrderController
|
||||
description: >-
|
||||
For valid response try integer IDs with value <= 5 or > 10. Other values
|
||||
will generate exceptions.
|
||||
operationId: getOrderById
|
||||
parameters:
|
||||
- name: orderId
|
||||
in: path
|
||||
description: ID of order that needs to be fetched
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Order not found
|
||||
delete:
|
||||
tags:
|
||||
- store
|
||||
summary: Delete purchase order by ID
|
||||
x-swagger-router-controller: OrderController
|
||||
description: >-
|
||||
For valid response try integer IDs with value < 1000. Anything above
|
||||
1000 or nonintegers will generate API errors
|
||||
operationId: deleteOrder
|
||||
parameters:
|
||||
- name: orderId
|
||||
in: path
|
||||
description: ID of the order that needs to be deleted
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Order not found
|
||||
/user:
|
||||
post:
|
||||
tags:
|
||||
- user
|
||||
summary: Create user
|
||||
description: This can only be done by the logged in user.
|
||||
operationId: createUser
|
||||
responses:
|
||||
default:
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
description: Created user object
|
||||
/user/createWithList:
|
||||
post:
|
||||
tags:
|
||||
- user
|
||||
summary: Creates list of users with given input array
|
||||
description: 'Creates list of users with given input array'
|
||||
x-swagger-router-controller: UserController
|
||||
operationId: createUsersWithListInput
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
default:
|
||||
description: successful operation
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
/user/login:
|
||||
get:
|
||||
tags:
|
||||
- user
|
||||
summary: Logs user into the system
|
||||
description: ''
|
||||
operationId: loginUser
|
||||
parameters:
|
||||
- name: username
|
||||
in: query
|
||||
description: The user name for login
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
- name: password
|
||||
in: query
|
||||
description: The password for login in clear text
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
headers:
|
||||
X-Rate-Limit:
|
||||
description: calls per hour allowed by the user
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
X-Expires-After:
|
||||
description: date in UTC when token expires
|
||||
schema:
|
||||
type: string
|
||||
format: date-time
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
type: string
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: Invalid username/password supplied
|
||||
/user/logout:
|
||||
get:
|
||||
tags:
|
||||
- user
|
||||
summary: Logs out current logged in user session
|
||||
description: ''
|
||||
operationId: logoutUser
|
||||
parameters: []
|
||||
responses:
|
||||
default:
|
||||
description: successful operation
|
||||
'/user/{username}':
|
||||
get:
|
||||
tags:
|
||||
- user
|
||||
summary: Get user by user name
|
||||
description: ''
|
||||
operationId: getUserByName
|
||||
parameters:
|
||||
- name: username
|
||||
in: path
|
||||
description: 'The name that needs to be fetched. Use user1 for testing. '
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'400':
|
||||
description: Invalid username supplied
|
||||
'404':
|
||||
description: User not found
|
||||
put:
|
||||
tags:
|
||||
- user
|
||||
summary: Update user
|
||||
x-swagger-router-controller: UserController
|
||||
description: This can only be done by the logged in user.
|
||||
operationId: updateUser
|
||||
parameters:
|
||||
- name: username
|
||||
in: path
|
||||
description: name that need to be deleted
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
default:
|
||||
description: successful operation
|
||||
requestBody:
|
||||
description: Update an existent user in the store
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
delete:
|
||||
tags:
|
||||
- user
|
||||
summary: Delete user
|
||||
description: This can only be done by the logged in user.
|
||||
operationId: deleteUser
|
||||
parameters:
|
||||
- name: username
|
||||
in: path
|
||||
description: The name that needs to be deleted
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'400':
|
||||
description: Invalid username supplied
|
||||
'404':
|
||||
description: User not found
|
||||
externalDocs:
|
||||
description: Find out more about Swagger
|
||||
url: 'http://swagger.io'
|
||||
components:
|
||||
schemas:
|
||||
Order:
|
||||
x-swagger-router-model: io.swagger.petstore.model.Order
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
example: 10
|
||||
petId:
|
||||
type: integer
|
||||
format: int64
|
||||
example: 198772
|
||||
quantity:
|
||||
type: integer
|
||||
format: int32
|
||||
example: 7
|
||||
shipDate:
|
||||
type: string
|
||||
format: date-time
|
||||
status:
|
||||
type: string
|
||||
description: Order Status
|
||||
enum:
|
||||
- placed
|
||||
- approved
|
||||
- delivered
|
||||
example: approved
|
||||
complete:
|
||||
type: boolean
|
||||
xml:
|
||||
name: order
|
||||
type: object
|
||||
Customer:
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
example: 100000
|
||||
username:
|
||||
type: string
|
||||
example: fehguy
|
||||
address:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Address'
|
||||
xml:
|
||||
wrapped: true
|
||||
name: addresses
|
||||
xml:
|
||||
name: customer
|
||||
type: object
|
||||
Address:
|
||||
properties:
|
||||
street:
|
||||
type: string
|
||||
example: 437 Lytton
|
||||
city:
|
||||
type: string
|
||||
example: Palo Alto
|
||||
state:
|
||||
type: string
|
||||
example: CA
|
||||
zip:
|
||||
type: string
|
||||
example: 94301
|
||||
xml:
|
||||
name: address
|
||||
type: object
|
||||
Category:
|
||||
x-swagger-router-model: io.swagger.petstore.model.Category
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
example: 1
|
||||
name:
|
||||
type: string
|
||||
example: Dogs
|
||||
xml:
|
||||
name: category
|
||||
type: object
|
||||
User:
|
||||
x-swagger-router-model: io.swagger.petstore.model.User
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
example: 10
|
||||
username:
|
||||
type: string
|
||||
example: theUser
|
||||
firstName:
|
||||
type: string
|
||||
example: John
|
||||
lastName:
|
||||
type: string
|
||||
example: James
|
||||
email:
|
||||
type: string
|
||||
example: john@email.com
|
||||
password:
|
||||
type: string
|
||||
example: 12345
|
||||
phone:
|
||||
type: string
|
||||
example: 12345
|
||||
userStatus:
|
||||
type: integer
|
||||
format: int32
|
||||
example: 1
|
||||
description: User Status
|
||||
xml:
|
||||
name: user
|
||||
type: object
|
||||
Tag:
|
||||
x-swagger-router-model: io.swagger.petstore.model.Tag
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
xml:
|
||||
name: tag
|
||||
type: object
|
||||
Pet:
|
||||
x-swagger-router-model: io.swagger.petstore.model.Pet
|
||||
required:
|
||||
- name
|
||||
- photoUrls
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
example: 10
|
||||
name:
|
||||
type: string
|
||||
example: doggie
|
||||
category:
|
||||
$ref: '#/components/schemas/Category'
|
||||
photoUrls:
|
||||
type: array
|
||||
xml:
|
||||
wrapped: true
|
||||
items:
|
||||
type: string
|
||||
xml:
|
||||
name: photoUrl
|
||||
tags:
|
||||
type: array
|
||||
xml:
|
||||
wrapped: true
|
||||
items:
|
||||
$ref: '#/components/schemas/Tag'
|
||||
xml:
|
||||
name: tag
|
||||
status:
|
||||
type: string
|
||||
description: pet status in the store
|
||||
enum:
|
||||
- available
|
||||
- pending
|
||||
- sold
|
||||
xml:
|
||||
name: pet
|
||||
type: object
|
||||
ApiResponse:
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
type:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
xml:
|
||||
name: '##default'
|
||||
type: object
|
||||
requestBodies:
|
||||
Pet:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
description: Pet object that needs to be added to the store
|
||||
UserArray:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
description: List of user object
|
||||
securitySchemes:
|
||||
petstore_auth:
|
||||
type: oauth2
|
||||
flows:
|
||||
implicit:
|
||||
authorizationUrl: 'https://petstore.swagger.io/oauth/authorize'
|
||||
scopes:
|
||||
'write:pets': modify pets in your account
|
||||
'read:pets': read your pets
|
||||
api_key:
|
||||
type: apiKey
|
||||
name: api_key
|
||||
in: header
|
50
tests/test_apigateway/resources/test_deep_api.yaml
Normal file
50
tests/test_apigateway/resources/test_deep_api.yaml
Normal file
@ -0,0 +1,50 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
description: description
|
||||
version: '1'
|
||||
title: doc
|
||||
paths:
|
||||
/test/some/deep/path:
|
||||
post:
|
||||
description: Method description.
|
||||
responses:
|
||||
'200':
|
||||
description: 200 response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Empty'
|
||||
|
||||
x-amazon-apigateway-documentation:
|
||||
version: 1.0.3
|
||||
documentationParts:
|
||||
- location:
|
||||
type: API
|
||||
properties:
|
||||
description: API description
|
||||
info:
|
||||
description: API info description 4
|
||||
version: API info version 3
|
||||
- location:
|
||||
type: METHOD
|
||||
method: GET
|
||||
properties:
|
||||
description: Method description.
|
||||
- location:
|
||||
type: MODEL
|
||||
name: Empty
|
||||
properties:
|
||||
title: Empty Schema
|
||||
- location:
|
||||
type: RESPONSE
|
||||
method: GET
|
||||
statusCode: '200'
|
||||
properties:
|
||||
description: 200 response
|
||||
servers:
|
||||
- url: /
|
||||
components:
|
||||
schemas:
|
||||
Empty:
|
||||
type: object
|
||||
title: Empty Schema
|
81
tests/test_apigateway/test_apigateway_export.py
Normal file
81
tests/test_apigateway/test_apigateway_export.py
Normal file
@ -0,0 +1,81 @@
|
||||
import boto3
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from botocore.exceptions import ClientError
|
||||
from moto import mock_apigateway
|
||||
|
||||
|
||||
@mock_apigateway
|
||||
def test_import_rest_api__api_is_created():
|
||||
client = boto3.client("apigateway", region_name="us-west-2")
|
||||
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
with open(path + "/resources/petstore-swagger-v3.yaml", "rb") as api_json:
|
||||
response = client.import_rest_api(body=api_json.read())
|
||||
api_id = response["id"]
|
||||
|
||||
root_id = client.get_resources(restApiId=api_id)["items"][4]["id"]
|
||||
client.get_method(restApiId=api_id, resourceId=root_id, httpMethod="POST")
|
||||
|
||||
client.put_integration(
|
||||
restApiId=api_id, resourceId=root_id, httpMethod="POST", type="MOCK"
|
||||
)
|
||||
client.put_integration_response(
|
||||
restApiId=api_id, resourceId=root_id, httpMethod="POST", statusCode="200"
|
||||
)
|
||||
|
||||
deployment_id = client.create_deployment(restApiId=api_id, stageName="dep")["id"]
|
||||
|
||||
client.create_stage(restApiId=api_id, stageName="stg", deploymentId=deployment_id)
|
||||
|
||||
resp = client.get_export(restApiId=api_id, stageName="stg", exportType="swagger")
|
||||
resp.should.have.key("contentType").equals("application/octet-stream")
|
||||
resp.should.have.key("contentDisposition").match('attachment; filename="swagger')
|
||||
|
||||
body = json.loads(resp["body"].read().decode("utf-8"))
|
||||
|
||||
body["info"].should.have.key("title").equals("Swagger Petstore - OpenAPI 3.0")
|
||||
body["paths"].should.have.length_of(15)
|
||||
|
||||
body["paths"]["/pet/{petId}"].should.have.length_of(3)
|
||||
set(body["paths"]["/pet/{petId}"].keys()).should.equal({"DELETE", "GET", "POST"})
|
||||
|
||||
|
||||
@mock_apigateway
|
||||
def test_export_api__unknown_api():
|
||||
client = boto3.client("apigateway", region_name="us-west-2")
|
||||
|
||||
with pytest.raises(ClientError) as exc:
|
||||
client.get_export(restApiId="unknown", stageName="l", exportType="a")
|
||||
err = exc.value.response["Error"]
|
||||
err["Code"].should.equal("NotFoundException")
|
||||
err["Message"].should.equal("Invalid stage identifier specified")
|
||||
|
||||
|
||||
@mock_apigateway
|
||||
def test_export_api__unknown_export_type():
|
||||
client = boto3.client("apigateway", region_name="us-east-1")
|
||||
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
with open(path + "/resources/petstore-swagger-v3.yaml", "rb") as api_json:
|
||||
response = client.import_rest_api(body=api_json.read())
|
||||
api_id = response["id"]
|
||||
|
||||
root_id = client.get_resources(restApiId=api_id)["items"][4]["id"]
|
||||
client.get_method(restApiId=api_id, resourceId=root_id, httpMethod="POST")
|
||||
|
||||
client.put_integration(
|
||||
restApiId=api_id, resourceId=root_id, httpMethod="POST", type="MOCK"
|
||||
)
|
||||
client.put_integration_response(
|
||||
restApiId=api_id, resourceId=root_id, httpMethod="POST", statusCode="200"
|
||||
)
|
||||
client.create_deployment(restApiId=api_id, stageName="dep")
|
||||
|
||||
with pytest.raises(ClientError) as exc:
|
||||
client.get_export(restApiId=api_id, stageName="dep", exportType="a")
|
||||
err = exc.value.response["Error"]
|
||||
err["Code"].should.equal("BadRequestException")
|
||||
err["Message"].should.equal("No API exporter for type 'a'")
|
@ -27,6 +27,25 @@ def test_import_rest_api__api_is_created():
|
||||
)
|
||||
|
||||
|
||||
@mock_apigateway
|
||||
def test_import_rest_api__nested_api():
|
||||
client = boto3.client("apigateway", region_name="us-west-2")
|
||||
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
with open(path + "/resources/test_deep_api.yaml", "rb") as api_json:
|
||||
response = client.import_rest_api(body=api_json.read())
|
||||
|
||||
resources = client.get_resources(restApiId=response["id"])["items"]
|
||||
resources.should.have.length_of(5)
|
||||
|
||||
paths = [res["path"] for res in resources]
|
||||
paths.should.contain("/")
|
||||
paths.should.contain("/test")
|
||||
paths.should.contain("/test/some")
|
||||
paths.should.contain("/test/some/deep")
|
||||
paths.should.contain("/test/some/deep/path")
|
||||
|
||||
|
||||
@mock_apigateway
|
||||
def test_import_rest_api__invalid_api_creates_nothing():
|
||||
client = boto3.client("apigateway", region_name="us-west-2")
|
||||
|
Loading…
Reference in New Issue
Block a user