SlideShare uma empresa Scribd logo
1 de 32
Becoming a Polyglot
Simple API Engines in 5 Languages
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Introduction
Kirsten Hunter
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Kirsten Hunter
@synedra
http://www.princesspolymath.com
The Challenge
Siloed Communities
Poor Understanding of
Language Differences
Fear of the Unknown
Exclusivity
Kirsten Hunter
@synedra
http://www.princesspolymath.com
The Solution
• Simple API Project
• Mongo Backend
• Single Page Application Front End
• Identically functioning API Engines in 5
Languages
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Fortune Cookie
Server
Engines use data from
mongo db
Each engine presents
full API capability
* GET
* PUT
* POST
* DELETE
Github / Docker
synedra/polyglot
c9.io
python image
clone github repo
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Single Page Application
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Mongo Setup
load quoteid.jsonStartup mongo
/etc/init.d/mongodb start
{
"content": "Boredom: the
desire for desires.",
"index": 1998,
"author": "Leo Tolstoy"
},
mongoimport --collection quotes --file quoteid.json --type json
jsonArray
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Schema
Modeling
RAML
OpenAPI
Kirsten Hunter
@synedra
http://www.princesspolymath.com
RAML 0.8
title: Fortune Cookie
version: V1
baseUri: http://www.fortunecookieserver.com/api/v1
/quotes:
displayName: Quotes
get:
description: Get a list of quotes
queryParameters:
random:
description: Retrieve a random quote
required: false
default: false
type: boolean
responses:
200:
body:
application/json:
example: |
[
{"content":"That which does not kill us makes us stronger.",
"author":"Sun Yi",
"id":1
}
]
Kirsten Hunter
@synedra
http://www.princesspolymath.com
RAML 0.8
title: Fortune Cookie
version: V1
baseUri: http://www.fortunecookieserver.com/api/v1
/quotes:
displayName: Quotes
get:
description: Get a list of quotes
queryParameters:
random:
description: Retrieve a random quote
required: false
default: false
type: boolean
responses:
200:
body:
application/json:
example: |
[
{"content":"That which does not kill us makes us stronger.",
"author":"Sun Yi",
"id":1
}
]
Kirsten Hunter
@synedra
http://www.princesspolymath.com
RAML 0.8
title: Fortune Cookie
version: V1
baseUri: http://www.fortunecookieserver.com/api/v1
/quotes:
displayName: Quotes
get:
description: Get a list of quotes
queryParameters:
random:
description: Retrieve a random quote
required: false
default: false
type: boolean
responses:
200:
body:
application/json:
example: |
[
{"content":"That which does not kill us makes us stronger.",
"author":"Sun Yi",
"id":1
}
]
Kirsten Hunter
@synedra
http://www.princesspolymath.com
{
"swagger": "2.0",
"info": {
"title": "Fortune Cookie API",
"description": "Random quote of the day",
"version": "1.0.0"
},
"host": "api.fortunecookieserver.com",
"schemes": [
"http"
],
"basePath": "/v1",
"produces": [
"application/json"
],
"paths": {
"/quotes": {
"get": {
"summary": "Quotes",
"description": "This is a quote server.n",
"tags": [
"Quotes"
],
"responses": {
"200": {
"description": "An array of products",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Quote"
}
}
},
Kirsten Hunter
@synedra
http://www.princesspolymath.com
{
"swagger": "2.0",
"info": {
"title": "Fortune Cookie API",
"description": "Random quote of the day",
"version": "1.0.0"
},
"host": "api.fortunecookieserver.com",
"schemes": [
"http"
],
"basePath": "/v1",
"produces": [
"application/json"
],
"paths": {
"/quotes": {
"get": {
"summary": "Quotes",
"description": "This is a quote server.n",
"tags": [
"Quotes"
],
"responses": {
"200": {
"description": "An array of products",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Quote"
}
}
},
Kirsten Hunter
@synedra
http://www.princesspolymath.com
{
"swagger": "2.0",
"info": {
"title": "Fortune Cookie API",
"description": "Random quote of the day",
"version": "1.0.0"
},
"host": "api.fortunecookieserver.com",
"schemes": [
"http"
],
"basePath": "/v1",
"produces": [
"application/json"
],
"paths": {
"/quotes": {
"get": {
"summary": "Quotes",
"description": "This is a quote server.n",
"tags": [
"Quotes"
],
"responses": {
"200": {
"description": "An array of products",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Quote"
}
}
},
Kirsten Hunter
@synedra
http://www.princesspolymath.com
PHP - Mongo Setup// Routes
$app->group('/api/quotes', function () {
// Setup DB connection
$mongo = new MongoClient('mongodb://localhost:27017');
$mongo->connect();
$db = $mongo->test;
$quotes = $db->selectCollection('quotes');
$this->get('', function (Request $request, Response $response, array $args) use ($quotes) {
$this->logger->info("Fetching 10 records…n");
$results = [];
foreach ($quotes->find([], ['_id' => 0])->sort(['index' => -1])->limit(10) as $quote) {
$results[] = $quote;
}
$response
->getBody()->write(json_encode($results, JSON_PRETTY_PRINT));
$newResponse = $response->withHeader(
'Content-type',
'application/json; charset=utf-8'
);
return $newResponse;
});
Kirsten Hunter
@synedra
http://www.princesspolymath.com
PHP - Route// Routes
$app->group('/api/quotes', function () {
// Setup DB connection
$mongo = new MongoClient('mongodb://localhost:27017');
$mongo->connect();
$db = $mongo->test;
$quotes = $db->selectCollection('quotes');
$this->get('', function (Request $request, Response $response, array $args) use ($quotes) {
$this->logger->info("Fetching 10 records…n");
$results = [];
foreach ($quotes->find([], ['_id' => 0])->sort(['index' => -1])->limit(10) as $quote) {
$results[] = $quote;
}
$response
->getBody()->write(json_encode($results, JSON_PRETTY_PRINT));
$newResponse = $response->withHeader(
'Content-type',
'application/json; charset=utf-8'
);
return $newResponse;
});
Kirsten Hunter
@synedra
http://www.princesspolymath.com
PHP - Static
$app->get('/', function(Request $request, Response $response, $args) {
return $response->getBody()->write('Hello World from PHP Slim');
});
$app->get('/demo', function(Request $request, Response $response, $args) {
$content = file_get_contents('../static/index.html');
return $response->getBody()->write($content);
});
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Perl - Mongo Setup
use Dancer;
use Dancer::Plugin::CRUD;
use MongoDB;
my $client = MongoDB->connect();
my $db = $client->get_database('test');
my $quotes = $db->get_collection('quotes');
my $json = JSON->new->allow_nonref;
set content_type => 'application/json';
get '/' => sub{
return {message => "Hello from Perl and Dancer"};
};
set public => path(dirname(__FILE__), '..', 'static');
get "/demo/?" => sub {
send_file '/index.html'
};
get '/api/quotes' => sub {
my $response = $quotes->find()->sort({'index' => -1})->limit(10);
my @results = ();
while(my $quote = $response->next) {
push (@results,
{"content" => $quote->{'content'},
"index" => $quote->{'index'},
"author" => $quote->{'author'}
}
);
}
if (! scalar (@results)) {
status 404;
return;
}
return @results;
};
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Perl - Static Files
use Dancer;
use Dancer::Plugin::CRUD;
use MongoDB;
my $client = MongoDB->connect();
my $db = $client->get_database('test');
my $quotes = $db->get_collection('quotes');
my $json = JSON->new->allow_nonref;
set content_type => 'application/json';
get '/' => sub{
return {message => "Hello from Perl and Dancer"};
};
set public => path(dirname(__FILE__), '..', 'static');
get "/demo/?" => sub {
send_file '/index.html'
};
get '/api/quotes' => sub {
my $response = $quotes->find()->sort({'index' => -1})->limit(10);
my @results = ();
while(my $quote = $response->next) {
push (@results,
{"content" => $quote->{'content'},
"index" => $quote->{'index'},
"author" => $quote->{'author'}
}
);
}
if (! scalar (@results)) {
status 404;
return;
}
return @results;
};
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Perl - Routes
get '/api/quotes' => sub {
my $response = $quotes->find()->sort({'index' => -1})->limit(10);
my @results = ();
while(my $quote = $response->next) {
push (@results,
{"content" => $quote->{'content'},
"index" => $quote->{'index'},
"author" => $quote->{'author'}
}
);
}
if (! scalar (@results)) {
status 404;
return;
}
return @results;
};
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Python - Mongo Setup
resp = Response(dumps(quotes, default=default),
mimetype='application/json')
return resp
def delete(self, quote_id):
print "Quote id is %s" % quote_id
try:
mongo.db.quotes.remove({
'index': int(quote_id)
})
except Exception as ve:
print ve
abort(400, str(ve))
return '', 204
def put(self, quote_id):
args = parser.parse_args()
if not (args['content'] or args['author']):
return 'Missing data', 400
existing_quote = mongo.db.quotes.find_one({"index": int(quote_id)})
args['content'] = args['content'] if args['content'] else existing_quote["content"]
args['author'] = args['author'] if args['author'] else existing_quote["author"]
try:
mongo.db.quotes.update({
'index': quote_id
},{
'$set': {
'content': args['content'],
'author': args['author']
}
}, upsert=False)
except Exception as ve:
print ve
abort(400, str(ve))
return 201
# TodoList
# shows a list of all todos, and lets you POST to add new tasks
class QuoteList(Resource):
def get(self):
quotes = mongo.db.quotes.find().sort("index", -1).limit(10)
resp = Response(dumps(quotes, default=default),
mimetype='application/json')
return resp
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Python - Static
return resp
…
@app.route('/')
def hello_world():
return 'Hello from Flask!'
@app.route('/demo')
def serve_page():
return send_from_directory(STATIC_ROOT, "index.html")
abort(400, str(ve))
return '', 204
def put(self, quote_id):
args = parser.parse_args()
if not (args['content'] or args['author']):
return 'Missing data', 400
existing_quote = mongo.db.quotes.find_one({"index": int(quote_id)})
args['content'] = args['content'] if args['content'] else existing_quote["content"]
args['author'] = args['author'] if args['author'] else existing_quote["author"]
try:
mongo.db.quotes.update({
'index': quote_id
},{
'$set': {
'content': args['content'],
'author': args['author']
}
}, upsert=False)
except Exception as ve:
print ve
abort(400, str(ve))
return 201
# TodoList
# shows a list of all todos, and lets you POST to add new tasks
class QuoteList(Resource):
def get(self):
quotes = mongo.db.quotes.find().sort("index", -1).limit(10)
resp = Response(dumps(quotes, default=default),
mimetype='application/json')
return resp
def post(self):
args = parser.parse_args()
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Python - Route
# shows a list of all quotes, and lets you POST to add new quotes
class QuoteList(Resource):
def get(self):
quotes = mongo.db.quotes.find().sort("index", -1).limit(10)
resp = Response(dumps(quotes, default=default),
mimetype='application/json')
return resp
def post(self):
args = parser.parse_args()
quotes = mongo.db.quotes.find().sort("index", -1).limit(1)
print quotes[0]
args["index"] = int(quotes[0]["index"]) + 1
print args
try:
mongo.db.quotes.insert(args)
except Error as ve:
abort(400, str(ve))
return 201
api.add_resource(QuoteList, '/api/quotes')
api.add_resource(Quote, '/api/quotes/<quote_id>')
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Ruby - Mongo Setup
end
get '/' do
content_type :html
"Hello World from Sinatra"
end
before do
content_type 'application/json'
end
namespace "/api" do
# list all
get '/quotes' do
Quote.all.desc(:index).limit(10).to_json
end
get '/quotes/random' do
newnumber = Quote.count
random_num = rand(newnumber)
quote = Quote.find_by(index: random_num.to_i)
return status 404 if quote.nil?
quote.to_json
end
# view one
get '/quotes/:index' do
quote = Quote.find_by(index: params[:index].to_i)
return status 404 if quote.nil?
quote.to_json
end
# create
post '/quotes' do
newnumber = Quote.count + 1
@json = JSON.parse(request.body.read)
quote = Quote.new(
content: @json['content'],
author: @json['author'],
index: newnumber)
quote.save
newnumber.to_json
end
# update
put '/quotes/:index' do
Kirsten Hunter
@synedra
http://www.princesspolymath.com
end
get '/' do
content_type :html
"Hello World from Sinatra"
end
before do
content_type 'application/json'
end
namespace "/api" do
# list all
get '/quotes' do
Quote.all.desc(:index).limit(10).to_json
end
get '/quotes/random' do
newnumber = Quote.count
random_num = rand(newnumber)
quote = Quote.find_by(index: random_num.to_i)
return status 404 if quote.nil?
quote.to_json
end
# view one
get '/quotes/:index' do
quote = Quote.find_by(index: params[:index].to_i)
return status 404 if quote.nil?
quote.to_json
end
# create
post '/quotes' do
newnumber = Quote.count + 1
@json = JSON.parse(request.body.read)
quote = Quote.new(
content: @json['content'],
author: @json['author'],
index: newnumber)
quote.save
newnumber.to_json
end
# update
put '/quotes/:index' do
Ruby - Static
Kirsten Hunter
@synedra
http://www.princesspolymath.com
namespace "/api" do
# list all
get '/quotes' do
Quote.all.desc(:index).limit(10).to_json
end
get '/quotes/random' do
newnumber = Quote.count
random_num = rand(newnumber)
quote = Quote.find_by(index: random_num.to_i)
return status 404 if quote.nil?
quote.to_json
end
# view one
get '/quotes/:index' do
quote = Quote.find_by(index: params[:index].to_i)
return status 404 if quote.nil?
quote.to_json
end
# create
post '/quotes' do
newnumber = Quote.count + 1
@json = JSON.parse(request.body.read)
quote = Quote.new(
content: @json['content'],
author: @json['author'],
index: newnumber)
quote.save
newnumber.to_json
end
# update
put '/quotes/:index' do
@json = JSON.parse(request.body.read)
quote = Quote.find_by(index: params[:index].to_i)
return status 404 if quote.nil?
quote.update(
content: @json['content'],
author: @json['author']
)
quote.save
params[:index].to_json
end
Ruby - Route
Kirsten Hunter
@synedra
http://www.princesspolymath.com
app.use('/api', router);
// REST API
router.route('/quotes/random')
.get(function(req, res, next) {
var random = Math.floor(Math.random() * quotecount);
Quote.findOne({"index":random},
function (err, result) {
if (err) {
console.log(err);
res.redirect('/quotes/random');
}
res.send(result);
})
});
router.route('/quotes')
.get(function(req, res, next) {
var result = Quote.find().sort({'index': -1}).limit(10);
result.exec(function(err, quotes) {
res.send(quotes);
});
})
.post(function(req, res, next) {
if(!req.body.hasOwnProperty('content')) {
res.statusCode = 400;
return res.send('Error 400: Post syntax incorrect.');
}
quotecount = quotecount+1;
var newQuote;
if (req.body.hasOwnProperty('author')) {
newQuote = new Quote({'content': req.body.content, 'author': req.body.author, 'index': quotecount});
} else {
newQuote = new Quote({'content': req.body.content, 'index':quotecount});
}
newQuote.save(function (err, newQuote) {
if (err) return console.error(err);
res.json(quotecount);
});;
});
router.route('/quotes/:index')
.get(function(req, res, next) {
Quote.findOne({"index":req.params.index},
function (err, result) {
res.send(result);
Node - Mongo Setup
Kirsten Hunter
@synedra
http://www.princesspolymath.com
if (err) {
console.log(err);
res.redirect('/quotes/random');
}
res.send(result);
})
});
router.route('/quotes')
.get(function(req, res, next) {
var result = Quote.find().sort({'index': -1}).limit(10);
result.exec(function(err, quotes) {
res.send(quotes);
});
})
.post(function(req, res, next) {
if(!req.body.hasOwnProperty('content')) {
res.statusCode = 400;
return res.send('Error 400: Post syntax incorrect.');
}
quotecount = quotecount+1;
var newQuote;
if (req.body.hasOwnProperty('author')) {
newQuote = new Quote({'content': req.body.content, 'author': req.body.author, 'index': quotecount});
} else {
newQuote = new Quote({'content': req.body.content, 'index':quotecount});
}
newQuote.save(function (err, newQuote) {
if (err) return console.error(err);
res.json(quotecount);
});;
});
router.route('/quotes/:index')
.get(function(req, res, next) {
Quote.findOne({"index":req.params.index},
function (err, result) {
res.send(result);
});
})
.put(function(req, res, next) {
if(!req.body.hasOwnProperty('content') && (!req.body.hasOwnProperty('author'))) {
res.statusCode = 400;
return res.send('Error 400: Post syntax incorrect.');
}
var query = {'index':req.params.index};
Node - Express Static
Kirsten Hunter
@synedra
http://www.princesspolymath.com
if (err) {
console.log(err);
res.redirect('/quotes/random');
}
res.send(result);
})
});
router.route('/quotes')
.get(function(req, res, next) {
var result = Quote.find().sort({'index': -1}).limit(10);
result.exec(function(err, quotes) {
res.send(quotes);
});
})
.post(function(req, res, next) {
if(!req.body.hasOwnProperty('content')) {
res.statusCode = 400;
return res.send('Error 400: Post syntax incorrect.');
}
quotecount = quotecount+1;
var newQuote;
if (req.body.hasOwnProperty('author')) {
newQuote = new Quote({'content': req.body.content, 'author': req.body.author, 'index': quotecount});
} else {
newQuote = new Quote({'content': req.body.content, 'index':quotecount});
}
newQuote.save(function (err, newQuote) {
if (err) return console.error(err);
res.json(quotecount);
});;
});
router.route('/quotes/:index')
.get(function(req, res, next) {
Quote.findOne({"index":req.params.index},
function (err, result) {
res.send(result);
});
})
.put(function(req, res, next) {
if(!req.body.hasOwnProperty('content') && (!req.body.hasOwnProperty('author'))) {
res.statusCode = 400;
return res.send('Error 400: Post syntax incorrect.');
}
var query = {'index':req.params.index};
Node - Express Routes
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Node - Hapi Static
server.route({
method : 'GET', path : '/demo/{path*}', handler : {
directory : {
path : '../static',
listing : false,
index : true
}}})});
server.route([
{
method: 'GET',
path: '/',
handler: function(request, reply) {
reply('Hello world from hapi');
}}]);
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Node - Hapi Routes
server.route([
{
method: 'GET',
path: '/api/quotes/random',
handler: function(request, reply) {
var random = Math.floor(Math.random() * quotecount);
Quote.findOne({"index":random},
function (err, result) {
reply(result);
})
}
},
Kirsten Hunter
@synedra
http://www.princesspolymath.com
Questions?
http://www.princesspolymath.com
Kirsten Hunter
@synedra
http://www.princesspolymath.com

Mais conteúdo relacionado

Destaque

Designing for developers
Designing for developersDesigning for developers
Designing for developers
Kirsten Hunter
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
Hugo Hamon
 

Destaque (20)

Designing irresistible APIs
Designing irresistible APIsDesigning irresistible APIs
Designing irresistible APIs
 
Becoming a Polyglot Programmer Through the Eyes of a Freelance Musician
Becoming a Polyglot Programmer Through the Eyes of a Freelance MusicianBecoming a Polyglot Programmer Through the Eyes of a Freelance Musician
Becoming a Polyglot Programmer Through the Eyes of a Freelance Musician
 
Polyglot
PolyglotPolyglot
Polyglot
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
Liberating your data
Liberating your dataLiberating your data
Liberating your data
 
Prototyping in the cloud
Prototyping in the cloudPrototyping in the cloud
Prototyping in the cloud
 
Liberating your data
Liberating your dataLiberating your data
Liberating your data
 
Designing for developers
Designing for developersDesigning for developers
Designing for developers
 
Api 101
Api 101Api 101
Api 101
 
Facebook appsincloud
Facebook appsincloudFacebook appsincloud
Facebook appsincloud
 
Symfony2 en pièces détachées
Symfony2 en pièces détachéesSymfony2 en pièces détachées
Symfony2 en pièces détachées
 
API 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat ConferenceAPI 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat Conference
 
API First
API FirstAPI First
API First
 
Quantifying fitness
Quantifying fitnessQuantifying fitness
Quantifying fitness
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
 
Monitor the quality of your Symfony projects
Monitor the quality of your Symfony projectsMonitor the quality of your Symfony projects
Monitor the quality of your Symfony projects
 
Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)
 

Mais de Kirsten Hunter

API 101 - Understanding APIs.
API 101 - Understanding APIs.API 101 - Understanding APIs.
API 101 - Understanding APIs.
Kirsten Hunter
 
Demystifying REST - SFRails meetup
Demystifying REST - SFRails meetupDemystifying REST - SFRails meetup
Demystifying REST - SFRails meetup
Kirsten Hunter
 

Mais de Kirsten Hunter (13)

Polyglot copy
Polyglot copyPolyglot copy
Polyglot copy
 
Quantifying your-fitness
Quantifying your-fitnessQuantifying your-fitness
Quantifying your-fitness
 
Designing irresistible apis
Designing irresistible apisDesigning irresistible apis
Designing irresistible apis
 
Designing irresistible apis
Designing irresistible apisDesigning irresistible apis
Designing irresistible apis
 
API 101 - Understanding APIs.
API 101 - Understanding APIs.API 101 - Understanding APIs.
API 101 - Understanding APIs.
 
Demystifying REST - SFRails meetup
Demystifying REST - SFRails meetupDemystifying REST - SFRails meetup
Demystifying REST - SFRails meetup
 
Rest schema design
Rest schema designRest schema design
Rest schema design
 
Successful developers
Successful developersSuccessful developers
Successful developers
 
Demystifying REST
Demystifying RESTDemystifying REST
Demystifying REST
 
PHP Architect Virtual Cloud summit
PHP Architect Virtual Cloud summitPHP Architect Virtual Cloud summit
PHP Architect Virtual Cloud summit
 
Social Marketing with LinkedIn
Social Marketing with LinkedInSocial Marketing with LinkedIn
Social Marketing with LinkedIn
 
LinkedIn Everywhere
LinkedIn EverywhereLinkedIn Everywhere
LinkedIn Everywhere
 
Creating Professional Applications with the LinkedIn API
Creating Professional Applications with the LinkedIn APICreating Professional Applications with the LinkedIn API
Creating Professional Applications with the LinkedIn API
 

Último

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 

Último (20)

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 

Polyglot

  • 1. Becoming a Polyglot Simple API Engines in 5 Languages Kirsten Hunter @synedra http://www.princesspolymath.com
  • 3. Kirsten Hunter @synedra http://www.princesspolymath.com The Challenge Siloed Communities Poor Understanding of Language Differences Fear of the Unknown Exclusivity
  • 4. Kirsten Hunter @synedra http://www.princesspolymath.com The Solution • Simple API Project • Mongo Backend • Single Page Application Front End • Identically functioning API Engines in 5 Languages
  • 5. Kirsten Hunter @synedra http://www.princesspolymath.com Fortune Cookie Server Engines use data from mongo db Each engine presents full API capability * GET * PUT * POST * DELETE Github / Docker synedra/polyglot c9.io python image clone github repo
  • 7. Kirsten Hunter @synedra http://www.princesspolymath.com Mongo Setup load quoteid.jsonStartup mongo /etc/init.d/mongodb start { "content": "Boredom: the desire for desires.", "index": 1998, "author": "Leo Tolstoy" }, mongoimport --collection quotes --file quoteid.json --type json jsonArray
  • 9. Kirsten Hunter @synedra http://www.princesspolymath.com RAML 0.8 title: Fortune Cookie version: V1 baseUri: http://www.fortunecookieserver.com/api/v1 /quotes: displayName: Quotes get: description: Get a list of quotes queryParameters: random: description: Retrieve a random quote required: false default: false type: boolean responses: 200: body: application/json: example: | [ {"content":"That which does not kill us makes us stronger.", "author":"Sun Yi", "id":1 } ]
  • 10. Kirsten Hunter @synedra http://www.princesspolymath.com RAML 0.8 title: Fortune Cookie version: V1 baseUri: http://www.fortunecookieserver.com/api/v1 /quotes: displayName: Quotes get: description: Get a list of quotes queryParameters: random: description: Retrieve a random quote required: false default: false type: boolean responses: 200: body: application/json: example: | [ {"content":"That which does not kill us makes us stronger.", "author":"Sun Yi", "id":1 } ]
  • 11. Kirsten Hunter @synedra http://www.princesspolymath.com RAML 0.8 title: Fortune Cookie version: V1 baseUri: http://www.fortunecookieserver.com/api/v1 /quotes: displayName: Quotes get: description: Get a list of quotes queryParameters: random: description: Retrieve a random quote required: false default: false type: boolean responses: 200: body: application/json: example: | [ {"content":"That which does not kill us makes us stronger.", "author":"Sun Yi", "id":1 } ]
  • 12. Kirsten Hunter @synedra http://www.princesspolymath.com { "swagger": "2.0", "info": { "title": "Fortune Cookie API", "description": "Random quote of the day", "version": "1.0.0" }, "host": "api.fortunecookieserver.com", "schemes": [ "http" ], "basePath": "/v1", "produces": [ "application/json" ], "paths": { "/quotes": { "get": { "summary": "Quotes", "description": "This is a quote server.n", "tags": [ "Quotes" ], "responses": { "200": { "description": "An array of products", "schema": { "type": "array", "items": { "$ref": "#/definitions/Quote" } } },
  • 13. Kirsten Hunter @synedra http://www.princesspolymath.com { "swagger": "2.0", "info": { "title": "Fortune Cookie API", "description": "Random quote of the day", "version": "1.0.0" }, "host": "api.fortunecookieserver.com", "schemes": [ "http" ], "basePath": "/v1", "produces": [ "application/json" ], "paths": { "/quotes": { "get": { "summary": "Quotes", "description": "This is a quote server.n", "tags": [ "Quotes" ], "responses": { "200": { "description": "An array of products", "schema": { "type": "array", "items": { "$ref": "#/definitions/Quote" } } },
  • 14. Kirsten Hunter @synedra http://www.princesspolymath.com { "swagger": "2.0", "info": { "title": "Fortune Cookie API", "description": "Random quote of the day", "version": "1.0.0" }, "host": "api.fortunecookieserver.com", "schemes": [ "http" ], "basePath": "/v1", "produces": [ "application/json" ], "paths": { "/quotes": { "get": { "summary": "Quotes", "description": "This is a quote server.n", "tags": [ "Quotes" ], "responses": { "200": { "description": "An array of products", "schema": { "type": "array", "items": { "$ref": "#/definitions/Quote" } } },
  • 15. Kirsten Hunter @synedra http://www.princesspolymath.com PHP - Mongo Setup// Routes $app->group('/api/quotes', function () { // Setup DB connection $mongo = new MongoClient('mongodb://localhost:27017'); $mongo->connect(); $db = $mongo->test; $quotes = $db->selectCollection('quotes'); $this->get('', function (Request $request, Response $response, array $args) use ($quotes) { $this->logger->info("Fetching 10 records…n"); $results = []; foreach ($quotes->find([], ['_id' => 0])->sort(['index' => -1])->limit(10) as $quote) { $results[] = $quote; } $response ->getBody()->write(json_encode($results, JSON_PRETTY_PRINT)); $newResponse = $response->withHeader( 'Content-type', 'application/json; charset=utf-8' ); return $newResponse; });
  • 16. Kirsten Hunter @synedra http://www.princesspolymath.com PHP - Route// Routes $app->group('/api/quotes', function () { // Setup DB connection $mongo = new MongoClient('mongodb://localhost:27017'); $mongo->connect(); $db = $mongo->test; $quotes = $db->selectCollection('quotes'); $this->get('', function (Request $request, Response $response, array $args) use ($quotes) { $this->logger->info("Fetching 10 records…n"); $results = []; foreach ($quotes->find([], ['_id' => 0])->sort(['index' => -1])->limit(10) as $quote) { $results[] = $quote; } $response ->getBody()->write(json_encode($results, JSON_PRETTY_PRINT)); $newResponse = $response->withHeader( 'Content-type', 'application/json; charset=utf-8' ); return $newResponse; });
  • 17. Kirsten Hunter @synedra http://www.princesspolymath.com PHP - Static $app->get('/', function(Request $request, Response $response, $args) { return $response->getBody()->write('Hello World from PHP Slim'); }); $app->get('/demo', function(Request $request, Response $response, $args) { $content = file_get_contents('../static/index.html'); return $response->getBody()->write($content); });
  • 18. Kirsten Hunter @synedra http://www.princesspolymath.com Perl - Mongo Setup use Dancer; use Dancer::Plugin::CRUD; use MongoDB; my $client = MongoDB->connect(); my $db = $client->get_database('test'); my $quotes = $db->get_collection('quotes'); my $json = JSON->new->allow_nonref; set content_type => 'application/json'; get '/' => sub{ return {message => "Hello from Perl and Dancer"}; }; set public => path(dirname(__FILE__), '..', 'static'); get "/demo/?" => sub { send_file '/index.html' }; get '/api/quotes' => sub { my $response = $quotes->find()->sort({'index' => -1})->limit(10); my @results = (); while(my $quote = $response->next) { push (@results, {"content" => $quote->{'content'}, "index" => $quote->{'index'}, "author" => $quote->{'author'} } ); } if (! scalar (@results)) { status 404; return; } return @results; };
  • 19. Kirsten Hunter @synedra http://www.princesspolymath.com Perl - Static Files use Dancer; use Dancer::Plugin::CRUD; use MongoDB; my $client = MongoDB->connect(); my $db = $client->get_database('test'); my $quotes = $db->get_collection('quotes'); my $json = JSON->new->allow_nonref; set content_type => 'application/json'; get '/' => sub{ return {message => "Hello from Perl and Dancer"}; }; set public => path(dirname(__FILE__), '..', 'static'); get "/demo/?" => sub { send_file '/index.html' }; get '/api/quotes' => sub { my $response = $quotes->find()->sort({'index' => -1})->limit(10); my @results = (); while(my $quote = $response->next) { push (@results, {"content" => $quote->{'content'}, "index" => $quote->{'index'}, "author" => $quote->{'author'} } ); } if (! scalar (@results)) { status 404; return; } return @results; };
  • 20. Kirsten Hunter @synedra http://www.princesspolymath.com Perl - Routes get '/api/quotes' => sub { my $response = $quotes->find()->sort({'index' => -1})->limit(10); my @results = (); while(my $quote = $response->next) { push (@results, {"content" => $quote->{'content'}, "index" => $quote->{'index'}, "author" => $quote->{'author'} } ); } if (! scalar (@results)) { status 404; return; } return @results; };
  • 21. Kirsten Hunter @synedra http://www.princesspolymath.com Python - Mongo Setup resp = Response(dumps(quotes, default=default), mimetype='application/json') return resp def delete(self, quote_id): print "Quote id is %s" % quote_id try: mongo.db.quotes.remove({ 'index': int(quote_id) }) except Exception as ve: print ve abort(400, str(ve)) return '', 204 def put(self, quote_id): args = parser.parse_args() if not (args['content'] or args['author']): return 'Missing data', 400 existing_quote = mongo.db.quotes.find_one({"index": int(quote_id)}) args['content'] = args['content'] if args['content'] else existing_quote["content"] args['author'] = args['author'] if args['author'] else existing_quote["author"] try: mongo.db.quotes.update({ 'index': quote_id },{ '$set': { 'content': args['content'], 'author': args['author'] } }, upsert=False) except Exception as ve: print ve abort(400, str(ve)) return 201 # TodoList # shows a list of all todos, and lets you POST to add new tasks class QuoteList(Resource): def get(self): quotes = mongo.db.quotes.find().sort("index", -1).limit(10) resp = Response(dumps(quotes, default=default), mimetype='application/json') return resp
  • 22. Kirsten Hunter @synedra http://www.princesspolymath.com Python - Static return resp … @app.route('/') def hello_world(): return 'Hello from Flask!' @app.route('/demo') def serve_page(): return send_from_directory(STATIC_ROOT, "index.html") abort(400, str(ve)) return '', 204 def put(self, quote_id): args = parser.parse_args() if not (args['content'] or args['author']): return 'Missing data', 400 existing_quote = mongo.db.quotes.find_one({"index": int(quote_id)}) args['content'] = args['content'] if args['content'] else existing_quote["content"] args['author'] = args['author'] if args['author'] else existing_quote["author"] try: mongo.db.quotes.update({ 'index': quote_id },{ '$set': { 'content': args['content'], 'author': args['author'] } }, upsert=False) except Exception as ve: print ve abort(400, str(ve)) return 201 # TodoList # shows a list of all todos, and lets you POST to add new tasks class QuoteList(Resource): def get(self): quotes = mongo.db.quotes.find().sort("index", -1).limit(10) resp = Response(dumps(quotes, default=default), mimetype='application/json') return resp def post(self): args = parser.parse_args()
  • 23. Kirsten Hunter @synedra http://www.princesspolymath.com Python - Route # shows a list of all quotes, and lets you POST to add new quotes class QuoteList(Resource): def get(self): quotes = mongo.db.quotes.find().sort("index", -1).limit(10) resp = Response(dumps(quotes, default=default), mimetype='application/json') return resp def post(self): args = parser.parse_args() quotes = mongo.db.quotes.find().sort("index", -1).limit(1) print quotes[0] args["index"] = int(quotes[0]["index"]) + 1 print args try: mongo.db.quotes.insert(args) except Error as ve: abort(400, str(ve)) return 201 api.add_resource(QuoteList, '/api/quotes') api.add_resource(Quote, '/api/quotes/<quote_id>')
  • 24. Kirsten Hunter @synedra http://www.princesspolymath.com Ruby - Mongo Setup end get '/' do content_type :html "Hello World from Sinatra" end before do content_type 'application/json' end namespace "/api" do # list all get '/quotes' do Quote.all.desc(:index).limit(10).to_json end get '/quotes/random' do newnumber = Quote.count random_num = rand(newnumber) quote = Quote.find_by(index: random_num.to_i) return status 404 if quote.nil? quote.to_json end # view one get '/quotes/:index' do quote = Quote.find_by(index: params[:index].to_i) return status 404 if quote.nil? quote.to_json end # create post '/quotes' do newnumber = Quote.count + 1 @json = JSON.parse(request.body.read) quote = Quote.new( content: @json['content'], author: @json['author'], index: newnumber) quote.save newnumber.to_json end # update put '/quotes/:index' do
  • 25. Kirsten Hunter @synedra http://www.princesspolymath.com end get '/' do content_type :html "Hello World from Sinatra" end before do content_type 'application/json' end namespace "/api" do # list all get '/quotes' do Quote.all.desc(:index).limit(10).to_json end get '/quotes/random' do newnumber = Quote.count random_num = rand(newnumber) quote = Quote.find_by(index: random_num.to_i) return status 404 if quote.nil? quote.to_json end # view one get '/quotes/:index' do quote = Quote.find_by(index: params[:index].to_i) return status 404 if quote.nil? quote.to_json end # create post '/quotes' do newnumber = Quote.count + 1 @json = JSON.parse(request.body.read) quote = Quote.new( content: @json['content'], author: @json['author'], index: newnumber) quote.save newnumber.to_json end # update put '/quotes/:index' do Ruby - Static
  • 26. Kirsten Hunter @synedra http://www.princesspolymath.com namespace "/api" do # list all get '/quotes' do Quote.all.desc(:index).limit(10).to_json end get '/quotes/random' do newnumber = Quote.count random_num = rand(newnumber) quote = Quote.find_by(index: random_num.to_i) return status 404 if quote.nil? quote.to_json end # view one get '/quotes/:index' do quote = Quote.find_by(index: params[:index].to_i) return status 404 if quote.nil? quote.to_json end # create post '/quotes' do newnumber = Quote.count + 1 @json = JSON.parse(request.body.read) quote = Quote.new( content: @json['content'], author: @json['author'], index: newnumber) quote.save newnumber.to_json end # update put '/quotes/:index' do @json = JSON.parse(request.body.read) quote = Quote.find_by(index: params[:index].to_i) return status 404 if quote.nil? quote.update( content: @json['content'], author: @json['author'] ) quote.save params[:index].to_json end Ruby - Route
  • 27. Kirsten Hunter @synedra http://www.princesspolymath.com app.use('/api', router); // REST API router.route('/quotes/random') .get(function(req, res, next) { var random = Math.floor(Math.random() * quotecount); Quote.findOne({"index":random}, function (err, result) { if (err) { console.log(err); res.redirect('/quotes/random'); } res.send(result); }) }); router.route('/quotes') .get(function(req, res, next) { var result = Quote.find().sort({'index': -1}).limit(10); result.exec(function(err, quotes) { res.send(quotes); }); }) .post(function(req, res, next) { if(!req.body.hasOwnProperty('content')) { res.statusCode = 400; return res.send('Error 400: Post syntax incorrect.'); } quotecount = quotecount+1; var newQuote; if (req.body.hasOwnProperty('author')) { newQuote = new Quote({'content': req.body.content, 'author': req.body.author, 'index': quotecount}); } else { newQuote = new Quote({'content': req.body.content, 'index':quotecount}); } newQuote.save(function (err, newQuote) { if (err) return console.error(err); res.json(quotecount); });; }); router.route('/quotes/:index') .get(function(req, res, next) { Quote.findOne({"index":req.params.index}, function (err, result) { res.send(result); Node - Mongo Setup
  • 28. Kirsten Hunter @synedra http://www.princesspolymath.com if (err) { console.log(err); res.redirect('/quotes/random'); } res.send(result); }) }); router.route('/quotes') .get(function(req, res, next) { var result = Quote.find().sort({'index': -1}).limit(10); result.exec(function(err, quotes) { res.send(quotes); }); }) .post(function(req, res, next) { if(!req.body.hasOwnProperty('content')) { res.statusCode = 400; return res.send('Error 400: Post syntax incorrect.'); } quotecount = quotecount+1; var newQuote; if (req.body.hasOwnProperty('author')) { newQuote = new Quote({'content': req.body.content, 'author': req.body.author, 'index': quotecount}); } else { newQuote = new Quote({'content': req.body.content, 'index':quotecount}); } newQuote.save(function (err, newQuote) { if (err) return console.error(err); res.json(quotecount); });; }); router.route('/quotes/:index') .get(function(req, res, next) { Quote.findOne({"index":req.params.index}, function (err, result) { res.send(result); }); }) .put(function(req, res, next) { if(!req.body.hasOwnProperty('content') && (!req.body.hasOwnProperty('author'))) { res.statusCode = 400; return res.send('Error 400: Post syntax incorrect.'); } var query = {'index':req.params.index}; Node - Express Static
  • 29. Kirsten Hunter @synedra http://www.princesspolymath.com if (err) { console.log(err); res.redirect('/quotes/random'); } res.send(result); }) }); router.route('/quotes') .get(function(req, res, next) { var result = Quote.find().sort({'index': -1}).limit(10); result.exec(function(err, quotes) { res.send(quotes); }); }) .post(function(req, res, next) { if(!req.body.hasOwnProperty('content')) { res.statusCode = 400; return res.send('Error 400: Post syntax incorrect.'); } quotecount = quotecount+1; var newQuote; if (req.body.hasOwnProperty('author')) { newQuote = new Quote({'content': req.body.content, 'author': req.body.author, 'index': quotecount}); } else { newQuote = new Quote({'content': req.body.content, 'index':quotecount}); } newQuote.save(function (err, newQuote) { if (err) return console.error(err); res.json(quotecount); });; }); router.route('/quotes/:index') .get(function(req, res, next) { Quote.findOne({"index":req.params.index}, function (err, result) { res.send(result); }); }) .put(function(req, res, next) { if(!req.body.hasOwnProperty('content') && (!req.body.hasOwnProperty('author'))) { res.statusCode = 400; return res.send('Error 400: Post syntax incorrect.'); } var query = {'index':req.params.index}; Node - Express Routes
  • 30. Kirsten Hunter @synedra http://www.princesspolymath.com Node - Hapi Static server.route({ method : 'GET', path : '/demo/{path*}', handler : { directory : { path : '../static', listing : false, index : true }}})}); server.route([ { method: 'GET', path: '/', handler: function(request, reply) { reply('Hello world from hapi'); }}]);
  • 31. Kirsten Hunter @synedra http://www.princesspolymath.com Node - Hapi Routes server.route([ { method: 'GET', path: '/api/quotes/random', handler: function(request, reply) { var random = Math.floor(Math.random() * quotecount); Quote.findOne({"index":random}, function (err, result) { reply(result); }) } },