Леонід Кузьмін “Сам собі паблішер. Від сайту ігрової...

Post on 05-Aug-2015

181 Views

Category:

Business

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Сам собі паблішер. Від саиту ігровоі студіі до універсального back-end проваидера і сервісу

публікаціі ігор.

Leonid Kuzminlead developer Eforb

EFORB GAMEBOX

REST and RESTful API RESTful API adhere to the REST architectural constraints.

REST is not a protocol, but architectural style

• Client-Server – determined by environment

REST Architectural Constraints applied to web services

REST and RESTful API

• Client-Server – determined by environment

• Stateless – data needed for authentication included in every request headers (e.g. Cookies)

REST Architectural Constraints applied to web services

REST and RESTful API

• Client-Server – determined by environment

• Stateless – data needed for authentication included in every request headers (e.g. Cookies)

• Cacheable – HTTP cache control headers

REST Architectural Constraints applied to web services

REST and RESTful API

• Client-Server – determined by environment

• Stateless – data needed for authentication included in every request headers (e.g. Cookies)

• Cacheable – HTTP cache control headers

• Layered system – reverse proxy server could be used

REST Architectural Constraints applied to web services

REST and RESTful API

• Client-Server – determined by environment

• Stateless – data needed for authentication included in every request headers (e.g. Cookies)

• Cacheable – HTTP cache control headers

• Layered system – reverse proxy server could be used

• Uniform interface

REST Architectural Constraints applied to web services

REST and RESTful API

• Client-Server – determined by environment

• Stateless – data needed for authentication included in every request headers (e.g. Cookies)

• Cacheable – HTTP cache control headers

• Layered system – reverse proxy server could be used

• Uniform interface

REST Architectural Constraints applied to web services

- Identification of resources – URI

REST and RESTful API

• Client-Server – determined by environment

• Stateless – data needed for authentication included in every request headers (e.g. Cookies)

• Cacheable – HTTP cache control headers

• Layered system – reverse proxy server could be used

• Uniform interface

REST Architectural Constraints applied to web services

- Identification of resources – URI

- Self-descriptive messages – HTTP headers: cache control headers, “Content-Type” header, “Accept” header

REST and RESTful API

• Client-Server – determined by environment

• Stateless – data needed for authentication included in every request headers (e.g. Cookies)

• Cacheable – HTTP cache control headers

• Layered system – reverse proxy server could be used

• Uniform interface

REST Architectural Constraints applied to web services

- Identification of resources – URI

- Self-descriptive messages – HTTP headers: cache control headers, “Content-Type” header, “Accept” header

- Standard HTTP methods: POST, GET, PUT, DELETE and HTTP Response codes

REST and RESTful API

• Client-Server – determined by environment

• Stateless – data needed for authentication included in every request headers (e.g. Cookies)

• Cacheable – HTTP cache control headers

• Layered system – reverse proxy server could be used

• Uniform interface

REST Architectural Constraints applied to web services

- Identification of resources – URI

- Self-descriptive messages – HTTP headers: cache control headers, “Content-Type” header, “Accept” header

- Standard HTTP methods: POST, GET, PUT, DELETE and HTTP Response codes

- Resource entities can be filtered by referencing resources properties values in URI REST and

RESTful API

This is not RESTfulPOST /createAccount

Request:

Cookie: ...

{name: Petro, email: president@gov.ua}

Response:

{name: Petro, email: president@gov.ua}

GET /getAllAccounts?name=Petro

Request:

Cookie: ...

Response:

[{name: Petro, email: president@gov.ua},

{name: admin, email: admin@gov.ua}]

GET /findAccounts?name=Petro

Request:

Cookie: ...

Response:

[{name: Petro, email: president@gov.ua}]

GET /getAccount?id=1

Request:

Cookie: ...

Response:

{name: Petro, email: president@gov.ua}

POST /updateAccount

Request:

Cookie: ...

{id: 1, name: PetroP, email: president@gov.ua}

Response:

{name: PetroP, email: president@gov.ua}

POST /deleteAccount

Request:

Cookie: ...

{id: 1}

Response codes

Success: 200 OK

Fail: 200 OK {error: …}

This is RESTful!

POST /accounts

Request:

Cookie: ...

Content-Type: application/json

Accept: application/json

{name: Petro, email: president@gov.ua}

Response:

Cache-Control : private, max-age=0, no-cache

Content-Type: application/json

{name: Petro, email: president@gov.ua}

GET /accounts/1

Request:

Cookie: ...

Accept: application/json

Response:

Cache-Control : private, max-age=0, no-cache

Content-Type: application/json

{name: Petro, email: president@gov.ua}

GET /accounts

Request:

Cookie: ...

Accept: application/json

Response:

Cache-Control : private, max-age=0, no-cache

Content-Type: application/json

[{name: Petro, email: president@gov.ua},

{name: admin, email: admin@gov.ua}]

GET /accounts?name=Petro

Request:

Cookie: ...

Accept: application/json

Response:

Cache-Control : private, max-age=0, no-cache

Content-Type: application/json

[{name: Petro, email: president@gov.ua}]

PUT /accounts/1

Request:

Cookie: ...

Accept: application/json

{name: PetroP, email: president@gov.ua}

Response:

Cache-Control : private, max-age=0, no-cache

Content-Type: application/json

{name: PetroP, email: president@gov.ua}

DELETE /accounts/1

Request:

Cookie: ...

Content-Type: application/json

Accept: application/json

Response codes

Success: 200 OK, 201 Created

Fail: 400 Bad Request, 404 Not Found, 403 Forbidden, 500 Internal Server Error

Calculated data in REST

Int sum (a, b)

{ return a + b; }

• GET /sum – collection of all integers' sums: [0, 1, 2, 3, ..., N, ...]

• GET /sum/N – collection of all sums of 2 and all integers: [2, 3, 4, ..., N, ...]

• GET/sum/N/M–N+M

• POST /account/1/leaderboard/2 {score: 50}

• GET /account/1/leaderboard/2 {score: 100}

• GET /leaderboard/2 [ { account_id: 1, score: 100, position: 2 },{ account_id: 2, score: 200, position: 1 }

Game Leaderboard [

{ account_id: 1, score: 50, game_id: 2 },

{ account_id: 1, score: 100, game_id: 2 },

{ account_id: 2, score: 150, game_id: 2 },

{ account_id: 2, score: 200, game_id: 2 }]

RESTful: Pros and Cons

PROS

• Simply

• Consistent

• Easy to debug

• Scalable

RESTful: Pros and Cons

PROS CONS

• Simply

• Consistent

• Easy to debug

• Scalable

• Strange

• Lack of support

• Stateless

• Not a protocol

What we got from REST

• Direct mapping of resources to DB entities (SQL tables, NoSQL documents collections): POST /accounts => INSERT INTO accounts

What we got from REST

• Direct mapping of resources to DB entities (SQL tables, NoSQL documents collections): POST /accounts => INSERT INTO accounts

• Same access policies for different authentication flows (Cookies authorization, HTTP basic authorization)

What we got from REST

• Direct mapping of resources to DB entities (SQL tables, NoSQL documents collections): POST /accounts => INSERT INTO accounts

• Same access policies for different authentication flows (Cookies authorization, HTTP basic authorization)

• URI aliases (/accounts/1 => / me, /account/1/gamedata =>/my/gamedata)

What we got from REST

• Direct mapping of resources to DB entities (SQL tables, NoSQL documents collections): POST /accounts => INSERT INTO accounts

• Same access policies for different authentication flows (Cookies authorization, HTTP basic authorization)

• URI aliases (/accounts/1 => / me, /account/1/gamedata =>/my/gamedata)

• Common design guidelines

What we got from REST

• Direct mapping of resources to DB entities (SQL tables, NoSQL documents collections): POST /accounts => INSERT INTO accounts

• Same access policies for different authentication flows (Cookies authorization, HTTP basic authorization)

• URI aliases (/accounts/1 => / me, /account/1/gamedata => / my/gamedata)

• Common design guidelines

• Same back-end for external and internal services

What we got from REST

• Direct mapping of resources to DB entities (SQL tables, NoSQL documents collections): POST /accounts => INSERT INTO accounts

• Same access policies for different authentication flows (Cookies authorization, HTTP basic authorization)

• URI aliases (/accounts/1 => / me, /account/1/gamedata => / my/gamedata)

• Common design guidelines

• Same back-end for external and internal services

• Common test flow

REST API Testing

Test Unit = HTTP Verb + URI + Request headers + [Request Body]

HTTP Verb

URL

Request headers + [Request Body]

Test steps

1. Start the Application

2. Prepare test data in storage if needed

3. Perform HTTP API query

4. Check response headers and body

5. Check affected piece of data retrieved from storage directly or even through the REST API

Storage API could be stubbed and spied, in this case storage API calls should be checked on step 5.

Our API Building Codex

1. Everything is a collection

Our API Building Codex

1. Everything is a collection

2. Every collection has CRUD (POST, GET, PUT, DELETE)

Our API Building Codex

1. Everything is a collection

2. Every collection has CRUD (POST, GET, PUT, DELETE)

3. Use HTTP response codes

Our API Building Codex

1. Everything is a collection

2. Every collection has CRUD (POST, GET, PUT, DELETE)

3. Use HTTP response codes

4. Filter and pagination through URI params

Our API Building Codex

1. Everything is a collection

2. Every collection has CRUD (POST, GET, PUT, DELETE)

3. Use HTTP response codes

4. Filter and pagination through URI params

5. API version in URI

Our API Building Codex

1. Everything is a collection

2. Every collection has CRUD (POST, GET, PUT, DELETE)

3. Use HTTP response codes

4. Filter and pagination through URI params

5. API version in URI

6. Communicate with developers

Our API Building Codex

1. Everything is a collection

2. Every collection has CRUD (POST, GET, PUT, DELETE)

3. Use HTTP response codes

4. Filter and pagination through URI params

5. API version in URI

6. Communicate with developers

7. Documentation in code and tests

Our API Building Codex

1. Everything is a collection

2. Every collection has CRUD (POST, GET, PUT, DELETE)

3. Use HTTP response codes

4. Filter and pagination through URI params

5. API version in URI

6. Communicate with developers

7. Documentation in code and tests

8. No exceptions

Our API Building Codex

1. Everything is a collection

2. Every collection has CRUD (POST, GET, PUT, DELETE)

3. Use HTTP response codes

4. Filter and pagination through URI params

5. API version in URI

6. Communicate with developers

7. Documentation in code and tests

8. No exceptions

9. No exceptions for “No exceptions”

How games are published

Traditional Way Our Way

• Sign contract

• Satisfy publisher requirements

• Deploy game somewhere and providelink to publisher or send game archivedirectly

• Receive profit according to contract

• Register, fill billing info

• Fill game description fields, upload game archive through API

• Game appears in available gameslist for clients

• Start earning from ads and transactions

Our publishing way vs traditional way

Increased time between complete game and

actual publishing

Almost immediate game publishing

You need to implement and maintain back-end

for your games

Back-end services included

You need to implement monetization (ads or transactions)

Ads are served by our service, payment system

could be integrated with API. You receive profit

share.

Payment reports are often poor Full reports from ad providers and payment

systems

You need to maintain your own deploy cycle We have sandbox mode where you can view

your game before actual publishing.

Deployment API can be

Traditional Way Our Way

Embedding to third-party WEB resources

• IFrame

• Construct application on the fly on page with JS

• Subdomain with third-party wrapper

Embedding: IFrame

PROS

• Easy and obvious

• No cross-domain requests

• Client can control own page view

• Client can control own page view

• No conflicts with client's JS and CSS

Embedding: IFrame

PROS CONS

• Easy and obvious

• No cross-domain requests

• Client can control own page view

• Client can control own page view

• No conflicts with client's JS and CSS

• Client should be explicitlyidentified in each AJAX request

• Client can't customizeour application view

• Third-party cookiesbrowser policies

• No direct links to ourapplication's subpages

• Increased page construction time

Embedding: Subdomain

PROS

• No third-party cookies

• Client identified by domain

• No cross-domain requests

• Direct links to our applicationsubpages

• Less page construction time

• No conflicts with client's JS and CSS

Embedding: Subdomain

PROS CONS

• No third-party cookies

• Client identified by domain

• No cross-domain requests

• Direct links to our applicationsubpages

• Less page construction time

• No conflicts with client's JS and CSS

• Server configuration on theside of Client

• Client can't customize application view by own CSS or JS

• Client can't customize own views in wrapper

Embedding: Construct on the fly with JS

PROS

• No third-party cookies

• Client identified by domain

• No cross-domain requests

• Client can customize our application view

• Client can control own page

• Direct links to our applicationsubpages

Embedding: Construct on the fly with JS

PROS CONS

• No third-party cookies

• Client identified by domain

• No cross-domain requests

• Client can customize our application view

• Client can control own page

• Direct links to our applicationsubpages

• Increased page construction time

• Restricting customization of our application by Client'sCSS

• Isolating our application from client's JS

Construct on the fly solutions• Increased page construction time – pre-

rendered HTML

• Restricting customization of our application's CSS – random dynamic prefix for CSS

CSSclient.css.tpl: .{{placeholder}}_class {color: red;}GET /client.css .SOME_RANDOM_VALUE_class {color: red;}

JSapp.js.tpl: function App (cssPrefix) {var container = document.createElement('div');container.className = cssPrefix + '_class';}new App({{placeholder}});GET app.js…new App(‘SOME_RANDOM_VALUE’);

• Isolating our application from client's JS – wrap all code in closure, do not touch existing objects (internal browser objects, DOM objects etc.)

(function () {//all application code here})();

var container = document.createElement('div');

container.remove = function () {…}; //wrong

function remove (element) {…} //right

Our technologies and tools

• Back-end

• Front-end

- Node.js (Sails.js, pm2, Grunt)

- PostgreSQL

- HTML 5, CSS3

- Require.js

- Google Closure Compiler + Almond.js for production build

Leonid Kuzminlndkuzmin@gmail.comeforbgames.com

Thank you!

top related