Леонід Кузьмін “Сам собі паблішер. Від сайту ігрової...
Post on 05-Aug-2015
178 Views
Preview:
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
top related