Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Polyglot

As an API evangelist, I’m frequently put in a position where I need to provide sample code for my client developers, the folks who consume the API I’m charged with evangelizing. Our sample code is mostly in python at this point, because it’s the easiest language to understand if you don’t know python (if that makes any sense). These samples are really simple, demonstrating how to use the signing library for the language and then make a few HTTP calls to the actual APIs. However, I’ve run into several cases where customers are simply unwilling or unable to look at a “foreign” programming language to suss out what’s happening.

I am a firm believer that any programmer can read another programming language and understand what the underlying logic is, especially for fairly simple examples. The polyglot repository shows the same functionality (a very simple API engine) in 5 different languages. I’m hoping that providing this kind of apples to apples comparison will make it easier for developers to feel comfortable and confident looking at code in different languages. This is great for your career, for lowering your frustration level, and for just generally increasing your ability to code creatively and efficiently.

If you are on a platform which doesn’t appreciate interpreted languages, you can use the Docker Image (fastest way to get started). The new native clients for docker in Mac and Windows are fantastic and I highly recommend them. Just start up the docker engine and grab the repository with:

docker run -i -t -p 8080:8080 synedra/polyglot

  • Inicia sesión para ver los comentarios

Polyglot

  1. 1. Becoming a Polyglot Simple API Engines in 5 Languages Kirsten Hunter @synedra http://www.princesspolymath.com
  2. 2. Kirsten Hunter @synedra http://www.princesspolymath.com Introduction Kirsten Hunter Kirsten Hunter @synedra http://www.princesspolymath.com
  3. 3. Kirsten Hunter @synedra http://www.princesspolymath.com The Challenge Siloed Communities Poor Understanding of Language Differences Fear of the Unknown Exclusivity
  4. 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. 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
  6. 6. Kirsten Hunter @synedra http://www.princesspolymath.com Single Page Application
  7. 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
  8. 8. Kirsten Hunter @synedra http://www.princesspolymath.com Schema Modeling RAML OpenAPI
  9. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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); }) } },
  32. 32. Kirsten Hunter @synedra http://www.princesspolymath.com Questions? http://www.princesspolymath.com Kirsten Hunter @synedra http://www.princesspolymath.com

×