diff --git a/moto/apigateway/models.py b/moto/apigateway/models.py index cc8696104..27a9b86c2 100644 --- a/moto/apigateway/models.py +++ b/moto/apigateway/models.py @@ -1,6 +1,8 @@ from __future__ import absolute_import from __future__ import unicode_literals +import random +import string import requests import time @@ -291,6 +293,25 @@ class Stage(BaseModel, dict): raise Exception('Patch operation "%s" not implemented' % op['op']) +class ApiKey(BaseModel, dict): + + def __init__(self, name=None, description=None, enabled=True, + generateDistinctId=False, value=None, stageKeys=None, customerId=None): + super(ApiKey, self).__init__() + self['id'] = create_id() + if generateDistinctId: + # Best guess of what AWS does internally + self['value'] = ''.join(random.sample(string.ascii_letters + string.digits, 40)) + else: + self['value'] = value + self['name'] = name + self['customerId'] = customerId + self['description'] = description + self['enabled'] = enabled + self['createdDate'] = self['lastUpdatedDate'] = int(time.time()) + self['stageKeys'] = stageKeys + + class RestAPI(BaseModel): def __init__(self, id, region_name, name, description): @@ -386,6 +407,7 @@ class APIGatewayBackend(BaseBackend): def __init__(self, region_name): super(APIGatewayBackend, self).__init__() self.apis = {} + self.keys = {} self.region_name = region_name def reset(self): @@ -539,6 +561,21 @@ class APIGatewayBackend(BaseBackend): api = self.get_rest_api(function_id) return api.delete_deployment(deployment_id) + def create_apikey(self, payload): + key = ApiKey(**payload) + self.keys[key['value']] = key + return key + + def get_apikeys(self): + return list(self.keys.values()) + + def get_apikey(self, value): + return self.keys[value] + + def delete_apikey(self, value): + self.keys.pop(value) + return {} + apigateway_backends = {} # Not available in boto yet diff --git a/moto/apigateway/responses.py b/moto/apigateway/responses.py index 443fd4060..ff6ef1f33 100644 --- a/moto/apigateway/responses.py +++ b/moto/apigateway/responses.py @@ -226,3 +226,25 @@ class APIGatewayResponse(BaseResponse): deployment = self.backend.delete_deployment( function_id, deployment_id) return 200, {}, json.dumps(deployment) + + def apikeys(self, request, full_url, headers): + self.setup_class(request, full_url, headers) + + if self.method == 'POST': + apikey_response = self.backend.create_apikey(json.loads(self.body)) + elif self.method == 'GET': + apikeys_response = self.backend.get_apikeys() + return 200, {}, json.dumps({"item": apikeys_response}) + return 200, {}, json.dumps(apikey_response) + + def apikey_individual(self, request, full_url, headers): + self.setup_class(request, full_url, headers) + + url_path_parts = self.path.split("/") + apikey = url_path_parts[2] + + if self.method == 'GET': + apikey_response = self.backend.get_apikey(apikey) + elif self.method == 'DELETE': + apikey_response = self.backend.delete_apikey(apikey) + return 200, {}, json.dumps(apikey_response) diff --git a/moto/apigateway/urls.py b/moto/apigateway/urls.py index 5637699e0..ca1f445a7 100644 --- a/moto/apigateway/urls.py +++ b/moto/apigateway/urls.py @@ -18,4 +18,6 @@ url_paths = { '{0}/restapis/(?P[^/]+)/resources/(?P[^/]+)/methods/(?P[^/]+)/responses/(?P\d+)$': APIGatewayResponse().resource_method_responses, '{0}/restapis/(?P[^/]+)/resources/(?P[^/]+)/methods/(?P[^/]+)/integration/?$': APIGatewayResponse().integrations, '{0}/restapis/(?P[^/]+)/resources/(?P[^/]+)/methods/(?P[^/]+)/integration/responses/(?P\d+)/?$': APIGatewayResponse().integration_responses, + '{0}/apikeys$': APIGatewayResponse().apikeys, + '{0}/apikeys/(?P[^/]+)': APIGatewayResponse().apikey_individual, } diff --git a/tests/test_apigateway/test_apigateway.py b/tests/test_apigateway/test_apigateway.py index 11230658b..9e2307bdd 100644 --- a/tests/test_apigateway/test_apigateway.py +++ b/tests/test_apigateway/test_apigateway.py @@ -1,8 +1,6 @@ from __future__ import unicode_literals -from datetime import datetime -from dateutil.tz import tzutc import boto3 from freezegun import freeze_time import requests @@ -965,3 +963,35 @@ def test_http_proxying_integration(): if not settings.TEST_SERVER_MODE: requests.get(deploy_url).content.should.equal(b"a fake response") + + +@mock_apigateway +def test_api_keys(): + region_name = 'us-west-2' + client = boto3.client('apigateway', region_name=region_name) + response = client.get_api_keys() + len(response['items']).should.equal(0) + + apikey_value = '12345' + apikey_name = 'TESTKEY1' + payload = {'value': apikey_value, 'name': apikey_name} + response = client.create_api_key(**payload) + apikey = client.get_api_key(apiKey=payload['value']) + apikey['name'].should.equal(apikey_name) + apikey['value'].should.equal(apikey_value) + + apikey_name = 'TESTKEY2' + payload = {'name': apikey_name, 'generateDistinctId': True} + response = client.create_api_key(**payload) + apikey = client.get_api_key(apiKey=response['value']) + apikey['name'].should.equal(apikey_name) + len(apikey['value']).should.equal(40) + apikey_value = apikey['value'] + + response = client.get_api_keys() + len(response['items']).should.equal(2) + + client.delete_api_key(apiKey=apikey_value) + + response = client.get_api_keys() + len(response['items']).should.equal(1)