class: center, middle, blue # Dan Schlosser ## .subtitle[Internship Summary | Venmo Summer 2014] --- class: center, middle, blue # IN .flash[MARKDOWN] --- # Large Charge Amounts - My first pull request! - All charges for greater than $99,999,999.99 raise this message --- # Large Charge Amounts - My first pull request! - All charges for greater than $99,999,999.99 raise this message ![](img/bill-gates.gif) --- # A `required_scope` decorator Old: ```python def get(self, resource_id): """Returns a single user transaction. Defaults to most recent. """ * self.check_scope(Token.CAN_ACCESS_PROFILE) payment_id = sanitize(str, resource_id) # ... ``` New: ```python *@required_scope(Token.CAN_ACCESS_PROFILE) def get(self, resource_id): """Returns a single user transaction. Defaults to most recent. """ payment_id = sanitize(str, resource_id) # ... ``` --- # Decorators ```python def required_scope(*required_scopes): ``` --- # Decorators ```python def required_scope(*required_scopes): return decorator ``` --- # Decorators ```python def required_scope(*required_scopes): def decorator(func): return decorator ``` --- # Decorators ```python def required_scope(*required_scopes): def decorator(func): return has_required_scopes return decorator ``` --- # Decorators ```python def required_scope(*required_scopes): def decorator(func): def has_required_scopes(request_handler, *args, **kwargs): return has_required_scopes return decorator ``` --- # Decorators ```python def required_scope(*required_scopes): def decorator(func): def has_required_scopes(request_handler, *args, **kwargs): return func(request_handler, *args, **kwargs) return has_required_scopes return decorator ``` --- # Decorators ```python def required_scope(*required_scopes): def decorator(func): @wraps(func) def has_required_scopes(request_handler, *args, **kwargs): return func(request_handler, *args, **kwargs) return has_required_scopes return decorator ``` --- # Decorators ```python def required_scope(*required_scopes): def decorator(func): @wraps(func) def has_required_scopes(request_handler, *args, **kwargs): # Check required_scopes here return func(request_handler, *args, **kwargs) return has_required_scopes return decorator ``` --- class: center, middle, blue # Lesson: ## Decorators are fun --- # Managing OAuth Apps from the Developer Portal --- # Managing OAuth Apps from the Developer Portal - Create, edit, and delete OAuth apps. --- # Managing OAuth Apps from the Developer Portal - Create, edit, and delete OAuth apps. - The pipeline: --- # Managing OAuth Apps from the Developer Portal - Create, edit, and delete OAuth apps. - The pipeline: 1. Port functionality from the internal API to the developer API --- # Managing OAuth Apps from the Developer Portal - Create, edit, and delete OAuth apps. - The pipeline: 1. Port functionality from the internal API to the developer API 2. Call those endpoints from the Developer Portal --- # Managing OAuth Apps from the Developer Portal - Create, edit, and delete OAuth apps. - The pipeline: 1. Port functionality from the internal API to the developer API 2. Call those endpoints from the Developer Portal 3. Wireframe out HTML for the new interface (incomplete) --- # Managing OAuth Apps from the Developer Portal - Create, edit, and delete OAuth apps. - The pipeline: 1. Port functionality from the internal API to the developer API 2. Call those endpoints from the Developer Portal 3. Wireframe out HTML for the new interface (incomplete) - `venmo_api.py`: A ~100 line interface for the developer API --- # `VenmoError`: A lightweight, simplified `ApiMessage` for the Developer Portal --- # `VenmoError`: A lightweight, simplified `ApiMessage` for the Developer Portal - Moved from 16 methods to 4 (`__init__`, `_form_error_message`, `dict`, `__str__`) --- # `VenmoError`: A lightweight, simplified `ApiMessage` for the Developer Portal - Moved from 16 methods to 4 (`__init__`, `_form_error_message`, `dict`, `__str__`) - Associate subclasses directly with an HTTP status code --- # `VenmoError`: A lightweight, simplified `ApiMessage` for the Developer Portal - Moved from 16 methods to 4 (`__init__`, `_form_error_message`, `dict`, `__str__`) - Associate subclasses directly with an HTTP status code - Only one error message version --- # `VenmoError`: A lightweight, simplified `ApiMessage` for the Developer Portal - Moved from 16 methods to 4 (`__init__`, `_form_error_message`, `dict`, `__str__`) - Associate subclasses directly with an HTTP status code - Only one error message version - All the same flexibility and extensibility --- # `ApiMessage` ```python try: json_data = response.json() except JSONDecodeError: raise ApiMessage.APPS_API_RETURNED_INVALID_JSON(http_status_code=400, subs=(response.url, response.text)) ``` --- # `ApiMessage` ```python try: json_data = response.json() except JSONDecodeError: raise ApiMessage.APPS_API_RETURNED_INVALID_JSON(http_status_code=400, subs=(response.url, response.text)) ``` # `VenmoError` ```python try: json_data = response.json() except JSONDecodeError: raise VenmoError.APPS_API_RETURNED_INVALID_JSON(response.url, response.text) ``` --- ```python HTTP_OK = 200 HTTP_INTERNAL_SERVER_ERROR = 500 class VenmoError(Exception): errors = { 'SUCCESS': (1,'Successful.', HTTP_OK), 'APPS_API_RETURNED_INVALID_JSON': \ (751, 'The Venmo API route \'%s\' returned invalid JSON data. Got %s', HTTP_INTERNAL_SERVER_ERROR), # ... } def __init__(self, *subs): self.subs = subs self.error_type = self.__class__.__name__ error_resource = VenmoError.errors[self.error_type] self.error_code = error_resource[0] self.error_message = self._form_error_message(error_resource[1], subs) self.http_status_code = error_resource[2] def _form_error_message(self, message, subs): if self.subs: message = message % subs return re.sub(r'\%s', '', message) def dict(self): # ... def __str__(self): # ... for etype in VenmoError.errors: # add subclass errors to VenmoError setattr(VenmoError, etype, classobj(etype, (VenmoError,), {})) ``` --- # Blocking with ![Katie](https://s3-us-west-2.amazonaws.com/slack-files2/avatars/2014-04-15/2302527863_192.jpg) **#hackweek** --- # Blocking with ![Katie](https://s3-us-west-2.amazonaws.com/slack-files2/avatars/2014-04-15/2302527863_192.jpg) **#hackweek** - Wrote the front end for the feature --- # Blocking with ![Katie](https://s3-us-west-2.amazonaws.com/slack-files2/avatars/2014-04-15/2302527863_192.jpg) **#hackweek** - Wrote the front end for the feature - iOS and Shabu! --- # Blocking with ![Katie](https://s3-us-west-2.amazonaws.com/slack-files2/avatars/2014-04-15/2302527863_192.jpg) **#hackweek** - Wrote the front end for the feature - iOS and Shabu! - We won! (and brought chocolate to the masses) --- # Blocking with ![Katie](https://s3-us-west-2.amazonaws.com/slack-files2/avatars/2014-04-15/2302527863_192.jpg) **#hackweek** - Wrote the front end for the feature - iOS and Shabu! - We won! (and brought chocolate to the masses) .med[ ![chocolate](img/chocolate.jpg) ] --- # Managing Webhooks from the Developer Portal --- # Managing Webhooks from the Developer Portal - Create, edit, and delete Webhooks. --- # Managing Webhooks from the Developer Portal - Create, edit, and delete Webhooks. - Wrote the entire pipline: --- # Managing Webhooks from the Developer Portal - Create, edit, and delete Webhooks. - Wrote the entire pipline: - SQL Tables --- # Managing Webhooks from the Developer Portal - Create, edit, and delete Webhooks. - Wrote the entire pipline: - SQL Tables - Django Models --- # Managing Webhooks from the Developer Portal - Create, edit, and delete Webhooks. - Wrote the entire pipline: - SQL Tables - Django Models - Developer API endpoints --- # Managing Webhooks from the Developer Portal - Create, edit, and delete Webhooks. - Wrote the entire pipline: - SQL Tables - Django Models - Developer API endpoints - Flask endpoints --- # Managing Webhooks from the Developer Portal - Create, edit, and delete Webhooks. - Wrote the entire pipline: - SQL Tables - Django Models - Developer API endpoints - Flask endpoints - Basic HTML wireframe --- # Managing Webhooks from the Developer Portal - Create, edit, and delete Webhooks. - Wrote the entire pipline: - SQL Tables - Django Models - Developer API endpoints - Flask endpoints - Basic HTML wireframe - Webhook triggering isn't implmented yet. --- # Pagination and Filters with ![Razzi](https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-xap1/t1.0-9/10409039_10152932944592576_6961381094530204571_n.jpg) --- # Pagination and Filters with ![Razzi](https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-xap1/t1.0-9/10409039_10152932944592576_6961381094530204571_n.jpg) - Centralized --- # Pagination and Filters with ![Razzi](https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-xap1/t1.0-9/10409039_10152932944592576_6961381094530204571_n.jpg) - Centralized - External IDs > timestamps --- # Pagination and Filters with ![Razzi](https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-xap1/t1.0-9/10409039_10152932944592576_6961381094530204571_n.jpg) - Centralized - External IDs > timestamps - Simple API for the endpoints: --- # Pagination and Filters with ![Razzi](https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-xap1/t1.0-9/10409039_10152932944592576_6961381094530204571_n.jpg) - Centralized - External IDs > timestamps - Simple API for the endpoints: ``` python pagination = PaginationBuilder.build_pagination(endpoint_url, story_resources_with_paging_check, limit, before_id=before_id, after_id=after_id) story_resources = pagination.trim_resources(story_resources_with_paging_check) ``` --- # Pagination and Filters with ![Razzi](https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-xap1/t1.0-9/10409039_10152932944592576_6961381094530204571_n.jpg) - Centralized - External IDs > timestamps - Simple API for the endpoints: ``` python pagination = PaginationBuilder.build_pagination(endpoint_url, story_resources_with_paging_check, limit, before_id=before_id, after_id=after_id) story_resources = pagination.trim_resources(story_resources_with_paging_check) ``` - Filter payments by action: --- # Pagination and Filters with ![Razzi](https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-xap1/t1.0-9/10409039_10152932944592576_6961381094530204571_n.jpg) - Centralized - External IDs > timestamps - Simple API for the endpoints: ``` python pagination = PaginationBuilder.build_pagination(endpoint_url, story_resources_with_paging_check, limit, before_id=before_id, after_id=after_id) story_resources = pagination.trim_resources(story_resources_with_paging_check) ``` - Filter payments by action: ```http GET /v1/payments?action=pay ``` --- # Cross-Origin Resource Sharing (CORS) --- # Cross-Origin Resource Sharing (CORS) - JavaScript developers deserve to make money move with AJAX --- # Cross-Origin Resource Sharing (CORS) - JavaScript developers deserve to make money move with AJAX - JavaScript is dangerous: --- # Cross-Origin Resource Sharing (CORS) - JavaScript developers deserve to make money move with AJAX - JavaScript is dangerous: ```html
``` --- # Cross-Origin Resource Sharing (CORS) - JavaScript developers deserve to make money move with AJAX - JavaScript is dangerous: ```html
``` - Wrote a blog post! --- class: center, middle, blue # 5 codebases ## .subtitle[ Platform, Dev Portal, Shabu, iOS, puppet-venmo-platform] --- class: center, middle, blue # 4 languages ## .subtitle[Python, Javascipt, HTML, Objective-C] --- class: center, middle, blue # 3 months ## .subtitle[June, July, August] --- class: center, middle, blue # 2 mentors / managers # ![cody](https://venmopics.appspot.com/u/v4/l/6ecc7b37-5c4a-49df-b91e-3552f02dc397), ![matt](https://secure.gravatar.com/avatar/1e2ed66a1b6f3ef336ba157869c62dfc.jpg?s=192&d=https%3A%2F%2Fslack.global.ssl.fastly.net%2F8390%2Fimg%2Favatars%2Fava_0019.png') --- class: center, middle, blue # 1 .flash[ AWESOME SUMMER] --- class: center, middle, blue # Thanks! ## .subtitle[dan@danrs.ch | ![venmo.com](img/venmo_logo_white.png).com/drs | s.danrs.ch/venmo]