google cloud endpointsによる api構築

81
C-LIS CO., LTD.

Upload: keiji-ariyama

Post on 24-May-2015

4.547 views

Category:

Technology


1 download

DESCRIPTION

2014年2月15日、Osaka Innovation Hubで開催され「Innovation EGG 第二回」で発表した資料です。

TRANSCRIPT

  • 1. C-LIS CO., LTD.

2. C-LIS CO., LTD.Google Cloud EndpointsAPI 3. Who am I? AndroidAndroid 4. JSON JSON 5. API etc 6. JavaScript 7. API 8. API 9. 10. Google Cloud Endpoints 11. Google Cloud EndpointsAppEngine 12. 13. Google App Engine Java SDK (1.7.5 or newer) Java 7 Apache MavenYou need to be familiar with development using Google App Engine and the Java runtime. 14. Create your backend API project (using Maven to do this is the easiest method), then write your API backend code. Annotate your API backend code, so classes and client libraries can be generated from it. (Alternatively, use the Google Plugin for Eclipse, which can annotate for you.) Generate the client library using Maven, or alternatively, the endpoints.sh command line tool. (Another alternative is to use the Google Plugin for Eclipse to generate the client library.) Write your client app, using the client library when making calls to the API backend. 15. 16. 17. API 18. API insert list nyaaby 19. AppEngineURL 20. 34.706781 135.494632 21. 34.706781 135.494632 xn0m7q008t18 22. xn0m7q008t18 23. xn0m7q008t18 24. xn0m7q008t18 25. Geohash http://www.tom-carden.co.uk/p5/geohashing/applet/Geohash.java 26. 27. AppEngine $ cd coconeco $ mvn archetype:generateChoose a number or apply filter, com.google.appengine.archetypes:skeleton-archetype!Choose com.google.appengine.archetypes:skeleton-archetype version: 2: 1.7.5!groupId: io.keiji.coconeco!artifactId: coconeco!version:!padkage: 28. appengine-web.xml coconeco${appengine.app.version}true!coconeco/src/main/java/webapp/WEB-INF/appengine-web.xml 29. pom.xml ! ! ! !!! !! !4.0.0war1.0-SNAPSHOTio.keiji.coconecococoneco11.7.5UTF-8com.google.appengineappengine-api-1.0-sdk${appengine.target.version}javax.servletservlet-api2.5providedjstljstl1.2com.google.appengineappengine-testing${appengine.target.version}testcom.google.appengineappengine-api-stubs${appengine.target.version}testorg.apache.maven.plugins2.5.1maven-compiler-plugin1.61.6org.apache.maven.pluginsmaven-war-plugin2.3true${basedir}/src/main/webapp/WEB-INFtrueWEB-INFcom.google.appengineappengine-maven-plugin${appengine.target.version}coconeco/pom.xml ! ! !4.0.0war1.0-SNAPSHOTio.keiji.coconecococoneco11.8.9 appengine.target.version> UTF-8 project.build.sourceEncoding> ! 30. endpoints com.google.appengineappengine-api-1.0-sdk${appengine.target.version} com.google.appengineappengine-endpoints${appengine.target.version}javax.injectjavax.inject1com.google.appengineappengine-testing${appengine.target.version}test coconeco/pom.xml 31. org.apache.maven.pluginsmaven-war-plugin2.3${project.build.directory}/generated-sources/ appengine-endpoints/WEB-INF/web.xml${project.build.directory}/ generated-sources/appengine-endpointsWEB-INF/*.discoveryWEB-INF/*.apicom.google.appengineappengine-maven-plugin${appengine.target.version}falseendpoints_get_discovery_doccoconeco/pom.xml 32. $ mvn installJDK 7 Unsupported major.minor version 51.0 http://www.coderanch.com/t/624933/tools/Maven-dependency-mystery-Google-App 33. 34. package io.keiji.coconeco;!public class Entry { public Double latitude; public Double longitude; public String geoHash; public String url; public String description;! ! ! ! ! ! ! ! ! !public Entry() { } public Entry(String url) { this.url = url; } public Double getLatitude() { return latitude; } public Double getLongitude() { return longitude; } public String getGeoHash() { return geoHash; } public void setLocation(Double lat, Double lon) { this.latitude = lat; this.longitude = lon; this.geoHash = Geohash.encode(lat, lon); } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; };}coconeco/src/main/java/io/keiji/coconeco/Entry.java 35. package io.keiji.coconeco;! import java.util.ArrayList; !public class EntryList { public static ArrayList entries = new ArrayList();!static { entries.add( new Entry("http://i.gzn.jp/img/2009/03/13/swimming_cat/ swimming_cat.jpg")); entries.add( new Entry("http://upload.wikimedia.org/wikipedia/ja/ 1/16/%E6%97%A5%E6%9C%AC%E7%8C%AB_2008-4.jpg")); }!public Entry getEntryList(Integer id) { return entries.get(id); }}coconeco/src/main/java/io/keiji/coconeco/EntryList.java 36. package io.keiji.coconeco;! import java.util.ArrayList; ! import javax.inject.Named; ! import com.google.api.server.spi.config.Api; !@Api(name = "coconeco", version = "v1") public class EntryList { public static ArrayList entries = new ArrayList();!static { entries.add( new Entry("http://i.gzn.jp/img/2009/03/13/swimming_cat/ swimming_cat.jpg")); entries.add( new Entry("http://upload.wikimedia.org/wikipedia/ja/ 1/16/%E6%97%A5%E6%9C%AC%E7%8C%AB_2008-4.jpg")); }!public Entry getEntryList(@Named("id") Integer id) { return entries.get(id); }}coconeco/src/main/java/io/keiji/coconeco/EntryList.java 37. package io.keiji.coconeco;!// // // // // // // //http://www.tom-carden.co.uk/p5/geohashing/applet/Geohash.java Geohash.java Geohash library for Java ported from David Troy's Geohash library for Javascript - http://github.com/davetroy/geohash-js/tree/master (c) 2008 David Troy (c) 2008 Tom Carden Distributed under the MIT License! public class Geohash { ! coconeco/src/main/java/io/keiji/coconeco/Geohash.java 38. $ mvn appengine:devserver!![INFO] INFO: Started [email protected]:8080 [INFO] Feb 14, 2014 9:15:02 PM com.google.appengine.tools.development.JettyContainerService startHotDeployScanner [INFO] INFO: Full scan of the web app in place every 5s. [INFO] Feb 14, 2014 9:15:02 PM com.google.appengine.tools.development.AbstractModule startup [INFO] INFO: Module instance default is running at http://localhost:8080/ [INFO] Feb 14, 2014 9:15:02 PM com.google.appengine.tools.development.AbstractModule startup [INFO] INFO: The admin console is running at http://localhost:8080/_ah/admin [INFO] Feb 14, 2014 9:15:02 PM com.google.appengine.tools.development.DevAppServerImpl doStart [INFO] INFO: Dev App Server is now running 39. http://localhost:8080/_ah/api/explorer 40. http://localhost:8080/_ah/api/explorer 41. localhost127.0.0.1MacOS X Marverics 42. http://stackoverow.com/questions/20345132/127-0-0-1-is-working-but-localhost-not-working 43. https://developers.google.com/appengine/docs/java/tools/maven?hl=ja 44. pom.xml com.google.appengineappengine-maven-plugin${appengine.target.version}false0.0.0.0 8888endpoints_get_discovery_doccoconeco/pom.xml 45. http://localhost:8888/_ah/api/explorer 46. Discovery Based API 47. Google Cloud EndpointsAppEngineDiscovery Based API 48. package io.keiji.coconeco;! import java.util.ArrayList; ! import javax.inject.Named; !import com.google.api.server.spi.config.Api; import com.google.api.server.spi.config.ApiMethod;!@Api(name = "coconeco", version = "v1") public class EntryList { public static ArrayList entries = new ArrayList();!static { entries.add(new Entry("http://i.gzn.jp/img/2009/03/13/swimming_cat/ swimming_cat.jpg")); entries.add(new Entry("http://upload.wikimedia.org/wikipedia/ja/ 1/16/%E6%97%A5%E6%9C%AC%E7%8C%AB_2008-4.jpg")); }! ! !public ArrayList getEntryList() { return entries; } @ApiMethod(name = "get", httpMethod = "get") public Entry getEntry(@Named("id") Integer id) { return entries.get(id); }}coconeco/src/main/java/io/keiji/coconeco/EntryList.java 49. package io.keiji.coconeco;! import java.util.ArrayList; ! import javax.inject.Named; !import com.google.api.server.spi.config.Api; import com.google.api.server.spi.config.ApiMethod;!@Api(name = "coconeco", version = "v1") public class EntryList { public static ArrayList entries = new ArrayList();!static { entries.add(new Entry("http://i.gzn.jp/img/2009/03/13/swimming_cat/ swimming_cat.jpg")); entries.add(new Entry("http://upload.wikimedia.org/wikipedia/ja/ 1/16/%E6%97%A5%E6%9C%AC%E7%8C%AB_2008-4.jpg")); }! // !!@ApiMethod(name = "insert", httpMethod = "post") public Entry insertEntry( @Named("lat") Double lat, @Named("lng") Double lng, @Named("url") String url, @Named("desc") String description) { Entry entry = new Entry(); entry.setLocation(lat, lng); entry.setUrl(url); entry.setDescription(description);!// entries.add(entry);! !return entry; }}coconeco/src/main/java/io/keiji/coconeco/EntryList.java 50. lat34.69741835.675595lng135.516559139.767504urlhttp://i.gzn.jp/img/2009/03/13/ swimming_cat/swimming_cat.jpghttp://upload.wikimedia.org/wikipedia/ja/ 1/16/%E6%97%A5%E6%9C%AC%E7%8C %AB_2008-4.jpgdesc 51. !@ApiMethod(name = "insert", httpMethod = "post") public Entry insertEntry( @Named("lat") Double lat, @Named("lng") Double lng, @Named("url") String url, @Named("desc") String description) { Entry entry = new Entry(); entry.setLocation(lat, lng); entry.setUrl(url); entry.setDescription(description);!public void setLocation(Double lat, Double lon) { this.latitude = lat; this.longitude = lon; this.geoHash = Geohash.encode(lat, lon); }coconeco/src/main/java/io/keiji/coconeco/Entry.java// entries.add(entry);!return entry; }coconeco/src/main/java/io/keiji/coconeco/EntryList.java{"latitude": 34.697418,"longitude": 135.516559,"geoHash": "xn0m7u2phew2","url": "http%3A%2F%2Fi.gzn.jp%2Fimg%2F2009%2F03%2F13%2Fswimming_cat%2Fswimming_cat.jpg","description": "%E3%82%B7%E3%83%BC%E3%83%AA%E3%82%B9%E6%9C%AC%E7%A4%BE"} 52. package io.keiji.coconeco;!import java.util.ArrayList; import java.net.URLEncoder; import java.io.UnsupportedEncodingException;! import javax.inject.Named; !import com.google.api.server.spi.config.Api; import com.google.api.server.spi.config.ApiMethod;@ApiMethod(name = "nyaaby", httpMethod = "get") public ArrayList getEntry( @Named("lat") Double lat, @Named("lng") Double lng) {! ! !ArrayList result = new ArrayList(); String geoHash = Geohash.encode(lat, lng); // !@Api(name = "coconeco", version = "v1") public class EntryList { public static ArrayList entries = new ArrayList();! private static final int GEO_THRESHOLD = 7; !static { Entry entry1 = new Entry(); entry1.setLocation(34.697418, 135.516559); entry1.setUrl("http://i.gzn.jp/img/2009/03/13/swimming_cat/ swimming_cat.jpg"); try { entry1.setDescription( URLEncoder.encode("", "UTF-8")); !entries.add(entry2); } catch (UnsupportedEncodingException e) {} }!// search(entries, result, term);! !entries.add(entry1); } catch (UnsupportedEncodingException e) {}Entry entry2 = new Entry(); entry2.setLocation(35.675595, 139.767504); entry2.setUrl("http://upload.wikimedia.org/wikipedia/ja/ 1/16/%E6%97%A5%E6%9C%AC%E7%8C%AB_2008-4.jpg"); try { entry2.setDescription( URLEncoder.encode(, UTF-8));String term = geoHash.substring( 0, geoHash.length() - GEO_THRESHOLD);return result; } private static void search(ArrayList from, ArrayList to, String term) { for (Entry entry : from) { if (entry.getGeoHash().startsWith(term)) { to.add(entry); } } }}coconeco/src/main/java/io/keiji/coconeco/EntryList.java 53. desclat34.69721135.6770686lng135.513215139.7697867 54. {"items" : [ {"latitude" : 35.675595,"longitude" : 139.767504,"geoHash" : "xn76uqx96uut","url" : "http://upload.wikimedia.org/wikipedia/ja/1/16/%E6%97%A5%E6%9C%AC%E7%8C%AB_2008-4.jpg","description" : "%E3%82%B7%E3%83%BC%E3%83%AA%E3%82%B9%E6%9D%B1%E4%BA%AC%E3%82%AA %E3%83%95%E3%82%A3%E3%82%B9"} ]} 55. upload stable-apogee-4881true!coconeco/src/main/java/webapp/WEB-INF/appengine-web.xml 56. $ mvn appengine:update!!Please enter code: 57. Beginning interaction for module default... 0% Created staging directory at: '/var/folders/tv/yr_x0jn163s4yr1gv77bk1mr0000gn/T/ appcfg4387737080071537979.tmp' 5% Scanning for jsp files. 20% Scanning files on local disk. 25% Initiating update. 28% Cloning 10 application files. 40% Uploading 6 files. 52% Uploaded 1 files. 61% Uploaded 2 files. 68% Uploaded 3 files. 73% Uploaded 4 files. 77% Uploaded 5 files. 80% Uploaded 6 files. 82% Initializing precompilation... 84% Sending batch containing 6 file(s) totaling 21KB. 90% Deploying new version. 99% Closing update: new version is ready to start serving. 99% Uploading index definitions.!Update for module default completed successfully. Success. Cleaning up temporary files for module default... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1:00.795s [INFO] Finished at: Sat Feb 15 06:07:07 JST 2014 [INFO] Final Memory: 13M/245M [INFO] ------------------------------------------------------------------------ 58. https://apis-explorer.appspot.com/apis-explorer/?base=https://stable-apogee-488.appspot.com/_ah/api#p/ 59. Android 60. $ mvn appengine:endpoints_get_client_libtarget/endpoints-client-libs/coconeco/target/coconeco-v1-1.17.0-rc-SNAPSHOT.jar 61. google-api-client-1.12.0-beta.jargoogle-api-client-android-1.12.0-beta.jargoogle-http-client-1.12.0-beta.jargoogle-http-client-android-1.12.0-beta.jargoogle-http-client-gson-1.12.0-beta.jargoogle-oauth-client-1.12.0-beta.jargson-2.1.jarguava-jdk5-13.0.jarjsr305-1.3.9.jarhttps://developers.google.com/appengine/docs/java/endpoints/consume_android 62. pom.xml com.google.api-clientgoogle-api-client1.17.0-rccom.google.api-clientgoogle-api-client-android1.17.0-rccom.google.api-clientgoogle-api-client-gson1.17.0-rc!UTF-8 project.build.sourceEncoding> target/endpoints-client-libs/coconeco/pom.xml 63. $ target/endpoints-client-libs/coconeco/ $ mvn dependency:copy-dependenciestarget/endpoints-client-libs/coconeco/target/dependency 64. Android Coconeco io.keiji.coconeco.android 65. libs/ 66. !!activity_main.xml 67. package io.keiji.coconeco.android;! public class MainActivity extends Activity { ! private ImageView mImage; private TextView mDescription; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImage = (ImageView) findViewById(R.id.iv_picture); mDescription = (TextView) findViewById(R.id.tv_description);// }NyaaByTask task = new NyaaByTask(); task.execute(new Void[0]); @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; }! ! ! !!MainActivity.java 68. private class NyaaByTask extends AsyncTask> { @Override protected List doInBackground(Void... params) { } @Override protected void onPostExecute(List result) { super.onPostExecute(result); if (result.size() > 0) { CoconecoEntry entry = result.get(0); try { String desc = URLDecoder.decode(entry.getDescription(), "UTF-8"); mDescription.setText(desc); } catch (UnsupportedEncodingException e) { } } }! !!!Coconeco.Builder builder = new Coconeco.Builder( AndroidHttp.newCompatibleTransport(), new GsonFactory(), null); Coconeco service = builder.build(); try { EntryCollection result = service.nyaaby(34.697211, 135.513215) .execute(); return result.getItems(); } catch (IOException e) { } return null; }ImageLoadTask task = new ImageLoadTask(); task.execute(new String[] { entry.getUrl() });MainActivity.java 69. private class ImageLoadTask extends AsyncTask { @Override protected Bitmap doInBackground(String... params) { String url = params[0]; HttpGet request = new HttpGet(url); AndroidHttpClient client = AndroidHttpClient .newInstance("Coconeco"); }Bitmap bmp = null; InputStream is = null; try { HttpResponse response = client.execute(request); is = response.getEntity().getContent(); bmp = BitmapFactory.decodeStream(is); } catch (IOException e) { } finally { if (is != null) { try { is.close(); } catch (IOException e) { } } client.getConnectionManager().shutdown(); } return bmp; }@Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); mImage.setImageBitmap(result); }! ! !!MainActivity.java 70. 71. JavaScript https://developers.google.com/appengine/docs/java/endpoints/consume_jsiOS https://developers.google.com/appengine/docs/java/endpoints/consume_ios 72. C-LIS CO., LTD. -- 3.0 Unported