├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── build.gradle ├── gradle.properties ├── gradle ├── lint.xml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proguard-rules.pro └── src ├── integration-test ├── java │ └── com │ │ └── yelp │ │ └── clientlib │ │ ├── BusinessIntegrationTest.java │ │ ├── Credential.java │ │ ├── PhoneSearchIntegrationTest.java │ │ └── SearchIntegrationTest.java └── resources │ └── credentials.yaml ├── main ├── AndroidManifest.xml └── java │ └── com │ └── yelp │ └── clientlib │ ├── annotation │ └── Nullable.java │ ├── connection │ ├── YelpAPI.java │ └── YelpAPIFactory.java │ ├── entities │ ├── Business.java │ ├── Category.java │ ├── Coordinate.java │ ├── Deal.java │ ├── DealOption.java │ ├── GiftCertificate.java │ ├── GiftCertificateOption.java │ ├── Location.java │ ├── Region.java │ ├── Review.java │ ├── SearchResponse.java │ ├── Span.java │ ├── User.java │ └── options │ │ ├── BoundingBoxOptions.java │ │ └── CoordinateOptions.java │ └── exception │ ├── ErrorHandlingInterceptor.java │ └── exceptions │ ├── AreaTooLarge.java │ ├── BadCategory.java │ ├── BusinessUnavailable.java │ ├── ExceededReqs.java │ ├── InternalError.java │ ├── InvalidOAuthCredentials.java │ ├── InvalidOAuthUser.java │ ├── InvalidParameter.java │ ├── InvalidSignature.java │ ├── MissingParameter.java │ ├── MultipleLocations.java │ ├── SSLRequired.java │ ├── UnavailableForLocation.java │ ├── UnexpectedAPIError.java │ ├── UnspecifiedLocation.java │ └── YelpAPIError.java └── test ├── java └── com │ └── yelp │ └── clientlib │ ├── connection │ └── YelpAPITest.java │ ├── entities │ ├── BusinessTest.java │ ├── CategoryTest.java │ ├── CoordinateTest.java │ ├── DealOptionTest.java │ ├── DealTest.java │ ├── GiftCertificateOptionTest.java │ ├── GiftCertificateTest.java │ ├── LocationTest.java │ ├── RegionTest.java │ ├── ReviewTest.java │ ├── SearchResponseTest.java │ ├── SpanTest.java │ ├── UserTest.java │ └── options │ │ ├── BoundingBoxOptionsTest.java │ │ └── CoordinateOptionsTest.java │ ├── exception │ └── ErrorHandlingInterceptorTest.java │ └── utils │ ├── AsyncTestUtils.java │ ├── ErrorTestUtils.java │ ├── JsonTestUtils.java │ └── SerializationTestUtils.java └── resources ├── businessResponse.json ├── noReviewBusinessResponse.json ├── sampleFailureResponse.json └── searchResponse.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .gradle/ 3 | /build 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | android: 4 | components: 5 | - tools 6 | - platform-tools 7 | # The BuildTools version used by your project 8 | - build-tools-25.0.0 9 | # The SDK version used to compile your project 10 | - android-25 11 | 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | Version 3.0.0 *(2017-01-10)* 5 | ---------------------------- 6 | 7 | * Remove the compatibility to non-Android Java. 8 | * Use Android library Gradle plugin instead of Java plugin 9 | * Build-script generate AAR instead of JAR file. 10 | 11 | 12 | Version 2.0.0 *(2016-04-26)* 13 | ---------------------------- 14 | 15 | * Change Retrofit dependency from using beta2 to a stable release version 2.0.0. 16 | 17 | 18 | Version 1.0.0 *(2016-01-29)* 19 | ---------------------------- 20 | 21 | Initial release. 22 | 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Yelp Inc 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/Yelp/yelp-android.svg?branch=master)](https://travis-ci.org/Yelp/yelp-android) 2 | 3 | # yelp-android 4 | An Android library for the [Yelp API v2](https://www.yelp.com/developers/documentation/v2/overview). It simplifies the 5 | process of authentication, request construction, and response parsing for Android developers using the 6 | [Yelp API v2](https://www.yelp.com/developers/documentation/v2/overview). This clientlib has been tested with 7 | applications written in Android API level 15 and 25. 8 | 9 | ## Installation 10 | 11 | Download [the latest AAR](https://search.maven.org/remote_content?g=com.yelp.clientlib&a=yelp-android&v=LATEST) or 12 | install by using [Maven](https://maven.apache.org/): 13 | 14 | ```xml 15 | 16 | com.yelp.clientlib 17 | yelp-android 18 | 3.0.0 19 | 20 | ``` 21 | 22 | or [Gradle](http://gradle.org/): 23 | 24 | ```groovy 25 | repositories { 26 | mavenCentral() 27 | } 28 | 29 | dependencies { 30 | ... 31 | compile 'com.yelp.clientlib:yelp-android:3.0.0' 32 | ... 33 | } 34 | ``` 35 | Proguard rules for the library can be found [here](https://github.com/Yelp/yelp-android/blob/master/proguard-rules.pro) 36 | 37 | ## Usage 38 | 39 | ### Basic usage 40 | This library uses a `YelpAPI` object to query against the API. Instantiate a `YelpAPI` object by using 41 | `YelpAPIFactory` with your API keys. 42 | ```java 43 | YelpAPIFactory apiFactory = new YelpAPIFactory(consumerKey, consumerSecret, token, tokenSecret); 44 | YelpAPI yelpAPI = apiFactory.createAPI(); 45 | ``` 46 | 47 | ### [Search API](http://www.yelp.com/developers/documentation/v2/search_api) 48 | Once you have a `YelpAPI` object you can use the `search` function to generate a `Call` object which makes a request to 49 | the Search API. 50 | 51 | The general params and locale options should be passed to the method as a `Map`. The full list of 52 | parameters can be found in the [Search API Documentation](https://www.yelp.com/developers/documentation/v2/search_api). 53 | ```java 54 | Map params = new HashMap<>(); 55 | 56 | // general params 57 | params.put("term", "food"); 58 | params.put("limit", "3"); 59 | 60 | // locale params 61 | params.put("lang", "fr"); 62 | 63 | Call call = yelpAPI.search("San Francisco", params); 64 | ``` 65 | 66 | Now you can execute the `Call` object to send the request. 67 | ```java 68 | Response response = call.execute(); 69 | ``` 70 | 71 | You can also pass in a `Callback` object to send the request asynchronously. For more see [Asynchronous Requests](#asynchronous-requests) section. 72 | ```java 73 | Callback callback = new Callback() { 74 | @Override 75 | public void onResponse(Call call, Response response) { 76 | SearchResponse searchResponse = response.body(); 77 | // Update UI text with the searchResponse. 78 | } 79 | @Override 80 | public void onFailure(Call call, Throwable t) { 81 | // HTTP error happened, do something to handle it. 82 | } 83 | }; 84 | 85 | call.enqueue(callback); 86 | ``` 87 | 88 | Additionally there are two more search methods for searching by a [bounding box](https://www.yelp.com/developers/documentation/v2/search_api#searchGBB) or for [geographical coordinates](https://www.yelp.com/developers/documentation/v2/search_api#searchGC): 89 | ```java 90 | // bounding box 91 | BoundingBoxOptions bounds = BoundingBoxOptions.builder() 92 | .swLatitude(37.7577) 93 | .swLongitude(-122.4376) 94 | .neLatitude(37.785381) 95 | .neLongitude(-122.391681).build(); 96 | Call call = yelpAPI.search(bounds, params); 97 | Response response = call.execute(); 98 | 99 | // coordinates 100 | CoordinateOptions coordinate = CoordinateOptions.builder() 101 | .latitude(37.7577) 102 | .longitude(-122.4376).build(); 103 | Call call = yelpAPI.search(coordinate, params); 104 | Response response = call.execute(); 105 | ``` 106 | 107 | ### [Business API](http://www.yelp.com/developers/documentation/v2/business) 108 | To query the Business API, use the `getBusiness` function with a `business_id`. You can also pass in locale parameters 109 | in a `Map` as specified in the [Business API Documentation](http://www.yelp.com/developers/documentation/v2/business). 110 | ```java 111 | Call call = yelpAPI.getBusiness("yelp-san-francisco"); 112 | Response response = call.execute(); 113 | ``` 114 | You can pass in locale information as well. 115 | ```java 116 | Map params = new HashMap<>(); 117 | params.put("lang", "fr"); 118 | 119 | Call call = yelpAPI.getBusiness("yelp-san-francisco", params); 120 | Response response = call.execute(); 121 | ``` 122 | 123 | ### [Phone Search API](http://www.yelp.com/developers/documentation/v2/phone_search) 124 | To query the Phone Search API, use the `getPhoneSearch` function with a phone number. Additional parameters can be 125 | passed in by using a `Map` as specified in the [Phone Search API Documentation](https://www.yelp.com/developers/documentation/v2/phone_search). 126 | ```java 127 | Call call = yelpAPI.getPhoneSearch("+15555555555"); 128 | Response response = call.execute(); 129 | ``` 130 | You can pass in country code information as well 131 | ```java 132 | Map params = new HashMap<>(); 133 | params.put("cc", "US"); 134 | params.put("category", "fashion"); 135 | 136 | Call call = yelpAPI.getPhoneSearch("5555555555", params); 137 | Response response = call.execute(); 138 | ``` 139 | 140 | ### Asynchronous Requests 141 | This library uses [Retrofit](http://square.github.io/retrofit/) as the HTTP client. To send a request asynchronously, 142 | use `Call.enqueue()` to set `Callback` function for an asynchronous request. 143 | ```java 144 | Callback callback = new Callback() { 145 | @Override 146 | public void onResponse(Call call, Response response) { 147 | Business business = response.body(); 148 | // Update UI text with the Business object. 149 | } 150 | @Override 151 | public void onFailure(Call call, Throwable t) { 152 | // HTTP error happened, do something to handle it. 153 | } 154 | }; 155 | 156 | Call call = yelpAPI.getBusiness(businessId); 157 | call.enqueue(callback); 158 | ``` 159 | 160 | You can cancel asynchronous requests by simply call `cancel()` on `Call` objects. It is important to cancel your calls 161 | while your `Activity` is being destroyed to avoid memory leaks. 162 | ```java 163 | Call call = yelpAPI.getBusiness(businessId); 164 | call.enqueue(callback); 165 | 166 | // Activity is being destroyed and the call should be canceled. 167 | call.cancel(); 168 | ``` 169 | 170 | For more information about the usage of asynchronous requests in Retrofit, see [Retrofit documentation](http://square.github.io/retrofit/). 171 | 172 | ## Responses 173 | After `Call` object is executed, a `Response` contains parsed Java objects will be returned, use `Response.body()` to 174 | get parsed Java objects. 175 | 176 | Search and phone search responses are parsed into `SearchResponse` objects. 177 | ```java 178 | Call call = yelpAPI.search("San Francisco", params); 179 | SearchResponse searchResponse = call.execute().body(); 180 | 181 | int totalNumberOfResult = searchResponse.total(); // 3 182 | 183 | ArrayList businesses = searchResponse.businesses(); 184 | String businessName = businesses.get(0).name(); // "JapaCurry Truck" 185 | Double rating = businesses.get(0).rating(); // 4.0 186 | ``` 187 | 188 | Business responses are parsed into `Business` objects directly. 189 | ```java 190 | Call call = yelpAPI.business("japacurry-truck-san-francisco"); 191 | Response response = call.execute(); 192 | Business business = response.body(); 193 | 194 | String businessName = business.name(); // "JapaCurry Truck" 195 | Double rating = business.rating(); // 4.0 196 | ``` 197 | 198 | For a full list of available response fields, take a look at the [documentation](https://www.yelp.com/developers/documentation/v2/overview) 199 | or the classes defined in [com.yelp.clientlib.entities](../../tree/master/src/main/java/com/yelp/clientlib/entities). 200 | 201 | ## Contributing 202 | 1. Fork it (http://github.com/yelp/yelp-android/fork) 203 | 2. Create your feature branch (git checkout -b my-new-feature) 204 | 3. Commit your changes (git commit -am 'Add some feature') 205 | 4. Push to the branch (git push origin my-new-feature) 206 | 5. Create new Pull Request 207 | 208 | ## Testing 209 | Please write tests for any new features. We use JUnit + Gradle so just run `./gradlew test` to run the full test suite. 210 | To know more about running JUnit tests in Gradle, see [Gradle: The Java Plugin - Test](https://docs.gradle 211 | .org/current/userguide/java_plugin.html#sec:java_test). 212 | 213 | If you are adding a new integration test, you will need to connect to the Yelp API. You can set this up by putting 214 | your API keys into `src/integration-test/resources/credentials.yaml` in the following format: 215 | ``` 216 | consumer_key: YOUR_CONSUMER_KEY 217 | consumer_secret: YOUR_CONSUMER_SECRET 218 | token: YOUR_TOKEN 219 | token_secret: YOUR_TOKEN_SECRET 220 | ``` 221 | 222 | To run the integration tests, execute `./gradlew integrationTest`. Integration tests will not be ran in the build 223 | process by executing `./gradlew build`. 224 | 225 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'maven' 3 | apply plugin: 'signing' 4 | 5 | android { 6 | compileSdkVersion 25 7 | buildToolsVersion "25.0.0" 8 | 9 | defaultConfig { 10 | minSdkVersion 15 11 | targetSdkVersion 25 12 | } 13 | 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | packagingOptions { 22 | // com.fasterxml.jackson.core:jackson-databind includes duplicate licenses in it's own submodule dependencies. 23 | // Build fails because of this even though the submodules are not wrapped into the output artifacts. We exclude 24 | // the LICENSE files from the build so it doesn't fail the process. 25 | exclude 'META-INF/LICENSE' 26 | } 27 | 28 | lintOptions { 29 | lintConfig rootProject.file('gradle/lint.xml') 30 | } 31 | } 32 | 33 | buildscript { 34 | repositories { 35 | jcenter() 36 | } 37 | dependencies { 38 | classpath 'com.android.tools.build:gradle:2.2.3' 39 | } 40 | } 41 | 42 | /** 43 | * Configure integration tests. Set up a new integrationTest task to execute tests in src/integration-test separately 44 | * from the main build. 45 | * 46 | * To run all of the integration tests, run "gradle integrationTest". 47 | */ 48 | sourceSets { 49 | integrationTest { 50 | java { 51 | java.srcDirs = [ 52 | 'src/integration-test/java', 53 | 'src/main/java', 54 | 'src/test/java' 55 | ] 56 | resources.srcDirs = [ 57 | 'src/integration-test/resources', 58 | 'src/test/resources' 59 | ] 60 | } 61 | } 62 | } 63 | 64 | configurations { 65 | integrationTestCompile.extendsFrom testCompile 66 | integrationTestRuntime.extendsFrom testRuntime 67 | } 68 | 69 | task integrationTest(type: Test) { 70 | testClassesDir = sourceSets.integrationTest.output.classesDir 71 | classpath = sourceSets.integrationTest.runtimeClasspath 72 | 73 | // Set upToDateWhen to false so integration tests always run when the task is called. 74 | outputs.upToDateWhen { false } 75 | } 76 | 77 | // Makes integration tests not run by default. 78 | check.dependsOn -= integrationTest 79 | 80 | /** 81 | * Configure deployment. 82 | * 83 | * To deploy artifacts to public repository, run "gradle upload". You need to have "ossrhUsername", "ossrhPassword", 84 | * "signing.keyId", "signing.password" and "signing.secretKeyRingFile" in your HOME/.gradle/gradle.properties file 85 | * to upload archives. 86 | * 87 | * To deploy artifacts to local Maven repository, run "gradle install". 88 | */ 89 | group = 'com.yelp.clientlib' 90 | archivesBaseName = 'yelp-android' 91 | 92 | task androidJavadocs(type: Javadoc) { 93 | source = android.sourceSets.main.java.srcDirs 94 | } 95 | 96 | task androidJavadocsJar(type: Jar) { 97 | classifier = 'javadoc' 98 | from androidJavadocs.destinationDir 99 | } 100 | 101 | task androidSourcesJar(type: Jar) { 102 | classifier = 'sources' 103 | from android.sourceSets.main.java.srcDirs 104 | } 105 | 106 | artifacts { 107 | archives androidJavadocsJar 108 | archives androidSourcesJar 109 | } 110 | 111 | task checkOSSRHProperties << { 112 | if (project.properties['ossrhUsername'] == null || project.properties['ossrhPassword'] == null) { 113 | throw new IllegalStateException('ERROR: you need to have ossrhUsername and ossrhPassword properties' + 114 | ' defined in your HOME/.gradle/gradle.properties file to upload archives'); 115 | } 116 | if (project.properties['signing.keyId'] == null || project.properties['signing.password'] == null || project 117 | .properties['signing.secretKeyRingFile'] == null) { 118 | throw new IllegalStateException('ERROR: you need to have signing.keyId, signing.password and ' + 119 | 'signing.secretKeyRingFile properties defined in your HOME/.gradle/gradle.properties file to sign ' + 120 | 'the archives.'); 121 | } 122 | } 123 | 124 | uploadArchives { 125 | dependsOn checkOSSRHProperties 126 | repositories { 127 | mavenDeployer { 128 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 129 | 130 | repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') { 131 | authentication(userName: project.properties['ossrhUsername'], password: project.properties['ossrhPassword']) 132 | } 133 | 134 | snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots') { 135 | authentication(userName: project.properties['ossrhUsername'], password: project.properties['ossrhPassword']) 136 | } 137 | 138 | pom.project { 139 | name 'Yelp Android Clientlib' 140 | packaging 'jar' 141 | description 'A Java library for the Yelp API. It simplifies the process of authentication, request ' + 142 | 'construction, and response parsing for Java/Android developers using the Yelp API.' 143 | url 'https://www.yelp.com/developers' 144 | 145 | scm { 146 | connection 'scm:git:git@github.com:Yelp/yelp-android.git' 147 | developerConnection 'scm:git:git@github.com:Yelp/yelp-android.git' 148 | url 'git@github.com:Yelp/yelp-android.git' 149 | } 150 | 151 | licenses { 152 | license { 153 | name 'The MIT License (MIT)' 154 | url 'https://opensource.org/licenses/MIT' 155 | } 156 | } 157 | 158 | developers { 159 | developer { 160 | name 'Yelp' 161 | email 'api+android@yelp.com' 162 | } 163 | 164 | developer { 165 | id 'tzuhanwu' 166 | name 'Tzu-Han Wu' 167 | email 'tzuhanwu@yelp.com' 168 | } 169 | } 170 | } 171 | } 172 | } 173 | } 174 | 175 | signing { 176 | required { gradle.taskGraph.hasTask('uploadArchives') } 177 | sign configurations.archives 178 | } 179 | 180 | /** 181 | * Configure package dependencies. 182 | */ 183 | repositories { 184 | mavenCentral() 185 | } 186 | 187 | dependencies { 188 | compile fileTree(dir: 'libs', include: ['*.jar']) 189 | compile 'com.google.auto.value:auto-value:1.2' 190 | compile 'com.squareup.retrofit2:retrofit:2.0.0' 191 | compile 'com.squareup.retrofit2:converter-jackson:2.0.0' 192 | compile 'oauth.signpost:signpost-core:1.2.1.2' 193 | compile 'se.akerfeldt:okhttp-signpost:1.1.0' 194 | compile 'com.squareup.okhttp3:okhttp:3.1.2' 195 | 196 | testCompile 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.7.2' 197 | testCompile 'com.squareup.okhttp3:mockwebserver:3.2.0' 198 | testCompile 'org.easymock:easymock:3.4' 199 | testCompile 'org.powermock:powermock-api-easymock:1.6.4' 200 | testCompile 'org.powermock:powermock-module-junit4:1.6.4' 201 | testCompile 'junit:junit:4.12' 202 | testCompile 'junit-addons:junit-addons:1.4' 203 | 204 | integrationTestCompile 'com.google.auto.value:auto-value:1.2' 205 | integrationTestCompile 'com.squareup.retrofit2:converter-jackson:2.0.0' 206 | integrationTestCompile 'se.akerfeldt:okhttp-signpost:1.1.0' 207 | integrationTestCompile 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.7.2' 208 | } 209 | 210 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=3.0.0-SNAPSHOT 2 | -------------------------------------------------------------------------------- /gradle/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yelp/yelp-android/c9ed1aae0cc3068dc2e4ae78dd7465e7db201c93/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\adt-bundle-windows-x86_64-20131030\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -dontwarn com.google.android.gms.internal.zzhu 19 | 20 | # autovalue 21 | -dontwarn javax.lang.** 22 | -dontwarn javax.tools.** 23 | -dontwarn javax.annotation.** 24 | -dontwarn autovalue.shaded.com.** 25 | -dontwarn com.google.auto.value.** 26 | -dontwarn javax.servlet.** 27 | -dontwarn sun.misc.** 28 | -dontwarn autovalue.shaded.org.apache.commons.** 29 | -dontwarn org.apache.log4j.** 30 | -dontwarn org.apache.log.** 31 | -dontwarn org.apache.velocity.** 32 | -dontwarn org.apache.tools.** 33 | -dontwarn org.jdom.** 34 | -dontwarn org.java.lang.** 35 | 36 | # OkHttp 37 | # Ignore warnings: https://github.com/square/okhttp/wiki/FAQs 38 | -dontwarn com.squareup.okhttp.internal.huc.** 39 | # Ignore warnings: https://github.com/square/okio/issues/60 40 | -dontwarn okio.** 41 | # Ignore warnings: https://github.com/square/retrofit/issues/435 42 | -dontwarn com.google.appengine.api.urlfetch.** 43 | 44 | -keepattributes Signature 45 | -keepattributes *Annotation* 46 | -keep class okhttp3.** { *; } 47 | -keep interface okhttp3.** { *; } 48 | -dontwarn okhttp3.** 49 | 50 | # Retrofit 51 | -dontwarn retrofit2.Platform$Java8 52 | 53 | -keep class com.google.gson.** { *; } 54 | -keep class com.google.inject.** { *; } 55 | -keep class org.apache.http.** { *; } 56 | -keep class org.apache.james.mime4j.** { *; } 57 | -keep class javax.inject.** { *; } 58 | -keep class retrofit.** { *; } 59 | -keepclasseswithmembers class * { 60 | @retrofit.** *; 61 | } 62 | -keepclassmembers class * { 63 | @retrofit.** *; 64 | } 65 | 66 | # Proguard configuration for Jackson 2.x (fasterxml package instead of codehaus package) 67 | 68 | -keep class com.fasterxml.jackson.databind.ObjectMapper { 69 | public ; 70 | protected ; 71 | } 72 | -keep class com.fasterxml.jackson.databind.ObjectWriter { 73 | public ** writeValueAsString(**); 74 | } 75 | -keepattributes *Annotation*,EnclosingMethod,Signature 76 | -keepnames class com.fasterxml.jackson.** { *; } 77 | 78 | -dontwarn com.fasterxml.jackson.databind.** 79 | -dontwarn com.fasterxml.jackson.databind.PropertyNamingStrategy$LowerCaseWithUnderscoresStrategy 80 | 81 | -keep class org.codehaus.** { *; } 82 | -keep class com.fasterxml.jackson.annotation.** { *; } 83 | -keepclassmembers public final enum org.codehaus.jackson.annotate.JsonAutoDetect$Visibility { 84 | public static final org.codehaus.jackson.annotate.JsonAutoDetect$Visibility *; } 85 | -keepclassmembers public class com.fasterxml.jackson.databind.PropertyNamingStrategy$LowerCaseWithUnderscoresStrategy { 86 | public (...); } 87 | 88 | #Yelp Serializable objects 89 | -keep class com.yelp.clientlib.entities.*$* { 90 | *; 91 | } 92 | 93 | -printmapping build/outputs/mapping/release/mapping.txt 94 | 95 | -------------------------------------------------------------------------------- /src/integration-test/java/com/yelp/clientlib/BusinessIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib; 2 | 3 | import com.yelp.clientlib.connection.YelpAPI; 4 | import com.yelp.clientlib.connection.YelpAPIFactory; 5 | import com.yelp.clientlib.entities.Business; 6 | import com.yelp.clientlib.exception.exceptions.BusinessUnavailable; 7 | import com.yelp.clientlib.exception.exceptions.YelpAPIError; 8 | import com.yelp.clientlib.utils.AsyncTestUtils; 9 | import com.yelp.clientlib.utils.ErrorTestUtils; 10 | 11 | import org.junit.Assert; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import retrofit2.Call; 21 | import retrofit2.Callback; 22 | import retrofit2.Response; 23 | import retrofit2.Retrofit; 24 | 25 | /** 26 | * TODO: Move this class to other directory so src/java/test only contains unit-tests related files. 27 | */ 28 | public class BusinessIntegrationTest { 29 | private String businessId = "yelp-san-francisco"; 30 | private YelpAPI yelpAPI; 31 | 32 | @Before 33 | public void setUp() { 34 | YelpAPIFactory yelpAPIFactory = new YelpAPIFactory( 35 | Credential.consumerKey(), 36 | Credential.consumerSecret(), 37 | Credential.token(), 38 | Credential.tokenSecret() 39 | ); 40 | 41 | // Make API requests to be executed in main thread so we can verify it easily. 42 | yelpAPIFactory = AsyncTestUtils.setToRunInMainThread(yelpAPIFactory); 43 | 44 | yelpAPI = yelpAPIFactory.createAPI(); 45 | } 46 | 47 | @Test 48 | public void testGetBusiness() throws IOException { 49 | Call call = yelpAPI.getBusiness(businessId); 50 | Response response = call.execute(); 51 | Assert.assertEquals(200, response.code()); 52 | 53 | Business business = response.body(); 54 | Assert.assertNotNull(business); 55 | Assert.assertEquals(businessId, business.id()); 56 | } 57 | 58 | @Test 59 | public void testGetBusinessWithParams() throws IOException { 60 | Map params = new HashMap<>(); 61 | params.put("cc", "US"); 62 | params.put("lang", "en"); 63 | params.put("lang_filter", "true"); 64 | params.put("actionlinks", "true"); 65 | 66 | Call call = yelpAPI.getBusiness(businessId, params); 67 | Response response = call.execute(); 68 | Assert.assertEquals(200, response.code()); 69 | 70 | Business business = response.body(); 71 | Assert.assertNotNull(business); 72 | Assert.assertEquals(businessId, business.id()); 73 | } 74 | 75 | @Test 76 | public void testGetBusinessAsynchronous() { 77 | final ArrayList> responseWrapper = new ArrayList<>(); 78 | Callback businessCallback = new Callback() { 79 | @Override 80 | public void onResponse(Call call, Response response) { 81 | responseWrapper.add(response); 82 | } 83 | 84 | @Override 85 | public void onFailure(Call call, Throwable t) { 86 | Assert.fail("Unexpected failure: " + t.toString()); 87 | } 88 | }; 89 | 90 | Call call = yelpAPI.getBusiness(businessId); 91 | call.enqueue(businessCallback); 92 | 93 | Response response = responseWrapper.get(0); 94 | Assert.assertEquals(200, response.code()); 95 | 96 | Business business = response.body(); 97 | Assert.assertNotNull(business); 98 | Assert.assertEquals(businessId, business.id()); 99 | } 100 | 101 | @Test 102 | public void testGetBusinessWith400Response() throws IOException { 103 | Call call = yelpAPI.getBusiness("I-dont-think-this-biz-really-exists"); 104 | 105 | try { 106 | call.execute(); 107 | } catch (YelpAPIError apiError) { 108 | Assert.assertTrue(apiError instanceof BusinessUnavailable); 109 | ErrorTestUtils.verifyErrorContent( 110 | apiError, 111 | 400, 112 | "Bad Request", 113 | "BUSINESS_UNAVAILABLE", 114 | "Business information is unavailable" 115 | ); 116 | } 117 | } 118 | 119 | @Test 120 | public void testGetBusinessAsynchronousWith400Response() throws IOException { 121 | Callback businessCallback = new Callback() { 122 | @Override 123 | public void onResponse(Call call, Response response) { 124 | Assert.fail("Expected failure not returned."); 125 | } 126 | 127 | @Override 128 | public void onFailure(Call call, Throwable t) { 129 | Assert.assertTrue(t instanceof BusinessUnavailable); 130 | ErrorTestUtils.verifyErrorContent( 131 | (YelpAPIError) t, 132 | 400, 133 | "Bad Request", 134 | "BUSINESS_UNAVAILABLE", 135 | "Business information is unavailable" 136 | ); 137 | } 138 | }; 139 | 140 | Call call = yelpAPI.getBusiness("I-dont-think-this-biz-really-exists"); 141 | call.enqueue(businessCallback); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/integration-test/java/com/yelp/clientlib/Credential.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 7 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 8 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 9 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 10 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 11 | 12 | import org.junit.Assert; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | 17 | /** 18 | * Util class to get test credentials from credentials.yaml file.
19 | * JSON annotations are used by Jackson {@link ObjectMapper} to determine field name mappings. To consume YAML files, 20 | * {@link YAMLFactory} is passed into {@link ObjectMapper} to parse YAML formatted data. Refer to 21 | * jackson-dataformat-yaml for more information. 22 | */ 23 | @JsonIgnoreProperties(ignoreUnknown = true) 24 | @JsonDeserialize(builder = Credential.Builder.class) 25 | public class Credential { 26 | 27 | private static final String CREDS_CONFIG_FILE_NAME = "credentials.yaml"; 28 | 29 | private static Credential instance; 30 | 31 | private String consumerKey; 32 | private String consumerSecret; 33 | private String token; 34 | private String tokenSecret; 35 | 36 | private Credential(Builder builder) { 37 | consumerKey = builder.consumerKey; 38 | consumerSecret = builder.consumerSecret; 39 | token = builder.token; 40 | tokenSecret = builder.tokenSecret; 41 | } 42 | 43 | public static String consumerKey() { 44 | return getCredential().consumerKey; 45 | } 46 | 47 | public static String consumerSecret() { 48 | return getCredential().consumerSecret; 49 | } 50 | 51 | public static String token() { 52 | return getCredential().token; 53 | } 54 | 55 | public static String tokenSecret() { 56 | return getCredential().tokenSecret; 57 | } 58 | 59 | private static Credential getCredential() { 60 | if (instance == null) { 61 | InputStream inputStream = Credential.class.getClassLoader().getResourceAsStream(CREDS_CONFIG_FILE_NAME); 62 | ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); 63 | try { 64 | instance = objectMapper.readValue(inputStream, Credential.class); 65 | } catch (IOException e) { 66 | Assert.fail("Failed to get credentials from " + CREDS_CONFIG_FILE_NAME + ": " + e.toString()); 67 | } 68 | } 69 | 70 | return instance; 71 | } 72 | 73 | @JsonPOJOBuilder(withPrefix = "") 74 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 75 | public static final class Builder { 76 | private String consumerKey; 77 | private String consumerSecret; 78 | private String token; 79 | private String tokenSecret; 80 | 81 | public Builder() { 82 | } 83 | 84 | @JsonProperty("consumer_key") 85 | public Builder consumerKey(String val) { 86 | consumerKey = val; 87 | return this; 88 | } 89 | 90 | @JsonProperty("consumer_secret") 91 | public Builder consumerSecret(String val) { 92 | consumerSecret = val; 93 | return this; 94 | } 95 | 96 | @JsonProperty("token") 97 | public Builder token(String val) { 98 | token = val; 99 | return this; 100 | } 101 | 102 | @JsonProperty("token_secret") 103 | public Builder tokenSecret(String val) { 104 | tokenSecret = val; 105 | return this; 106 | } 107 | 108 | public Credential build() { 109 | return new Credential(this); 110 | } 111 | } 112 | 113 | public static Builder builder() { 114 | return new Builder(); 115 | } 116 | } -------------------------------------------------------------------------------- /src/integration-test/java/com/yelp/clientlib/PhoneSearchIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib; 2 | 3 | import com.yelp.clientlib.connection.YelpAPI; 4 | import com.yelp.clientlib.connection.YelpAPIFactory; 5 | import com.yelp.clientlib.entities.Business; 6 | import com.yelp.clientlib.entities.SearchResponse; 7 | import com.yelp.clientlib.utils.AsyncTestUtils; 8 | 9 | import org.junit.Assert; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | import retrofit2.Call; 19 | import retrofit2.Callback; 20 | import retrofit2.Response; 21 | import retrofit2.Retrofit; 22 | 23 | /** 24 | * TODO: Move this class to other directory so src/java/test only contains unit-tests related files. 25 | */ 26 | public class PhoneSearchIntegrationTest { 27 | private String phone = "+14159083801"; 28 | private YelpAPI yelpAPI; 29 | 30 | @Before 31 | public void setUp() { 32 | YelpAPIFactory yelpAPIFactory = new YelpAPIFactory( 33 | Credential.consumerKey(), 34 | Credential.consumerSecret(), 35 | Credential.token(), 36 | Credential.tokenSecret() 37 | ); 38 | 39 | // Make API requests to be executed in main thread so we can verify it easily. 40 | yelpAPIFactory = AsyncTestUtils.setToRunInMainThread(yelpAPIFactory); 41 | 42 | yelpAPI = yelpAPIFactory.createAPI(); 43 | } 44 | 45 | @Test 46 | public void testGetPhoneSearch() throws IOException { 47 | Call call = yelpAPI.getPhoneSearch(phone); 48 | Response response = call.execute(); 49 | Assert.assertEquals(200, response.code()); 50 | 51 | SearchResponse searchResponse = response.body(); 52 | Assert.assertNotNull(searchResponse); 53 | Business business = searchResponse.businesses().get(0); 54 | Assert.assertEquals(phone, business.phone()); 55 | } 56 | 57 | @Test 58 | public void testGetPhoneSearchWithParams() throws IOException { 59 | Map params = new HashMap<>(); 60 | params.put("category", "massmedia"); 61 | params.put("cc", "US"); 62 | 63 | Call call = yelpAPI.getPhoneSearch(phone, params); 64 | Response response = call.execute(); 65 | Assert.assertEquals(200, response.code()); 66 | 67 | SearchResponse searchResponse = response.body(); 68 | Assert.assertNotNull(searchResponse); 69 | Business business = searchResponse.businesses().get(0); 70 | Assert.assertEquals(phone, business.phone()); 71 | } 72 | 73 | @Test 74 | public void testGetPhoneSearchAsynchronous() { 75 | final ArrayList> responseWrapper = new ArrayList<>(); 76 | Callback searchCallback = new Callback() { 77 | @Override 78 | public void onResponse(Call call, Response response) { 79 | responseWrapper.add(response); 80 | } 81 | 82 | @Override 83 | public void onFailure(Call call, Throwable t) { 84 | Assert.fail("Unexpected failure: " + t.toString()); 85 | } 86 | }; 87 | 88 | Call call = yelpAPI.getPhoneSearch(phone); 89 | call.enqueue(searchCallback); 90 | 91 | Response response = responseWrapper.get(0); 92 | Assert.assertEquals(200, response.code()); 93 | 94 | SearchResponse searchResponse = response.body(); 95 | Assert.assertNotNull(searchResponse); 96 | 97 | Business business = searchResponse.businesses().get(0); 98 | Assert.assertEquals(phone, business.phone()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/integration-test/java/com/yelp/clientlib/SearchIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib; 2 | 3 | import com.yelp.clientlib.connection.YelpAPI; 4 | import com.yelp.clientlib.connection.YelpAPIFactory; 5 | import com.yelp.clientlib.entities.SearchResponse; 6 | import com.yelp.clientlib.entities.options.BoundingBoxOptions; 7 | import com.yelp.clientlib.entities.options.CoordinateOptions; 8 | import com.yelp.clientlib.utils.AsyncTestUtils; 9 | 10 | import org.junit.Assert; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | 14 | import java.io.IOException; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | import retrofit2.Call; 19 | import retrofit2.Response; 20 | 21 | /** 22 | * TODO: Move this class to other directory so src/java/test only contains unit-tests related files. 23 | */ 24 | public class SearchIntegrationTest { 25 | private YelpAPI yelpAPI; 26 | 27 | @Before 28 | public void setUp() { 29 | YelpAPIFactory yelpAPIFactory = new YelpAPIFactory( 30 | Credential.consumerKey(), 31 | Credential.consumerSecret(), 32 | Credential.token(), 33 | Credential.tokenSecret() 34 | 35 | ); 36 | 37 | // Make API requests to be executed in main thread so we can verify it easily. 38 | yelpAPIFactory = AsyncTestUtils.setToRunInMainThread(yelpAPIFactory); 39 | 40 | yelpAPI = yelpAPIFactory.createAPI(); 41 | } 42 | 43 | @Test 44 | public void testSearchByLocation() throws IOException { 45 | Map params = new HashMap<>(); 46 | params.put("term", "yelp"); 47 | 48 | Call call = yelpAPI.search("San Francisco", params); 49 | Response response = call.execute(); 50 | Assert.assertEquals(200, response.code()); 51 | 52 | SearchResponse searchResponse = response.body(); 53 | Assert.assertNotNull(searchResponse); 54 | } 55 | 56 | @Test 57 | public void testSearchByLocationWithOptionalCoordinate() throws IOException { 58 | Map params = new HashMap<>(); 59 | params.put("term", "yelp"); 60 | params.put("cll", "37.7867703362929,-122.399958372115"); 61 | 62 | Call call = yelpAPI.search("San Francisco", params); 63 | Response response = call.execute(); 64 | Assert.assertEquals(200, response.code()); 65 | 66 | SearchResponse searchResponse = response.body(); 67 | Assert.assertNotNull(searchResponse); 68 | } 69 | 70 | 71 | @Test 72 | public void testSearchByCoordinateOptions() throws IOException { 73 | CoordinateOptions coordinate = CoordinateOptions.builder() 74 | .latitude(37.7867703362929) 75 | .longitude(-122.399958372115).build(); 76 | 77 | Map params = new HashMap<>(); 78 | params.put("term", "yelp"); 79 | 80 | Call call = yelpAPI.search(coordinate, params); 81 | Response response = call.execute(); 82 | Assert.assertEquals(200, response.code()); 83 | 84 | SearchResponse searchResponse = response.body(); 85 | Assert.assertNotNull(searchResponse); 86 | } 87 | 88 | @Test 89 | public void testSearchByBoundingBoxOptions() throws IOException { 90 | BoundingBoxOptions bounds = BoundingBoxOptions.builder() 91 | .swLatitude(37.900000) 92 | .swLongitude(-122.500000) 93 | .neLatitude(37.788022) 94 | .neLongitude(-122.399797) 95 | .build(); 96 | 97 | Map params = new HashMap<>(); 98 | params.put("term", "yelp"); 99 | 100 | Call call = yelpAPI.search(bounds, params); 101 | Response response = call.execute(); 102 | Assert.assertEquals(200, response.code()); 103 | 104 | SearchResponse searchResponse = response.body(); 105 | Assert.assertNotNull(searchResponse); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/integration-test/resources/credentials.yaml: -------------------------------------------------------------------------------- 1 | # Add your credential to run the tests in test/java/com/yelp/clientlib/integration. 2 | # Reminder: DO NOT commit your credential into public repositories. 3 | # TODO: Move this class to other directory so src/java/test only contains unit-tests related files. 4 | 5 | consumer_key: 6 | consumer_secret: 7 | token: 8 | token_secret: 9 | -------------------------------------------------------------------------------- /src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/annotation/Nullable.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.annotation; 2 | 3 | /** 4 | * Indicates whether a field can be null. 5 | * 6 | * For fields with no {@link Nullable} decoration, {@link com.fasterxml.jackson.databind.JsonMappingException} is 7 | * raised while performing deserialization if the field is missing in the JSON string. 8 | * {@link java.lang.IllegalStateException} is raised while using builder to construct an instance with the field set as 9 | * null. 10 | */ 11 | 12 | public @interface Nullable { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/connection/YelpAPI.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.connection; 2 | 3 | import com.yelp.clientlib.entities.Business; 4 | import com.yelp.clientlib.entities.SearchResponse; 5 | import com.yelp.clientlib.entities.options.BoundingBoxOptions; 6 | import com.yelp.clientlib.entities.options.CoordinateOptions; 7 | 8 | import java.util.Map; 9 | 10 | import retrofit2.Call; 11 | import retrofit2.http.GET; 12 | import retrofit2.http.Path; 13 | import retrofit2.http.Query; 14 | import retrofit2.http.QueryMap; 15 | 16 | public interface YelpAPI { 17 | 18 | /** 19 | * Make a request to the business endpoint. 20 | * 21 | * @param businessId The business id. 22 | * @return Object to execute the request. 23 | * @see https://www.yelp.com/developers/documentation/v2/business 24 | */ 25 | @GET("/v2/business/{businessId}") 26 | Call getBusiness(@Path("businessId") String businessId); 27 | 28 | /** 29 | * Make a request to the business endpoint. 30 | * 31 | * @param businessId The business id. 32 | * @param params Key, value pairs as business API params. Keys and values will be URL encoded by {@link 33 | * QueryMap}. 34 | * @return Object to execute the request. 35 | * @see https://www.yelp.com/developers/documentation/v2/business 36 | */ 37 | @GET("/v2/business/{businessId}") 38 | Call getBusiness(@Path("businessId") String businessId, @QueryMap Map params); 39 | 40 | /** 41 | * Make a request to the phone search endpoint. 42 | * 43 | * @param phone Business phone number to search for. 44 | * @return Object to execute the request. 45 | * @see https://www.yelp.com/developers/documentation/v2/phone_search 46 | */ 47 | @GET("/v2/phone_search") 48 | Call getPhoneSearch(@Query("phone") String phone); 49 | 50 | /** 51 | * Make a request to the phone search endpoint. 52 | * 53 | * @param phone Business phone number to search for. 54 | * @param params Key, value pairs as phone search API params. Keys and values will be URL encoded by {@link 55 | * QueryMap}. 56 | * @return Object to execute the request. 57 | * @see https://www.yelp.com/developers/documentation/v2/phone_search 58 | */ 59 | @GET("/v2/phone_search") 60 | Call getPhoneSearch(@Query("phone") String phone, @QueryMap Map params); 61 | 62 | /** 63 | * Make a request to the search endpoint. Specify a location by neighborhood, address, or city. 64 | * 65 | * @param location Location by neighborhood, address, or city. 66 | * @param params Key, value pairs as search API params. Keys and values will be URL encoded by {@link QueryMap}. 67 | * @return Object to execute the request. 68 | * @see https://www.yelp.com/developers/documentation/v2/search_api#searchNAC 69 | */ 70 | @GET("/v2/search") 71 | Call search(@Query("location") String location, @QueryMap Map params); 72 | 73 | /** 74 | * Make a request to the search endpoint by geographic coordinate. Specify a latitude and longitude with optional 75 | * accuracy, altitude, and altitude_accuracy in {@link CoordinateOptions}. 76 | * 77 | * @param coordinate Geographic coordinate to search near. 78 | * @param params Key, value pairs as search API params. Keys and values will be URL encoded by {@link QueryMap}. 79 | * @return Object to execute the request. 80 | * @see http://www.yelp.com/developers/documentation/v2/search_api#searchGC 81 | */ 82 | @GET("/v2/search") 83 | Call search(@Query("ll") CoordinateOptions coordinate, @QueryMap Map params); 84 | 85 | /** 86 | * Make a request to the search endpoint by bounding box. Specify a southwest latitude/longitude and a northeast 87 | * latitude/longitude in {@link BoundingBoxOptions}. 88 | * 89 | *

{@link BoundingBoxOptions} is already encoded in {@link BoundingBoxOptions#toString()} for the special URI 90 | * character it uses, "encoded" is set to true so Retrofit doesn't encode it again. 91 | * 92 | * @param boundingBox Geographical bounding box to search in. 93 | * @param params Key, value pairs as search API params. Keys and values will be URL encoded by {@link QueryMap}. 94 | * @return Object to execute the request. 95 | * @see http://www.yelp.com/developers/documentation/v2/search_api#searchGBB 96 | */ 97 | @GET("/v2/search") 98 | Call search( 99 | @Query(value = "bounds", encoded = true) BoundingBoxOptions boundingBox, 100 | @QueryMap Map params 101 | ); 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/connection/YelpAPIFactory.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.connection; 2 | 3 | import okhttp3.OkHttpClient; 4 | import com.yelp.clientlib.exception.ErrorHandlingInterceptor; 5 | 6 | import retrofit2.converter.jackson.JacksonConverterFactory; 7 | import retrofit2.Retrofit; 8 | import se.akerfeldt.okhttp.signpost.OkHttpOAuthConsumer; 9 | import se.akerfeldt.okhttp.signpost.SigningInterceptor; 10 | 11 | 12 | /** 13 | * Util class to create YelpAPI as the stub to use Yelp API. This is the entry point to use this clientlib. 14 | *

15 | * Example:
16 | * YelpAPIFactory apiFactory = new YelpAPIFactory(consumerKey, consumerSecret, token, tokenSecret);
17 | * YelpAPI yelpAPI = apiFactory.createAPI();
18 | * Business business = yelpAPI.getBusiness(businessId).execute(); 19 | *

20 | */ 21 | public class YelpAPIFactory { 22 | 23 | private static final String YELP_API_BASE_URL = "https://api.yelp.com"; 24 | 25 | private OkHttpClient httpClient; 26 | 27 | /** 28 | * Construct a new {@code YelpAPIFactory}. 29 | * 30 | * @param consumerKey the consumer key. 31 | * @param consumerSecret the consumer secret. 32 | * @param token the access token. 33 | * @param tokenSecret the token secret. 34 | * @see https://www.yelp.com/developers/manage_api_keys 35 | */ 36 | public YelpAPIFactory(String consumerKey, String consumerSecret, String token, String tokenSecret) { 37 | OkHttpOAuthConsumer consumer = new OkHttpOAuthConsumer(consumerKey, consumerSecret); 38 | consumer.setTokenWithSecret(token, tokenSecret); 39 | 40 | this.httpClient = new OkHttpClient.Builder() 41 | .addInterceptor(new SigningInterceptor(consumer)) 42 | .addInterceptor(new ErrorHandlingInterceptor()) 43 | .build(); 44 | } 45 | 46 | /** 47 | * Initiate a {@link YelpAPI} instance. 48 | * 49 | * @return an instance of {@link YelpAPI}. 50 | */ 51 | public YelpAPI createAPI() { 52 | Retrofit retrofit = new Retrofit.Builder() 53 | .baseUrl(getAPIBaseUrl()) 54 | .addConverterFactory(JacksonConverterFactory.create()) 55 | .client(this.httpClient) 56 | .build(); 57 | 58 | return retrofit.create(YelpAPI.class); 59 | } 60 | 61 | /** 62 | * Get the base URL of Yelp APIs. 63 | * 64 | * @return the base URL of Yelp APIs. 65 | */ 66 | public String getAPIBaseUrl() { 67 | return YELP_API_BASE_URL; 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/Business.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | import java.util.ArrayList; 13 | 14 | @AutoValue 15 | @JsonIgnoreProperties(ignoreUnknown = true) 16 | @JsonDeserialize(builder = AutoValue_Business.Builder.class) 17 | public abstract class Business implements Serializable { 18 | 19 | public abstract String id(); 20 | 21 | public abstract String name(); 22 | 23 | @Nullable 24 | public abstract ArrayList categories(); 25 | 26 | @Nullable 27 | public abstract String displayPhone(); 28 | 29 | @Nullable 30 | public abstract Double distance(); 31 | 32 | @Nullable 33 | public abstract String eat24Url(); 34 | 35 | @Nullable 36 | public abstract String imageUrl(); 37 | 38 | @Nullable 39 | public abstract Boolean isClaimed(); 40 | 41 | @Nullable 42 | public abstract Boolean isClosed(); 43 | 44 | @Nullable 45 | public abstract String menuProvider(); 46 | 47 | @Nullable 48 | public abstract Long menuDateUpdated(); 49 | 50 | @Nullable 51 | public abstract String mobileUrl(); 52 | 53 | @Nullable 54 | public abstract String phone(); 55 | 56 | @Nullable 57 | public abstract String reservationUrl(); 58 | 59 | @Nullable 60 | public abstract Integer reviewCount(); 61 | 62 | @Nullable 63 | public abstract String snippetImageUrl(); 64 | 65 | @Nullable 66 | public abstract String snippetText(); 67 | 68 | @Nullable 69 | public abstract String url(); 70 | 71 | @Nullable 72 | public abstract ArrayList deals(); 73 | 74 | @Nullable 75 | public abstract ArrayList giftCertificates(); 76 | 77 | @Nullable 78 | public abstract Location location(); 79 | 80 | @Nullable 81 | public abstract Double rating(); 82 | 83 | @Nullable 84 | public abstract String ratingImgUrl(); 85 | 86 | @Nullable 87 | public abstract String ratingImgUrlLarge(); 88 | 89 | @Nullable 90 | public abstract String ratingImgUrlSmall(); 91 | 92 | @Nullable 93 | public abstract ArrayList reviews(); 94 | 95 | @AutoValue.Builder 96 | @JsonPOJOBuilder(withPrefix = "") 97 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 98 | public abstract static class Builder { 99 | 100 | public abstract Builder categories(ArrayList categories); 101 | 102 | public abstract Builder displayPhone(String displayPhone); 103 | 104 | public abstract Builder distance(Double distance); 105 | 106 | public abstract Builder eat24Url(String eat24Url); 107 | 108 | public abstract Builder id(String id); 109 | 110 | public abstract Builder imageUrl(String imageUrl); 111 | 112 | public abstract Builder isClaimed(Boolean isClaimed); 113 | 114 | public abstract Builder isClosed(Boolean isClosed); 115 | 116 | public abstract Builder menuProvider(String menuProvider); 117 | 118 | public abstract Builder menuDateUpdated(Long menuDateUpdated); 119 | 120 | public abstract Builder mobileUrl(String mobileUrl); 121 | 122 | public abstract Builder name(String name); 123 | 124 | public abstract Builder phone(String phone); 125 | 126 | public abstract Builder reservationUrl(String reservationUrl); 127 | 128 | public abstract Builder reviewCount(Integer reviewCount); 129 | 130 | public abstract Builder snippetImageUrl(String snippetImageUrl); 131 | 132 | public abstract Builder snippetText(String snippetText); 133 | 134 | public abstract Builder url(String url); 135 | 136 | public abstract Builder deals(ArrayList deals); 137 | 138 | public abstract Builder giftCertificates(ArrayList giftCertificates); 139 | 140 | public abstract Builder location(Location location); 141 | 142 | public abstract Builder rating(Double ratingScore); 143 | 144 | public abstract Builder ratingImgUrl(String ratingImgUrl); 145 | 146 | public abstract Builder ratingImgUrlLarge(String ratingImgUrlLarge); 147 | 148 | public abstract Builder ratingImgUrlSmall(String ratingImgUrlSmall); 149 | 150 | public abstract Builder reviews(ArrayList reviews); 151 | 152 | public abstract Business build(); 153 | } 154 | 155 | public static Builder builder() { 156 | return new AutoValue_Business.Builder(); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/Category.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.core.JsonParser; 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import com.fasterxml.jackson.databind.DeserializationContext; 7 | import com.fasterxml.jackson.databind.JsonDeserializer; 8 | import com.fasterxml.jackson.databind.JsonNode; 9 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 10 | import com.google.auto.value.AutoValue; 11 | 12 | import java.io.IOException; 13 | import java.io.Serializable; 14 | 15 | @AutoValue 16 | @JsonIgnoreProperties(ignoreUnknown = true) 17 | @JsonDeserialize(using = CategoryDeserializer.class) 18 | public abstract class Category implements Serializable{ 19 | 20 | public abstract String alias(); 21 | 22 | public abstract String name(); 23 | 24 | @AutoValue.Builder 25 | public abstract static class Builder { 26 | 27 | public abstract Builder alias(String alias); 28 | 29 | public abstract Builder name(String name); 30 | 31 | public abstract Category build(); 32 | } 33 | 34 | public static Builder builder() { 35 | return new AutoValue_Category.Builder(); 36 | } 37 | } 38 | 39 | /** 40 | * Custom deserializer for Category. The JSON string returned for Category is formatted as an array like 41 | * "["Bar", "bar"]" which does not fit into the default Jackson object deserializer which expects "{" as the first 42 | * character. 43 | */ 44 | class CategoryDeserializer extends JsonDeserializer { 45 | @Override 46 | public Category deserialize(JsonParser jsonParser, DeserializationContext context) 47 | throws IOException, JsonProcessingException { 48 | JsonNode node = jsonParser.getCodec().readTree(jsonParser); 49 | String name = node.get(0).textValue(); 50 | String alias = node.get(1).textValue(); 51 | 52 | return Category.builder().name(name).alias(alias).build(); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/Coordinate.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | 10 | import java.io.Serializable; 11 | 12 | @AutoValue 13 | @JsonIgnoreProperties(ignoreUnknown = true) 14 | @JsonDeserialize(builder = AutoValue_Coordinate.Builder.class) 15 | public abstract class Coordinate implements Serializable { 16 | 17 | public abstract Double latitude(); 18 | 19 | public abstract Double longitude(); 20 | 21 | @AutoValue.Builder 22 | @JsonPOJOBuilder(withPrefix = "") 23 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 24 | public abstract static class Builder { 25 | 26 | public abstract Builder latitude(Double latitude); 27 | 28 | public abstract Builder longitude(Double longitude); 29 | 30 | public abstract Coordinate build(); 31 | } 32 | 33 | public static Builder builder() { 34 | return new AutoValue_Coordinate.Builder(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/Deal.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | import java.util.ArrayList; 13 | 14 | @AutoValue 15 | @JsonIgnoreProperties(ignoreUnknown = true) 16 | @JsonDeserialize(builder = AutoValue_Deal.Builder.class) 17 | public abstract class Deal implements Serializable { 18 | 19 | @Nullable 20 | public abstract String additionalRestrictions(); 21 | 22 | @Nullable 23 | public abstract String currencyCode(); 24 | 25 | @Nullable 26 | public abstract String id(); 27 | 28 | @Nullable 29 | public abstract String imageUrl(); 30 | 31 | @Nullable 32 | public abstract String importantRestrictions(); 33 | 34 | @Nullable 35 | public abstract Boolean isPopular(); 36 | 37 | @Nullable 38 | public abstract ArrayList options(); 39 | 40 | @Nullable 41 | public abstract Long timeEnd(); 42 | 43 | @Nullable 44 | public abstract Long timeStart(); 45 | 46 | @Nullable 47 | public abstract String title(); 48 | 49 | @Nullable 50 | public abstract String url(); 51 | 52 | @Nullable 53 | public abstract String whatYouGet(); 54 | 55 | @AutoValue.Builder 56 | @JsonPOJOBuilder(withPrefix = "") 57 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 58 | public abstract static class Builder { 59 | public abstract Builder additionalRestrictions(String additionalRestrictions); 60 | 61 | public abstract Builder currencyCode(String currencyCode); 62 | 63 | public abstract Builder id(String id); 64 | 65 | public abstract Builder imageUrl(String imageUrl); 66 | 67 | public abstract Builder importantRestrictions(String importantRestrictions); 68 | 69 | public abstract Builder isPopular(Boolean isPopular); 70 | 71 | public abstract Builder options(ArrayList options); 72 | 73 | public abstract Builder timeEnd(Long timeEnd); 74 | 75 | public abstract Builder timeStart(Long timeStart); 76 | 77 | public abstract Builder title(String title); 78 | 79 | public abstract Builder url(String url); 80 | 81 | public abstract Builder whatYouGet(String whatYouGet); 82 | 83 | public abstract Deal build(); 84 | } 85 | 86 | public static Builder builder() { 87 | return new AutoValue_Deal.Builder(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/DealOption.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | 13 | @AutoValue 14 | @JsonIgnoreProperties(ignoreUnknown = true) 15 | @JsonDeserialize(builder = AutoValue_DealOption.Builder.class) 16 | public abstract class DealOption implements Serializable { 17 | 18 | @Nullable 19 | public abstract String formattedOriginalPrice(); 20 | 21 | @Nullable 22 | public abstract String formattedPrice(); 23 | 24 | @Nullable 25 | public abstract Boolean isQuantityLimited(); 26 | 27 | @Nullable 28 | public abstract Integer originalPrice(); 29 | 30 | @Nullable 31 | public abstract Integer price(); 32 | 33 | @Nullable 34 | public abstract String purchaseUrl(); 35 | 36 | @Nullable 37 | public abstract Integer remainingCount(); 38 | 39 | @Nullable 40 | public abstract String title(); 41 | 42 | @AutoValue.Builder 43 | @JsonPOJOBuilder(withPrefix = "") 44 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 45 | public abstract static class Builder { 46 | 47 | public abstract Builder formattedOriginalPrice(String formattedOriginalPrice); 48 | 49 | public abstract Builder formattedPrice(String formattedPrice); 50 | 51 | public abstract Builder isQuantityLimited(Boolean isQuantityLimited); 52 | 53 | public abstract Builder originalPrice(Integer originalPrice); 54 | 55 | public abstract Builder price(Integer price); 56 | 57 | public abstract Builder purchaseUrl(String purchaseUrl); 58 | 59 | public abstract Builder remainingCount(Integer remainingCount); 60 | 61 | public abstract Builder title(String title); 62 | 63 | public abstract DealOption build(); 64 | } 65 | 66 | public static Builder builder() { 67 | return new AutoValue_DealOption.Builder(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/GiftCertificate.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | import java.util.ArrayList; 13 | 14 | @AutoValue 15 | @JsonIgnoreProperties(ignoreUnknown = true) 16 | @JsonDeserialize(builder = AutoValue_GiftCertificate.Builder.class) 17 | public abstract class GiftCertificate implements Serializable { 18 | 19 | public abstract String id(); 20 | 21 | @Nullable 22 | public abstract String currencyCode(); 23 | 24 | @Nullable 25 | public abstract String imageUrl(); 26 | 27 | @Nullable 28 | public abstract String unusedBalances(); 29 | 30 | @Nullable 31 | public abstract String url(); 32 | 33 | @Nullable 34 | public abstract ArrayList options(); 35 | 36 | @AutoValue.Builder 37 | @JsonPOJOBuilder(withPrefix = "") 38 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 39 | public abstract static class Builder { 40 | 41 | public abstract Builder currencyCode(String currencyCode); 42 | 43 | public abstract Builder id(String id); 44 | 45 | public abstract Builder imageUrl(String imageUrl); 46 | 47 | public abstract Builder unusedBalances(String unusedBalanced); 48 | 49 | public abstract Builder url(String url); 50 | 51 | public abstract Builder options(ArrayList options); 52 | 53 | public abstract GiftCertificate build(); 54 | } 55 | 56 | public static Builder builder() { 57 | return new AutoValue_GiftCertificate.Builder(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/GiftCertificateOption.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | 13 | @AutoValue 14 | @JsonIgnoreProperties(ignoreUnknown = true) 15 | @JsonDeserialize(builder = AutoValue_GiftCertificateOption.Builder.class) 16 | public abstract class GiftCertificateOption implements Serializable { 17 | 18 | @Nullable 19 | public abstract String formattedPrice(); 20 | 21 | @Nullable 22 | public abstract Integer price(); 23 | 24 | @AutoValue.Builder 25 | @JsonPOJOBuilder(withPrefix = "") 26 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 27 | public abstract static class Builder { 28 | 29 | public abstract Builder formattedPrice(String formattedPrice); 30 | 31 | public abstract Builder price(Integer price); 32 | 33 | public abstract GiftCertificateOption build(); 34 | } 35 | 36 | public static Builder builder() { 37 | return new AutoValue_GiftCertificateOption.Builder(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/Location.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | import java.util.ArrayList; 13 | 14 | @AutoValue 15 | @JsonIgnoreProperties(ignoreUnknown = true) 16 | @JsonDeserialize(builder = AutoValue_Location.Builder.class) 17 | public abstract class Location implements Serializable { 18 | 19 | @Nullable 20 | public abstract ArrayList address(); 21 | 22 | @Nullable 23 | public abstract String city(); 24 | 25 | @Nullable 26 | public abstract Coordinate coordinate(); 27 | 28 | @Nullable 29 | public abstract String countryCode(); 30 | 31 | @Nullable 32 | public abstract String crossStreets(); 33 | 34 | @Nullable 35 | public abstract ArrayList displayAddress(); 36 | 37 | @Nullable 38 | public abstract Double geoAccuracy(); 39 | 40 | @Nullable 41 | public abstract ArrayList neighborhoods(); 42 | 43 | @Nullable 44 | public abstract String postalCode(); 45 | 46 | @Nullable 47 | public abstract String stateCode(); 48 | 49 | @AutoValue.Builder 50 | @JsonPOJOBuilder(withPrefix = "") 51 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 52 | public abstract static class Builder { 53 | 54 | public abstract Builder address(ArrayList address); 55 | 56 | public abstract Builder city(String city); 57 | 58 | public abstract Builder coordinate(Coordinate coordinate); 59 | 60 | public abstract Builder countryCode(String countryCode); 61 | 62 | public abstract Builder crossStreets(String crossStreets); 63 | 64 | public abstract Builder displayAddress(ArrayList displayAddress); 65 | 66 | public abstract Builder geoAccuracy(Double geoAccuracy); 67 | 68 | public abstract Builder neighborhoods(ArrayList neighborhoods); 69 | 70 | public abstract Builder postalCode(String postalCode); 71 | 72 | public abstract Builder stateCode(String stateCode); 73 | 74 | public abstract Location build(); 75 | } 76 | 77 | public static Builder builder() { 78 | return new AutoValue_Location.Builder(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/Region.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | 10 | import java.io.Serializable; 11 | 12 | @AutoValue 13 | @JsonIgnoreProperties(ignoreUnknown = true) 14 | @JsonDeserialize(builder = AutoValue_Region.Builder.class) 15 | public abstract class Region implements Serializable { 16 | 17 | public abstract Coordinate center(); 18 | 19 | public abstract Span span(); 20 | 21 | @AutoValue.Builder 22 | @JsonPOJOBuilder(withPrefix = "") 23 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 24 | public abstract static class Builder { 25 | 26 | public abstract Builder center(Coordinate center); 27 | 28 | public abstract Builder span(Span span); 29 | 30 | public abstract Region build(); 31 | } 32 | 33 | public static Builder builder() { 34 | return new AutoValue_Region.Builder(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/Review.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | 13 | @AutoValue 14 | @JsonIgnoreProperties(ignoreUnknown = true) 15 | @JsonDeserialize(builder = AutoValue_Review.Builder.class) 16 | public abstract class Review implements Serializable { 17 | 18 | public abstract String id(); 19 | 20 | @Nullable 21 | public abstract String excerpt(); 22 | 23 | @Nullable 24 | public abstract Double rating(); 25 | 26 | @Nullable 27 | public abstract String ratingImageUrl(); 28 | 29 | @Nullable 30 | public abstract String ratingImageLargeUrl(); 31 | 32 | @Nullable 33 | public abstract String ratingImageSmallUrl(); 34 | 35 | @Nullable 36 | public abstract Long timeCreated(); 37 | 38 | @Nullable 39 | public abstract User user(); 40 | 41 | @AutoValue.Builder 42 | @JsonPOJOBuilder(withPrefix = "") 43 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 44 | public abstract static class Builder { 45 | 46 | public abstract Builder excerpt(String excerpt); 47 | 48 | public abstract Builder id(String id); 49 | 50 | public abstract Builder rating(Double rating); 51 | 52 | public abstract Builder ratingImageUrl(String ratingImageUrl); 53 | 54 | public abstract Builder ratingImageLargeUrl(String ratingImageLargeUrl); 55 | 56 | public abstract Builder ratingImageSmallUrl(String ratingImageSmallUrl); 57 | 58 | public abstract Builder timeCreated(Long timeCreated); 59 | 60 | public abstract Builder user(User user); 61 | 62 | public abstract Review build(); 63 | } 64 | 65 | public static Builder builder() { 66 | return new AutoValue_Review.Builder(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/SearchResponse.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | import java.util.ArrayList; 13 | 14 | @AutoValue 15 | @JsonIgnoreProperties(ignoreUnknown = true) 16 | @JsonDeserialize(builder = AutoValue_SearchResponse.Builder.class) 17 | public abstract class SearchResponse implements Serializable { 18 | 19 | public abstract ArrayList businesses(); 20 | 21 | @Nullable 22 | public abstract Region region(); 23 | 24 | public abstract Integer total(); 25 | 26 | @AutoValue.Builder 27 | @JsonPOJOBuilder(withPrefix = "") 28 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 29 | public abstract static class Builder { 30 | 31 | public abstract Builder businesses(ArrayList businesses); 32 | 33 | public abstract Builder region(Region region); 34 | 35 | public abstract Builder total(Integer total); 36 | 37 | public abstract SearchResponse build(); 38 | } 39 | 40 | public static Builder builder() { 41 | return new AutoValue_SearchResponse.Builder(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/Span.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | 10 | import java.io.Serializable; 11 | 12 | @AutoValue 13 | @JsonIgnoreProperties(ignoreUnknown = true) 14 | @JsonDeserialize(builder = AutoValue_Span.Builder.class) 15 | public abstract class Span implements Serializable { 16 | 17 | public abstract Double latitudeDelta(); 18 | 19 | public abstract Double longitudeDelta(); 20 | 21 | @AutoValue.Builder 22 | @JsonPOJOBuilder(withPrefix = "") 23 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 24 | public abstract static class Builder { 25 | 26 | public abstract Builder latitudeDelta(Double latitudeDelta); 27 | 28 | public abstract Builder longitudeDelta(Double longitudeDelta); 29 | 30 | public abstract Span build(); 31 | } 32 | 33 | public static Builder builder() { 34 | return new AutoValue_Span.Builder(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/User.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 7 | import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; 8 | import com.google.auto.value.AutoValue; 9 | import com.yelp.clientlib.annotation.Nullable; 10 | 11 | import java.io.Serializable; 12 | 13 | @AutoValue 14 | @JsonIgnoreProperties(ignoreUnknown = true) 15 | @JsonDeserialize(builder = AutoValue_User.Builder.class) 16 | public abstract class User implements Serializable { 17 | 18 | public abstract String id(); 19 | 20 | @Nullable 21 | public abstract String imageUrl(); 22 | 23 | @Nullable 24 | public abstract String name(); 25 | 26 | @AutoValue.Builder 27 | @JsonPOJOBuilder(withPrefix = "") 28 | @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) 29 | public abstract static class Builder { 30 | 31 | public abstract Builder id(String id); 32 | 33 | public abstract Builder imageUrl(String imageUrl); 34 | 35 | public abstract Builder name(String name); 36 | 37 | public abstract User build(); 38 | } 39 | 40 | public static Builder builder() { 41 | return new AutoValue_User.Builder(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/options/BoundingBoxOptions.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities.options; 2 | 3 | import com.google.auto.value.AutoValue; 4 | 5 | import java.util.Locale; 6 | 7 | @AutoValue 8 | public abstract class BoundingBoxOptions { 9 | 10 | /** 11 | * @return Southwest latitude of bounding box. 12 | */ 13 | public abstract Double swLatitude(); 14 | 15 | /** 16 | * @return Southwest longitude of bounding box. 17 | */ 18 | public abstract Double swLongitude(); 19 | 20 | /** 21 | * @return Northeast latitude of bounding box. 22 | */ 23 | public abstract Double neLatitude(); 24 | 25 | /** 26 | * @return Northeast longitude of bounding box. 27 | */ 28 | public abstract Double neLongitude(); 29 | 30 | /** 31 | * String presentation for {@link BoundingBoxOptions}. The generated string is encoded as 32 | * "swLatitude,swLongitude%7CneLatitude,neLongitude". This method is used by {@link retrofit2.http.Query} to 33 | * generate the values of query parameters. 34 | * 35 | * BoundingBox query param value contains non-suggested URI character '|' which doesn't fit into most of the 36 | * signature functions, we encode it here into "%7C" so it's not passed through http client. 37 | * 38 | * @return String presentation for {@link BoundingBoxOptions} 39 | * @see https://www.yelp.com/developers/documentation/v2/search_api#searchGBB 40 | */ 41 | @Override 42 | public String toString() { 43 | return String.format( 44 | Locale.getDefault(), 45 | "%f,%f%%7C%f,%f", swLatitude(), swLongitude(), neLatitude(), neLongitude() 46 | ); 47 | } 48 | 49 | @AutoValue.Builder 50 | public abstract static class Builder { 51 | 52 | /** 53 | * @param latitude Sets southwest latitude. 54 | * 55 | * @return this 56 | */ 57 | public abstract Builder swLatitude(Double latitude); 58 | 59 | /** 60 | * @param longitude Sets southwest longitude. 61 | * 62 | * @return this 63 | */ 64 | public abstract Builder swLongitude(Double longitude); 65 | 66 | /** 67 | * @param latitude Sets northeast latitude. 68 | * 69 | * @return this 70 | */ 71 | public abstract Builder neLatitude(Double latitude); 72 | 73 | /** 74 | * @param longitude Sets northeast longitude. 75 | * 76 | * @return this 77 | */ 78 | public abstract Builder neLongitude(Double longitude); 79 | 80 | /** 81 | * Returns a reference to the object of {@link BoundingBoxOptions} being constructed by the builder. 82 | * 83 | * @return the {@link BoundingBoxOptions} constructed by the builder. 84 | */ 85 | public abstract BoundingBoxOptions build(); 86 | } 87 | 88 | public static Builder builder() { 89 | return new AutoValue_BoundingBoxOptions.Builder(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/entities/options/CoordinateOptions.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities.options; 2 | 3 | import com.google.auto.value.AutoValue; 4 | import com.yelp.clientlib.annotation.Nullable; 5 | 6 | @AutoValue 7 | public abstract class CoordinateOptions { 8 | 9 | /** 10 | * @return Latitude of geo-point to search near. 11 | */ 12 | public abstract Double latitude(); 13 | 14 | /** 15 | * @return Longitude of geo-point to search near. 16 | */ 17 | public abstract Double longitude(); 18 | 19 | /** 20 | * @return Optional accuracy of latitude, longitude. 21 | */ 22 | @Nullable 23 | public abstract Double accuracy(); 24 | 25 | /** 26 | * @return Optional altitude of geo-point to search near. 27 | */ 28 | @Nullable 29 | public abstract Double altitude(); 30 | 31 | /** 32 | * @return Optional accuracy of altitude. 33 | */ 34 | @Nullable 35 | public abstract Double altitudeAccuracy(); 36 | 37 | /** 38 | * String presentation for {@code CoordinateOptions}. The generated string is comma separated. It is encoded in the 39 | * order of latitude, longitude, accuracy, altitude and altitudeAccuracy. This method is used by {@code retrofit 40 | * .http.QueryMap} to generate the values of query parameters. 41 | * 42 | * @return String presentation for {@code CoordinateOptions} 43 | */ 44 | @Override 45 | public String toString() { 46 | Double[] optionalFields = new Double[]{accuracy(), altitude(), altitudeAccuracy()}; 47 | 48 | String coordinate = latitude() + "," + longitude(); 49 | for (Double field : optionalFields) { 50 | coordinate = String.format("%s,%s", coordinate, (field == null) ? "" : field.toString()); 51 | } 52 | 53 | return coordinate; 54 | } 55 | 56 | @AutoValue.Builder 57 | public abstract static class Builder { 58 | 59 | /** 60 | * @param latitude Sets latitude. 61 | * 62 | * @return this 63 | */ 64 | public abstract Builder latitude(Double latitude); 65 | 66 | /** 67 | * @param longitude Sets longitude. 68 | * 69 | * @return this 70 | */ 71 | public abstract Builder longitude(Double longitude); 72 | 73 | /** 74 | * @param accuracy Sets accuracy of latitude, longitude. 75 | * 76 | * @return this 77 | */ 78 | public abstract Builder accuracy(Double accuracy); 79 | 80 | /** 81 | * @param altitude Sets altitude. 82 | * 83 | * @return this 84 | */ 85 | public abstract Builder altitude(Double altitude); 86 | 87 | /** 88 | * @param altitudeAccuracy Sets accuracy of altitude. 89 | * 90 | * @return this 91 | */ 92 | public abstract Builder altitudeAccuracy(Double altitudeAccuracy); 93 | 94 | /** 95 | * Returns a reference to the object of {@code CoordinateOptions} being constructed by the builder. 96 | * 97 | * @return the {@code CoordinateOptions} constructed by the builder. 98 | */ 99 | public abstract CoordinateOptions build(); 100 | } 101 | 102 | public static Builder builder() { 103 | return new AutoValue_CoordinateOptions.Builder(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/ErrorHandlingInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import okhttp3.Interceptor; 6 | import okhttp3.Response; 7 | import com.yelp.clientlib.exception.exceptions.AreaTooLarge; 8 | import com.yelp.clientlib.exception.exceptions.BadCategory; 9 | import com.yelp.clientlib.exception.exceptions.BusinessUnavailable; 10 | import com.yelp.clientlib.exception.exceptions.ExceededReqs; 11 | import com.yelp.clientlib.exception.exceptions.InternalError; 12 | import com.yelp.clientlib.exception.exceptions.InvalidOAuthCredentials; 13 | import com.yelp.clientlib.exception.exceptions.InvalidOAuthUser; 14 | import com.yelp.clientlib.exception.exceptions.InvalidParameter; 15 | import com.yelp.clientlib.exception.exceptions.InvalidSignature; 16 | import com.yelp.clientlib.exception.exceptions.MissingParameter; 17 | import com.yelp.clientlib.exception.exceptions.MultipleLocations; 18 | import com.yelp.clientlib.exception.exceptions.SSLRequired; 19 | import com.yelp.clientlib.exception.exceptions.UnavailableForLocation; 20 | import com.yelp.clientlib.exception.exceptions.UnexpectedAPIError; 21 | import com.yelp.clientlib.exception.exceptions.UnspecifiedLocation; 22 | import com.yelp.clientlib.exception.exceptions.YelpAPIError; 23 | 24 | import java.io.IOException; 25 | 26 | /** 27 | * {@link Interceptor} to parse and transform the HTTP errors. 28 | */ 29 | public class ErrorHandlingInterceptor implements Interceptor { 30 | 31 | private static final ObjectMapper objectMapper = new ObjectMapper(); 32 | 33 | /** 34 | * Intercept HTTP responses and raise a {@link YelpAPIError} if the response code is not 2xx. 35 | * 36 | * @param chain {@link okhttp3.Interceptor.Chain} object for sending the HTTP request. 37 | * @return response 38 | * @throws IOException {@link YelpAPIError} generated depends on the response error id. 39 | */ 40 | @Override 41 | public Response intercept(Chain chain) throws IOException { 42 | Response response = chain.proceed(chain.request()); 43 | 44 | if (!response.isSuccessful()) { 45 | throw parseError( 46 | response.code(), 47 | response.message(), 48 | response.body() != null ? response.body().string() : null 49 | ); 50 | } 51 | return response; 52 | } 53 | 54 | private YelpAPIError parseError(int code, String message, String responseBody) throws IOException { 55 | if (responseBody == null) { 56 | return new UnexpectedAPIError(code, message); 57 | } 58 | 59 | JsonNode errorJsonNode = objectMapper.readTree(responseBody).path("error"); 60 | String errorId = errorJsonNode.path("id").asText(); 61 | String errorText = errorJsonNode.path("text").asText(); 62 | 63 | if (errorJsonNode.has("field")) { 64 | errorText += ": " + errorJsonNode.path("field").asText(); 65 | } 66 | 67 | switch (errorId) { 68 | case "AREA_TOO_LARGE": 69 | return new AreaTooLarge(code, message, errorId, errorText); 70 | case "BAD_CATEGORY": 71 | return new BadCategory(code, message, errorId, errorText); 72 | case "BUSINESS_UNAVAILABLE": 73 | return new BusinessUnavailable(code, message, errorId, errorText); 74 | case "EXCEEDED_REQS": 75 | return new ExceededReqs(code, message, errorId, errorText); 76 | case "INTERNAL_ERROR": 77 | return new InternalError(code, message, errorId, errorText); 78 | case "INVALID_OAUTH_CREDENTIALS": 79 | return new InvalidOAuthCredentials(code, message, errorId, errorText); 80 | case "INVALID_OAUTH_USER": 81 | return new InvalidOAuthUser(code, message, errorId, errorText); 82 | case "INVALID_PARAMETER": 83 | return new InvalidParameter(code, message, errorId, errorText); 84 | case "INVALID_SIGNATURE": 85 | return new InvalidSignature(code, message, errorId, errorText); 86 | case "MISSING_PARAMETER": 87 | return new MissingParameter(code, message, errorId, errorText); 88 | case "MULTIPLE_LOCATIONS": 89 | return new MultipleLocations(code, message, errorId, errorText); 90 | case "SSL_REQUIRED": 91 | return new SSLRequired(code, message, errorId, errorText); 92 | case "UNAVAILABLE_FOR_LOCATION": 93 | return new UnavailableForLocation(code, message, errorId, errorText); 94 | case "UNSPECIFIED_LOCATION": 95 | return new UnspecifiedLocation(code, message, errorId, errorText); 96 | default: 97 | return new UnexpectedAPIError(code, message, errorId, errorText); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/AreaTooLarge.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class AreaTooLarge extends YelpAPIError { 4 | public AreaTooLarge(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/BadCategory.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class BadCategory extends YelpAPIError { 4 | public BadCategory(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/BusinessUnavailable.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class BusinessUnavailable extends YelpAPIError { 4 | public BusinessUnavailable(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/ExceededReqs.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class ExceededReqs extends YelpAPIError { 4 | public ExceededReqs(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/InternalError.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class InternalError extends YelpAPIError { 4 | public InternalError(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/InvalidOAuthCredentials.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class InvalidOAuthCredentials extends YelpAPIError { 4 | public InvalidOAuthCredentials(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/InvalidOAuthUser.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class InvalidOAuthUser extends YelpAPIError { 4 | public InvalidOAuthUser(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/InvalidParameter.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class InvalidParameter extends YelpAPIError { 4 | public InvalidParameter(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/InvalidSignature.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class InvalidSignature extends YelpAPIError { 4 | public InvalidSignature(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/MissingParameter.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class MissingParameter extends YelpAPIError { 4 | public MissingParameter(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/MultipleLocations.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class MultipleLocations extends YelpAPIError { 4 | public MultipleLocations(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/SSLRequired.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class SSLRequired extends YelpAPIError { 4 | public SSLRequired(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/UnavailableForLocation.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class UnavailableForLocation extends YelpAPIError { 4 | public UnavailableForLocation(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/UnexpectedAPIError.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class UnexpectedAPIError extends YelpAPIError { 4 | public UnexpectedAPIError(int code, String message) { 5 | this(code, message, null, null); 6 | } 7 | 8 | public UnexpectedAPIError(int code, String message, String id, String text) { 9 | super(code, message, id, text); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/UnspecifiedLocation.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | public class UnspecifiedLocation extends YelpAPIError { 4 | public UnspecifiedLocation(int code, String message, String id, String text) { 5 | super(code, message, id, text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/yelp/clientlib/exception/exceptions/YelpAPIError.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception.exceptions; 2 | 3 | import java.io.IOException; 4 | 5 | public abstract class YelpAPIError extends IOException { 6 | private int code; 7 | private String message; 8 | private String text; 9 | private String errorId; 10 | 11 | public int getCode() { 12 | return code; 13 | } 14 | 15 | @Override 16 | public String getMessage() { 17 | return message; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public String getErrorId() { 25 | return errorId; 26 | } 27 | 28 | public YelpAPIError(int code, String message, String errorId, String text) { 29 | this.code = code; 30 | this.message = message; 31 | this.errorId = errorId; 32 | this.text = text; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/connection/YelpAPITest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.connection; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import okhttp3.mockwebserver.MockResponse; 5 | import okhttp3.mockwebserver.MockWebServer; 6 | import okhttp3.mockwebserver.RecordedRequest; 7 | import com.yelp.clientlib.entities.Business; 8 | import com.yelp.clientlib.utils.JsonTestUtils; 9 | import com.yelp.clientlib.entities.SearchResponse; 10 | import com.yelp.clientlib.entities.options.BoundingBoxOptions; 11 | import com.yelp.clientlib.entities.options.CoordinateOptions; 12 | import com.yelp.clientlib.exception.exceptions.BusinessUnavailable; 13 | import com.yelp.clientlib.utils.AsyncTestUtils; 14 | import com.yelp.clientlib.utils.ErrorTestUtils; 15 | 16 | import org.junit.After; 17 | import org.junit.Assert; 18 | import org.junit.Before; 19 | import org.junit.Test; 20 | 21 | import java.io.IOException; 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | import retrofit2.Call; 27 | import retrofit2.Callback; 28 | import retrofit2.Response; 29 | 30 | public class YelpAPITest { 31 | private MockWebServer mockServer; 32 | private YelpAPI yelpAPI; 33 | private JsonNode businessJsonNode; 34 | private JsonNode searchResponseJsonNode; 35 | 36 | @Before 37 | public void setup() throws IOException { 38 | mockServer = new MockWebServer(); 39 | mockServer.start(); 40 | 41 | // Use TestAPIFactory so the requests are sent to the mock web server. 42 | YelpAPIFactory yelpAPIFactory = new TestAPIFactory( 43 | "consumerKey", 44 | "consumerSecret", 45 | "token", 46 | "tokenSecret", 47 | mockServer.url("/").toString() 48 | ); 49 | 50 | // Make API requests to be executed in main thread so we can verify it easily. 51 | yelpAPIFactory = AsyncTestUtils.setToRunInMainThread(yelpAPIFactory); 52 | 53 | yelpAPI = yelpAPIFactory.createAPI(); 54 | 55 | businessJsonNode = JsonTestUtils.getBusinessResponseJsonNode(); 56 | searchResponseJsonNode = JsonTestUtils.getSearchResponseJsonNode(); 57 | } 58 | 59 | @After 60 | public void teardown() throws IOException { 61 | mockServer.shutdown(); 62 | } 63 | 64 | @Test 65 | public void testGetBusiness() throws IOException, InterruptedException { 66 | String testBusinessId = "test-business-id"; 67 | setUpMockServerResponse(200, "OK", businessJsonNode.toString()); 68 | 69 | Call call = yelpAPI.getBusiness(testBusinessId); 70 | Business business = call.execute().body(); 71 | 72 | verifyRequestForGetBusiness(testBusinessId); 73 | verifyResponseDeserializationForGetBusiness(business); 74 | } 75 | 76 | @Test 77 | public void testGetBusinessAsynchronous() throws InterruptedException { 78 | String testBusinessId = "test-business-id"; 79 | setUpMockServerResponse(200, "OK", businessJsonNode.toString()); 80 | 81 | final ArrayList returnedBusinessWrapper = new ArrayList<>(); 82 | Callback businessCallback = new Callback() { 83 | @Override 84 | public void onResponse(Call call, Response response) { 85 | returnedBusinessWrapper.add(response.body()); 86 | } 87 | 88 | @Override 89 | public void onFailure(Call call, Throwable t) { 90 | Assert.fail("Unexpected failure: " + t.toString()); 91 | } 92 | }; 93 | 94 | Call call = yelpAPI.getBusiness(testBusinessId); 95 | call.enqueue(businessCallback); 96 | 97 | verifyRequestForGetBusiness(testBusinessId); 98 | verifyResponseDeserializationForGetBusiness(returnedBusinessWrapper.get(0)); 99 | } 100 | 101 | @Test 102 | public void testGetBusinessWithParams() throws IOException, InterruptedException { 103 | setUpMockServerResponse(200, "OK", businessJsonNode.toString()); 104 | 105 | String testBusinessId = "test-business-id"; 106 | Map params = new HashMap<>(); 107 | params.put("cc", "US"); 108 | params.put("lang", "en"); 109 | params.put("lang_filter", "true"); 110 | params.put("actionlinks", "true"); 111 | 112 | Call call = yelpAPI.getBusiness(testBusinessId, params); 113 | Business business = call.execute().body(); 114 | 115 | verifyRequestForGetBusiness(testBusinessId, params); 116 | verifyResponseDeserializationForGetBusiness(business); 117 | } 118 | 119 | @Test 120 | public void testGetBusinessParamsBeURLEncoded() throws IOException, InterruptedException { 121 | setUpMockServerResponse(200, "OK", businessJsonNode.toString()); 122 | 123 | String testBusinessId = "test-business-id"; 124 | Map params = new HashMap<>(); 125 | String key = "the key"; 126 | String value = "the value"; 127 | params.put(key, value); 128 | String expectedEncodedParamString = "the%20key=the%20value"; 129 | 130 | Call call = yelpAPI.getBusiness(testBusinessId, params); 131 | call.execute().body(); 132 | 133 | RecordedRequest recordedRequest = mockServer.takeRequest(); 134 | Assert.assertTrue(recordedRequest.getPath().contains(expectedEncodedParamString)); 135 | } 136 | 137 | @Test 138 | public void testGetBusinessWithEmptyParams() throws IOException, InterruptedException { 139 | setUpMockServerResponse(200, "OK", businessJsonNode.toString()); 140 | 141 | String testBusinessId = "test-business-id"; 142 | Call call = yelpAPI.getBusiness(testBusinessId, new HashMap()); 143 | Business business = call.execute().body(); 144 | 145 | verifyRequestForGetBusiness(testBusinessId); 146 | verifyResponseDeserializationForGetBusiness(business); 147 | } 148 | 149 | @Test(expected = IllegalArgumentException.class) 150 | public void testGetBusinessWithNullParams() throws IOException, InterruptedException { 151 | Call call = yelpAPI.getBusiness("test-business-id", null); 152 | call.execute().body(); 153 | } 154 | 155 | @Test 156 | public void testGetPhoneSearch() throws IOException, InterruptedException { 157 | String testPhone = "1234567899"; 158 | setUpMockServerResponse(200, "OK", searchResponseJsonNode.toString()); 159 | 160 | Call call = yelpAPI.getPhoneSearch(testPhone); 161 | SearchResponse searchResponse = call.execute().body(); 162 | 163 | verifyRequestForGetPhoneSearch(testPhone); 164 | verifyResponseDeserializationForSearchResponse(searchResponse); 165 | } 166 | 167 | @Test 168 | public void testGetPhoneSearchAsynchronous() throws InterruptedException { 169 | String testPhone = "1234567899"; 170 | setUpMockServerResponse(200, "OK", searchResponseJsonNode.toString()); 171 | 172 | final ArrayList responseWrapper = new ArrayList<>(); 173 | Callback businessCallback = new Callback() { 174 | 175 | @Override 176 | public void onResponse(Call call, Response response) { 177 | responseWrapper.add(response.body()); 178 | } 179 | 180 | @Override 181 | public void onFailure(Call call, Throwable t) { 182 | Assert.fail("Unexpected failure: " + t.toString()); 183 | } 184 | }; 185 | 186 | Call call = yelpAPI.getPhoneSearch(testPhone); 187 | call.enqueue(businessCallback); 188 | 189 | verifyRequestForGetPhoneSearch(testPhone); 190 | verifyResponseDeserializationForSearchResponse(responseWrapper.get(0)); 191 | } 192 | 193 | @Test 194 | public void testGetPhoneSearchWithParams() throws IOException, InterruptedException { 195 | setUpMockServerResponse(200, "OK", searchResponseJsonNode.toString()); 196 | 197 | String testPhone = "1234567899"; 198 | Map params = new HashMap<>(); 199 | params.put("category", "restaurant"); 200 | params.put("cc", "US"); 201 | 202 | Call call = yelpAPI.getPhoneSearch(testPhone, params); 203 | SearchResponse searchResponse = call.execute().body(); 204 | 205 | verifyRequestForGetPhoneSearch(testPhone, params); 206 | verifyResponseDeserializationForSearchResponse(searchResponse); 207 | } 208 | 209 | @Test 210 | public void testGetPhoneSearchWithEmptyParams() throws IOException, InterruptedException { 211 | setUpMockServerResponse(200, "OK", searchResponseJsonNode.toString()); 212 | 213 | String testPhone = "1234567899"; 214 | Map params = new HashMap<>(); 215 | 216 | Call call = yelpAPI.getPhoneSearch(testPhone, params); 217 | SearchResponse searchResponse = call.execute().body(); 218 | 219 | verifyRequestForGetPhoneSearch(testPhone); 220 | verifyResponseDeserializationForSearchResponse(searchResponse); 221 | } 222 | 223 | @Test(expected = IllegalArgumentException.class) 224 | public void testGetPhoneSearchWithNullParams() throws IOException, InterruptedException { 225 | Call call = yelpAPI.getPhoneSearch("1234567899", null); 226 | call.execute().body(); 227 | } 228 | 229 | @Test 230 | public void testGetBusiness400Response() throws IOException, InterruptedException { 231 | String testBusinessId = "test-business-id"; 232 | String errorResponseBodyString = JsonTestUtils.getJsonNodeFromFile("sampleFailureResponse.json").toString(); 233 | setUpMockServerResponse(400, "Bad Request", errorResponseBodyString); 234 | 235 | Call call = yelpAPI.getBusiness(testBusinessId); 236 | try { 237 | call.execute().body(); 238 | } catch (BusinessUnavailable e) { 239 | ErrorTestUtils.verifyErrorContent( 240 | e, 241 | 400, 242 | "Bad Request", 243 | "BUSINESS_UNAVAILABLE", 244 | "Business information is unavailable" 245 | ); 246 | } 247 | } 248 | 249 | @Test 250 | public void testSearchByLocation() throws IOException, InterruptedException { 251 | setUpMockServerResponse(200, "OK", searchResponseJsonNode.toString()); 252 | 253 | Map params = new HashMap<>(); 254 | params.put("term", "yelp"); 255 | 256 | Call call = yelpAPI.search("Boston", params); 257 | SearchResponse searchResponse = call.execute().body(); 258 | 259 | Map expectedCalledParams = new HashMap<>(params); 260 | expectedCalledParams.put("location", "Boston"); 261 | 262 | verifyRequestForSearch(expectedCalledParams); 263 | verifyResponseDeserializationForSearchResponse(searchResponse); 264 | } 265 | 266 | @Test 267 | public void testSearchByCoordinateOptions() throws IOException, InterruptedException { 268 | setUpMockServerResponse(200, "OK", searchResponseJsonNode.toString()); 269 | 270 | Map params = new HashMap<>(); 271 | params.put("term", "yelp"); 272 | 273 | CoordinateOptions coordinate = CoordinateOptions.builder() 274 | .latitude(11.111111) 275 | .longitude(22.222222) 276 | .build(); 277 | 278 | Call call = yelpAPI.search(coordinate, params); 279 | SearchResponse searchResponse = call.execute().body(); 280 | 281 | Map expectedCalledParams = new HashMap<>(params); 282 | expectedCalledParams.put("ll", "11.111111,22.222222"); 283 | verifyRequestForSearch(expectedCalledParams); 284 | verifyResponseDeserializationForSearchResponse(searchResponse); 285 | } 286 | 287 | @Test 288 | public void testSearchByBoundingBoxOptions() throws IOException, InterruptedException { 289 | setUpMockServerResponse(200, "OK", searchResponseJsonNode.toString()); 290 | 291 | Map params = new HashMap<>(); 292 | params.put("term", "yelp"); 293 | 294 | BoundingBoxOptions bounds = BoundingBoxOptions.builder() 295 | .swLatitude(11.111111) 296 | .swLongitude(22.222222) 297 | .neLatitude(33.333333) 298 | .neLongitude(44.444444) 299 | .build(); 300 | 301 | Call call = yelpAPI.search(bounds, params); 302 | SearchResponse searchResponse = call.execute().body(); 303 | 304 | Map expectedCalledParams = new HashMap<>(params); 305 | expectedCalledParams.put("bounds", "11.111111,22.222222%7C33.333333,44.444444"); 306 | verifyRequestForSearch(expectedCalledParams); 307 | verifyResponseDeserializationForSearchResponse(searchResponse); 308 | } 309 | 310 | private void setUpMockServerResponse(int responseCode, String responseMessage, String responseBody) { 311 | MockResponse mockResponse = new MockResponse() 312 | .addHeader("Content-Type", "application/json; charset=utf-8") 313 | .setBody(responseBody) 314 | .setStatus(String.format("HTTP/1.1 %s %s", responseCode, responseMessage)); 315 | mockServer.enqueue(mockResponse); 316 | } 317 | 318 | private void verifyRequestForGetBusiness(String businessId) throws InterruptedException { 319 | verifyRequestForGetBusiness(businessId, null); 320 | } 321 | 322 | private void verifyRequestForGetBusiness(String businessId, Map params) 323 | throws InterruptedException { 324 | verifyRequest("/v2/business/" + businessId, params); 325 | } 326 | 327 | private void verifyRequestForGetPhoneSearch(String phone) throws InterruptedException { 328 | verifyRequestForGetPhoneSearch(phone, null); 329 | } 330 | 331 | private void verifyRequestForGetPhoneSearch(String phone, Map params) throws InterruptedException { 332 | params = (params == null) ? new HashMap() : new HashMap<>(params); 333 | params.put("phone", phone); 334 | 335 | verifyRequest("/v2/phone_search", params); 336 | } 337 | 338 | private void verifyRequestForSearch(Map params) throws InterruptedException { 339 | verifyRequest("/v2/search", params); 340 | } 341 | 342 | private void verifyRequest(String pathPrefix, Map params) throws InterruptedException { 343 | RecordedRequest recordedRequest = mockServer.takeRequest(); 344 | verifyAuthorizationHeader(recordedRequest.getHeaders().get("Authorization")); 345 | 346 | Assert.assertEquals("GET", recordedRequest.getMethod()); 347 | 348 | String path = recordedRequest.getPath(); 349 | Assert.assertTrue(path.startsWith(pathPrefix)); 350 | if (params != null) { 351 | for (Map.Entry param : params.entrySet()) { 352 | Assert.assertTrue(path.contains(param.getKey() + "=" + param.getValue())); 353 | } 354 | } 355 | 356 | Assert.assertEquals(0, recordedRequest.getBodySize()); 357 | } 358 | 359 | private void verifyResponseDeserializationForGetBusiness(Business business) { 360 | Assert.assertEquals(businessJsonNode.path("id").textValue(), business.id()); 361 | } 362 | 363 | private void verifyResponseDeserializationForSearchResponse(SearchResponse searchResponse) { 364 | Assert.assertEquals(new Integer(searchResponseJsonNode.path("total").asInt()), searchResponse.total()); 365 | } 366 | 367 | private void verifyAuthorizationHeader(String authHeader) { 368 | Assert.assertNotNull(authHeader); 369 | Assert.assertTrue(authHeader.contains("oauth_consumer_key")); 370 | Assert.assertTrue(authHeader.contains("oauth_nonce")); 371 | Assert.assertTrue(authHeader.contains("oauth_signature_method")); 372 | Assert.assertTrue(authHeader.contains("oauth_signature")); 373 | Assert.assertTrue(authHeader.contains("oauth_timestamp")); 374 | } 375 | 376 | /** 377 | * APIFactory which API base url can be set. Set apiBaseUrl to a mocked web server so requests are directed to it. 378 | */ 379 | class TestAPIFactory extends YelpAPIFactory { 380 | private String apiBaseUrl; 381 | 382 | public TestAPIFactory( 383 | String consumerKey, 384 | String consumerSecret, 385 | String token, 386 | String tokenSecret, 387 | String apiBaseUrl 388 | ) { 389 | super(consumerKey, consumerSecret, token, tokenSecret); 390 | this.apiBaseUrl = apiBaseUrl; 391 | } 392 | 393 | @Override 394 | public String getAPIBaseUrl() { 395 | return apiBaseUrl; 396 | } 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/BusinessTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonMappingException; 4 | import com.fasterxml.jackson.databind.JsonNode; 5 | import com.yelp.clientlib.utils.JsonTestUtils; 6 | import com.yelp.clientlib.utils.SerializationTestUtils; 7 | 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | 11 | import java.io.IOException; 12 | 13 | public class BusinessTest { 14 | 15 | @Test 16 | public void testDeserializeFromJson() throws IOException { 17 | JsonNode businessNode = JsonTestUtils.getBusinessResponseJsonNode(); 18 | Business business = JsonTestUtils.deserializeJson(businessNode.toString(), Business.class); 19 | 20 | Assert.assertEquals(businessNode.path("display_phone").textValue(), business.displayPhone()); 21 | Assert.assertEquals(businessNode.path("eat24_url").textValue(), business.eat24Url()); 22 | Assert.assertEquals(businessNode.path("id").textValue(), business.id()); 23 | Assert.assertEquals(businessNode.path("image_url").textValue(), business.imageUrl()); 24 | Assert.assertEquals(businessNode.path("is_claimed").asBoolean(), business.isClaimed()); 25 | Assert.assertEquals(businessNode.path("is_closed").asBoolean(), business.isClosed()); 26 | Assert.assertEquals(new Long(businessNode.path("menu_date_updated").asLong()), business.menuDateUpdated()); 27 | Assert.assertEquals(businessNode.path("menu_provider").textValue(), business.menuProvider()); 28 | Assert.assertEquals(businessNode.path("mobile_url").textValue(), business.mobileUrl()); 29 | Assert.assertEquals(businessNode.path("name").textValue(), business.name()); 30 | Assert.assertEquals(businessNode.path("phone").textValue(), business.phone()); 31 | Assert.assertEquals(businessNode.path("reservation_url").textValue(), business.reservationUrl()); 32 | Assert.assertEquals(new Double(businessNode.path("rating").asDouble()), business.rating()); 33 | Assert.assertEquals(businessNode.path("rating_img_url").textValue(), business.ratingImgUrl()); 34 | Assert.assertEquals(businessNode.path("rating_img_url_large").textValue(), business.ratingImgUrlLarge()); 35 | Assert.assertEquals(businessNode.path("rating_img_url_small").textValue(), business.ratingImgUrlSmall()); 36 | Assert.assertEquals(new Integer(businessNode.path("review_count").asInt()), business.reviewCount()); 37 | Assert.assertEquals(businessNode.path("snippet_image_url").textValue(), business.snippetImageUrl()); 38 | Assert.assertEquals(businessNode.path("snippet_text").textValue(), business.snippetText()); 39 | Assert.assertEquals(businessNode.path("url").textValue(), business.url()); 40 | 41 | // The following objects are tested in their own tests. 42 | Assert.assertNotNull(business.categories()); 43 | Assert.assertNotNull(business.deals()); 44 | Assert.assertNotNull(business.giftCertificates()); 45 | Assert.assertNotNull(business.location()); 46 | Assert.assertNotNull(business.reviews()); 47 | 48 | } 49 | 50 | @Test 51 | public void testDeserializationWithMissingNullableAttribute() throws IOException { 52 | String businessJsonString = "{\"name\":\"Yelp\", \"id\":\"yelp-san-francisco\"}"; 53 | Business business = JsonTestUtils.deserializeJson(businessJsonString, Business.class); 54 | Assert.assertEquals("Yelp", business.name()); 55 | Assert.assertEquals("yelp-san-francisco", business.id()); 56 | Assert.assertNull(business.displayPhone()); 57 | } 58 | 59 | @Test 60 | public void testDeserializationWithUTF8Characters() throws IOException { 61 | String businessJsonString = "{\"name\":\"Gööd Füsiön Fööd\", \"id\":\"gööd-füsiön-fööd-san-francisco\"}"; 62 | Business business = JsonTestUtils.deserializeJson(businessJsonString, Business.class); 63 | Assert.assertEquals("Gööd Füsiön Fööd", business.name()); 64 | Assert.assertEquals("gööd-füsiön-fööd-san-francisco", business.id()); 65 | } 66 | 67 | @Test 68 | public void testDeserializationWithNoReviewBusinessHasNullForReview() throws IOException { 69 | JsonNode businessNode = JsonTestUtils.getJsonNodeFromFile("noReviewBusinessResponse.json"); 70 | Business business = JsonTestUtils.deserializeJson(businessNode.toString(), Business.class); 71 | Assert.assertNull(business.reviews()); 72 | Assert.assertEquals(new Integer(0), business.reviewCount()); 73 | Assert.assertEquals(businessNode.path("id").textValue(), business.id()); 74 | Assert.assertEquals(businessNode.path("rating_img_url").textValue(), business.ratingImgUrl()); 75 | Assert.assertEquals(businessNode.path("rating_img_url_small").textValue(), business.ratingImgUrlSmall()); 76 | } 77 | 78 | @Test(expected = JsonMappingException.class) 79 | public void testDeserializationFailedWithMissingAttributes() throws IOException { 80 | String businessJsonString = "{\"name\":\"Yelp\"}"; 81 | JsonTestUtils.deserializeJson(businessJsonString, Business.class); 82 | } 83 | 84 | @Test 85 | public void testSerializable() throws IOException, ClassNotFoundException { 86 | JsonNode businessNode = JsonTestUtils.getBusinessResponseJsonNode(); 87 | Business business = JsonTestUtils.deserializeJson(businessNode.toString(), Business.class); 88 | 89 | byte[] bytes = SerializationTestUtils.serialize(business); 90 | Assert.assertEquals(business, SerializationTestUtils.deserialize(bytes, Business.class)); 91 | } 92 | 93 | @Test 94 | public void testBuildWithNullableAttributesNotSet() throws IOException { 95 | Business.builder().name("Yelp").id("yelp-san-francisco").build(); 96 | } 97 | 98 | @Test(expected = IllegalStateException.class) 99 | public void testBuildFailedWithMissingId() throws IOException { 100 | Business.builder().name("Yelp").build(); 101 | } 102 | 103 | @Test(expected = IllegalStateException.class) 104 | public void testBuildFailedWithMissingName() throws IOException { 105 | Business.builder().id("yelp-san-francisco").build(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/CategoryTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonMappingException; 4 | import com.fasterxml.jackson.databind.JsonNode; 5 | import com.yelp.clientlib.utils.JsonTestUtils; 6 | import com.yelp.clientlib.utils.SerializationTestUtils; 7 | 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | 11 | import java.io.IOException; 12 | 13 | public class CategoryTest { 14 | 15 | @Test 16 | public void testDeserializeFromJson() throws IOException { 17 | JsonNode categoryNode = JsonTestUtils.getBusinessResponseJsonNode().path("categories").get(0); 18 | Category category = JsonTestUtils.deserializeJson(categoryNode.toString(), Category.class); 19 | 20 | Assert.assertEquals(categoryNode.get(0).textValue(), category.name()); 21 | Assert.assertEquals(categoryNode.get(1).textValue(), category.alias()); 22 | } 23 | 24 | @Test(expected = JsonMappingException.class) 25 | public void testDeserializationFailedWithNonPairedValue() throws IOException { 26 | String categoryJsonString = "[\"Restaurant\"]"; 27 | JsonTestUtils.deserializeJson(categoryJsonString, Business.class); 28 | } 29 | 30 | @Test 31 | public void testSerializable() throws IOException, ClassNotFoundException { 32 | JsonNode categoryNode = JsonTestUtils.getBusinessResponseJsonNode().path("categories").get(0); 33 | Category category = JsonTestUtils.deserializeJson(categoryNode.toString(), Category.class); 34 | 35 | byte[] bytes = SerializationTestUtils.serialize(category); 36 | Assert.assertEquals(category, SerializationTestUtils.deserialize(bytes, Category.class)); 37 | } 38 | 39 | @Test(expected = IllegalStateException.class) 40 | public void testBuildFailedWithNoAlias() throws IOException { 41 | Category.builder().name("Restaurant").build(); 42 | } 43 | 44 | @Test(expected = IllegalStateException.class) 45 | public void testBuildFailedWithNoName() throws IOException { 46 | Category.builder().alias("restaurant").build(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/CoordinateTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class CoordinateTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode coordinateNode = JsonTestUtils.getBusinessResponseJsonNode().path("location").path("coordinate"); 17 | Coordinate coordinate = JsonTestUtils.deserializeJson(coordinateNode.toString(), Coordinate.class); 18 | 19 | Assert.assertEquals(new Double(coordinateNode.path("latitude").asDouble()), coordinate.latitude()); 20 | Assert.assertEquals(new Double(coordinateNode.path("longitude").asDouble()), coordinate.longitude()); 21 | } 22 | 23 | @Test 24 | public void testSerializable() throws IOException, ClassNotFoundException { 25 | JsonNode coordinateNode = JsonTestUtils.getBusinessResponseJsonNode().path("location").path("coordinate"); 26 | Coordinate coordinate = JsonTestUtils.deserializeJson(coordinateNode.toString(), Coordinate.class); 27 | 28 | byte[] bytes = SerializationTestUtils.serialize(coordinate); 29 | Assert.assertEquals(coordinate, SerializationTestUtils.deserialize(bytes, Coordinate.class)); 30 | } 31 | 32 | @Test(expected = IllegalStateException.class) 33 | public void testBuildFailedWithNoLatitude() throws IOException { 34 | Coordinate.builder().longitude(123.123123).build(); 35 | } 36 | 37 | @Test(expected = IllegalStateException.class) 38 | public void testBuildFailedWithNoLongitude() throws IOException { 39 | Coordinate.builder().latitude(123.123123).build(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/DealOptionTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class DealOptionTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode dealOptionNode = JsonTestUtils.getBusinessResponseJsonNode() 17 | .path("deals").get(0).path("options").get(0); 18 | DealOption dealOption = JsonTestUtils.deserializeJson(dealOptionNode.toString(), DealOption.class); 19 | 20 | Assert.assertEquals( 21 | dealOptionNode.path("formatted_original_price").textValue(), 22 | dealOption.formattedOriginalPrice() 23 | ); 24 | Assert.assertEquals(dealOptionNode.path("formatted_price").textValue(), dealOption.formattedPrice()); 25 | Assert.assertEquals(dealOptionNode.path("is_quantity_limited").asBoolean(), dealOption.isQuantityLimited()); 26 | Assert.assertEquals(new Integer(dealOptionNode.path("original_price").asInt()), dealOption.originalPrice()); 27 | Assert.assertEquals(new Integer(dealOptionNode.path("price").asInt()), dealOption.price()); 28 | Assert.assertEquals(dealOptionNode.path("purchase_url").textValue(), dealOption.purchaseUrl()); 29 | Assert.assertEquals(new Integer(dealOptionNode.path("remaining_count").asInt()), dealOption.remainingCount()); 30 | Assert.assertEquals(dealOptionNode.path("title").textValue(), dealOption.title()); 31 | } 32 | 33 | @Test 34 | public void testSerializable() throws IOException, ClassNotFoundException { 35 | JsonNode dealOptionNode = JsonTestUtils.getBusinessResponseJsonNode() 36 | .path("deals").get(0).path("options").get(0); 37 | DealOption dealOption = JsonTestUtils.deserializeJson(dealOptionNode.toString(), DealOption.class); 38 | 39 | byte[] bytes = SerializationTestUtils.serialize(dealOption); 40 | Assert.assertEquals(dealOption, SerializationTestUtils.deserialize(bytes, DealOption.class)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/DealTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class DealTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode dealNode = JsonTestUtils.getBusinessResponseJsonNode().path("deals").get(0); 17 | Deal deal = JsonTestUtils.deserializeJson(dealNode.toString(), Deal.class); 18 | 19 | Assert.assertNull(deal.additionalRestrictions()); 20 | Assert.assertEquals(dealNode.path("currency_code").textValue(), deal.currencyCode()); 21 | Assert.assertNull(deal.id()); 22 | Assert.assertEquals(dealNode.path("image_url").textValue(), deal.imageUrl()); 23 | Assert.assertNull(deal.importantRestrictions()); 24 | Assert.assertEquals(dealNode.path("is_popular").asBoolean(), deal.isPopular()); 25 | Assert.assertNotNull(deal.options().get(0)); 26 | Assert.assertNull(deal.timeEnd()); 27 | Assert.assertEquals(new Long(dealNode.path("time_start").asLong()), deal.timeStart()); 28 | Assert.assertEquals(dealNode.path("title").textValue(), deal.title()); 29 | Assert.assertEquals(dealNode.path("url").textValue(), deal.url()); 30 | Assert.assertNull(deal.whatYouGet()); 31 | } 32 | 33 | @Test 34 | public void testSerializable() throws IOException, ClassNotFoundException { 35 | JsonNode dealNode = JsonTestUtils.getBusinessResponseJsonNode().path("deals").get(0); 36 | Deal deal = JsonTestUtils.deserializeJson(dealNode.toString(), Deal.class); 37 | 38 | byte[] bytes = SerializationTestUtils.serialize(deal); 39 | Assert.assertEquals(deal, SerializationTestUtils.deserialize(bytes, Deal.class)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/GiftCertificateOptionTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class GiftCertificateOptionTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode giftCertificateOptionNode = JsonTestUtils.getBusinessResponseJsonNode() 17 | .path("gift_certificates").get(0).path("options").get(0); 18 | 19 | GiftCertificateOption giftCertificateOption = JsonTestUtils.deserializeJson( 20 | giftCertificateOptionNode.toString(), 21 | GiftCertificateOption.class 22 | ); 23 | 24 | Assert.assertEquals( 25 | giftCertificateOptionNode.path("formatted_price").textValue(), 26 | giftCertificateOption.formattedPrice() 27 | ); 28 | Assert.assertEquals( 29 | new Integer(giftCertificateOptionNode.path("price").asInt()), 30 | giftCertificateOption.price() 31 | ); 32 | } 33 | 34 | @Test 35 | public void testSerializable() throws IOException, ClassNotFoundException { 36 | JsonNode giftCertificateOptionNode = JsonTestUtils.getBusinessResponseJsonNode() 37 | .path("gift_certificates").get(0).path("options").get(0); 38 | GiftCertificateOption giftCertificateOption = JsonTestUtils.deserializeJson( 39 | giftCertificateOptionNode.toString(), 40 | GiftCertificateOption.class 41 | ); 42 | 43 | byte[] bytes = SerializationTestUtils.serialize(giftCertificateOption); 44 | Assert.assertEquals( 45 | giftCertificateOption, 46 | SerializationTestUtils.deserialize(bytes, GiftCertificateOption.class) 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/GiftCertificateTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class GiftCertificateTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode giftCertificatesNode = JsonTestUtils.getBusinessResponseJsonNode().path("gift_certificates").get(0); 17 | 18 | GiftCertificate giftCertificate = JsonTestUtils.deserializeJson( 19 | giftCertificatesNode.toString(), 20 | GiftCertificate.class 21 | ); 22 | 23 | Assert.assertEquals(giftCertificatesNode.path("id").textValue(), giftCertificate.id()); 24 | Assert.assertEquals(giftCertificatesNode.path("url").textValue(), giftCertificate.url()); 25 | Assert.assertEquals(giftCertificatesNode.path("image_url").textValue(), giftCertificate.imageUrl()); 26 | Assert.assertEquals(giftCertificatesNode.path("currency_code").textValue(), giftCertificate.currencyCode()); 27 | Assert.assertEquals(giftCertificatesNode.path("unused_balances").textValue(), giftCertificate.unusedBalances()); 28 | 29 | // GiftCertificateOption is tested in it's own test. 30 | Assert.assertNotNull(giftCertificate.options().get(0)); 31 | } 32 | 33 | @Test 34 | public void testSerializable() throws IOException, ClassNotFoundException { 35 | JsonNode giftCertificatesNode = JsonTestUtils.getBusinessResponseJsonNode().path("gift_certificates").get(0); 36 | GiftCertificate giftCertificate = JsonTestUtils.deserializeJson( 37 | giftCertificatesNode.toString(), 38 | GiftCertificate.class 39 | ); 40 | 41 | byte[] bytes = SerializationTestUtils.serialize(giftCertificate); 42 | Assert.assertEquals(giftCertificate, SerializationTestUtils.deserialize(bytes, GiftCertificate.class)); 43 | } 44 | 45 | @Test(expected = IllegalStateException.class) 46 | public void testBuildFailedWithNoId() throws IOException { 47 | GiftCertificate.builder().id(null).build(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/LocationTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class LocationTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode locationNode = JsonTestUtils.getBusinessResponseJsonNode().path("location"); 17 | Location location = JsonTestUtils.deserializeJson(locationNode.toString(), Location.class); 18 | 19 | Assert.assertEquals(1, location.address().size()); 20 | Assert.assertEquals(locationNode.path("city").textValue(), location.city()); 21 | Assert.assertNotNull(location.coordinate()); 22 | Assert.assertEquals(locationNode.path("country_code").textValue(), location.countryCode()); 23 | Assert.assertEquals(locationNode.path("cross_streets").textValue(), location.crossStreets()); 24 | Assert.assertEquals(3, location.displayAddress().size()); 25 | Assert.assertEquals(new Double(locationNode.path("geo_accuracy").asDouble()), location.geoAccuracy()); 26 | Assert.assertEquals(2, location.neighborhoods().size()); 27 | Assert.assertEquals(locationNode.path("postal_code").textValue(), location.postalCode()); 28 | Assert.assertEquals(locationNode.path("state_code").textValue(), location.stateCode()); 29 | } 30 | 31 | @Test 32 | public void testSerializable() throws IOException, ClassNotFoundException { 33 | JsonNode locationNode = JsonTestUtils.getBusinessResponseJsonNode().path("location"); 34 | Location location = JsonTestUtils.deserializeJson(locationNode.toString(), Location.class); 35 | 36 | byte[] bytes = SerializationTestUtils.serialize(location); 37 | Assert.assertEquals(location, SerializationTestUtils.deserialize(bytes, Location.class)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/RegionTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class RegionTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode regionNode = JsonTestUtils.getSearchResponseJsonNode().path("region"); 17 | Region region = JsonTestUtils.deserializeJson(regionNode.toString(), Region.class); 18 | 19 | // Coordinate and Span are tested in their own tests. 20 | Assert.assertNotNull(region.center()); 21 | Assert.assertNotNull(region.span()); 22 | } 23 | 24 | @Test 25 | public void testSerializable() throws IOException, ClassNotFoundException { 26 | JsonNode regionNode = JsonTestUtils.getSearchResponseJsonNode().path("region"); 27 | Region region = JsonTestUtils.deserializeJson(regionNode.toString(), Region.class); 28 | 29 | byte[] bytes = SerializationTestUtils.serialize(region); 30 | Assert.assertEquals(region, SerializationTestUtils.deserialize(bytes, Region.class)); 31 | } 32 | 33 | @Test(expected = IllegalStateException.class) 34 | public void testBuildFailedWithNoCenter() throws IOException { 35 | Span span = Span.builder().latitudeDelta(50.123).longitudeDelta(50.123).build(); 36 | Region.builder().span(span).build(); 37 | } 38 | 39 | @Test(expected = IllegalStateException.class) 40 | public void testBuildFailedWithNoSpan() throws IOException { 41 | Coordinate center = Coordinate.builder().latitude(123.123123).longitude(123.123123).build(); 42 | Region.builder().center(center).build(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/ReviewTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | 4 | import com.fasterxml.jackson.databind.JsonNode; 5 | import com.yelp.clientlib.utils.JsonTestUtils; 6 | import com.yelp.clientlib.utils.SerializationTestUtils; 7 | 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | 11 | import java.io.IOException; 12 | 13 | public class ReviewTest { 14 | 15 | @Test 16 | public void testDeserializeFromJson() throws IOException { 17 | JsonNode reviewNode = JsonTestUtils.getBusinessResponseJsonNode().path("reviews").get(0); 18 | Review review = JsonTestUtils.deserializeJson(reviewNode.toString(), Review.class); 19 | 20 | Assert.assertEquals(reviewNode.path("excerpt").textValue(), review.excerpt()); 21 | Assert.assertEquals(reviewNode.path("id").textValue(), review.id()); 22 | Assert.assertEquals(new Double(reviewNode.path("rating").asDouble()), review.rating()); 23 | Assert.assertEquals(reviewNode.path("rating_image_large_url").textValue(), review.ratingImageLargeUrl()); 24 | Assert.assertEquals(reviewNode.path("rating_image_small_url").textValue(), review.ratingImageSmallUrl()); 25 | Assert.assertEquals(reviewNode.path("rating_image_url").textValue(), review.ratingImageUrl()); 26 | Assert.assertEquals(new Long(reviewNode.path("time_created").asLong()), review.timeCreated()); 27 | 28 | // User is tested in it's own test. 29 | Assert.assertNotNull(review.user()); 30 | } 31 | 32 | @Test 33 | public void testSerializable() throws IOException, ClassNotFoundException { 34 | JsonNode reviewNode = JsonTestUtils.getBusinessResponseJsonNode().path("reviews").get(0); 35 | Review review = JsonTestUtils.deserializeJson(reviewNode.toString(), Review.class); 36 | 37 | byte[] bytes = SerializationTestUtils.serialize(review); 38 | Assert.assertEquals(review, SerializationTestUtils.deserialize(bytes, Review.class)); 39 | } 40 | 41 | @Test(expected = IllegalStateException.class) 42 | public void testBuildFailedWithNoId() throws IOException { 43 | Review.builder().id(null).build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/SearchResponseTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class SearchResponseTest { 13 | @Test 14 | public void testDeserializeFromJson() throws IOException { 15 | JsonNode searchNode = JsonTestUtils.getSearchResponseJsonNode(); 16 | SearchResponse searchResponse = JsonTestUtils.deserializeJson(searchNode.toString(), SearchResponse.class); 17 | 18 | Assert.assertEquals(new Integer(searchNode.path("total").asInt()), searchResponse.total()); 19 | 20 | // The following objects are tested in their own tests. 21 | Assert.assertNotNull(searchResponse.region()); 22 | Assert.assertNotNull(searchResponse.businesses()); 23 | } 24 | 25 | @Test 26 | public void testSerializable() throws IOException, ClassNotFoundException { 27 | JsonNode searchResponseNode = JsonTestUtils.getSearchResponseJsonNode(); 28 | SearchResponse searchResponse = JsonTestUtils.deserializeJson( 29 | searchResponseNode.toString(), 30 | SearchResponse.class 31 | ); 32 | 33 | byte[] bytes = SerializationTestUtils.serialize(searchResponse); 34 | Assert.assertEquals(searchResponse, SerializationTestUtils.deserialize(bytes, SearchResponse.class)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/SpanTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class SpanTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode spanNode = JsonTestUtils.getSearchResponseJsonNode().path("region").path("span"); 17 | Span span = JsonTestUtils.deserializeJson(spanNode.toString(), Span.class); 18 | 19 | Assert.assertEquals(new Double(spanNode.path("latitude_delta").asDouble()), span.latitudeDelta()); 20 | Assert.assertEquals(new Double(spanNode.path("longitude_delta").asDouble()), span.longitudeDelta()); 21 | } 22 | 23 | @Test 24 | public void testSerializable() throws IOException, ClassNotFoundException { 25 | JsonNode spanNode = JsonTestUtils.getSearchResponseJsonNode().path("region").path("span"); 26 | Span span = JsonTestUtils.deserializeJson(spanNode.toString(), Span.class); 27 | 28 | byte[] bytes = SerializationTestUtils.serialize(span); 29 | Assert.assertEquals(span, SerializationTestUtils.deserialize(bytes, Span.class)); 30 | } 31 | 32 | @Test(expected = IllegalStateException.class) 33 | public void testBuildFailedWithNoLatitudeDelta() throws IOException { 34 | Span.builder().longitudeDelta(50.123123).build(); 35 | } 36 | 37 | @Test(expected = IllegalStateException.class) 38 | public void testBuildFailedWithNoLongitude() throws IOException { 39 | Span.builder().latitudeDelta(50.123123).build(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/UserTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.yelp.clientlib.utils.JsonTestUtils; 5 | import com.yelp.clientlib.utils.SerializationTestUtils; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | public class UserTest { 13 | 14 | @Test 15 | public void testDeserializeFromJson() throws IOException { 16 | JsonNode userNode = JsonTestUtils.getBusinessResponseJsonNode().path("reviews").get(0).path("user"); 17 | User user = JsonTestUtils.deserializeJson(userNode.toString(), User.class); 18 | 19 | Assert.assertEquals(userNode.path("id").textValue(), user.id()); 20 | Assert.assertEquals(userNode.path("image_url").textValue(), user.imageUrl()); 21 | Assert.assertEquals(userNode.path("name").textValue(), user.name()); 22 | } 23 | 24 | @Test 25 | public void testSerializable() throws IOException, ClassNotFoundException { 26 | JsonNode userNode = JsonTestUtils.getBusinessResponseJsonNode().path("reviews").get(0).path("user"); 27 | User user = JsonTestUtils.deserializeJson(userNode.toString(), User.class); 28 | 29 | byte[] bytes = SerializationTestUtils.serialize(user); 30 | Assert.assertEquals(user, SerializationTestUtils.deserialize(bytes, User.class)); 31 | } 32 | 33 | @Test(expected = IllegalStateException.class) 34 | public void testBuildFailedWithNoId() throws IOException { 35 | User.builder().id(null).build(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/options/BoundingBoxOptionsTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities.options; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class BoundingBoxOptionsTest { 7 | Double swLatitude = 11.11111; 8 | Double swLongitude = 22.11111; 9 | Double neLatitude = 33.11111; 10 | Double neLongitude = 44.11111; 11 | 12 | @Test 13 | public void testBuilder() { 14 | BoundingBoxOptions bounds = BoundingBoxOptions.builder() 15 | .swLatitude(swLatitude) 16 | .swLongitude(swLongitude) 17 | .neLatitude(neLatitude) 18 | .neLongitude(neLongitude).build(); 19 | 20 | Assert.assertEquals(swLatitude, bounds.swLatitude()); 21 | Assert.assertEquals(swLongitude, bounds.swLongitude()); 22 | Assert.assertEquals(neLatitude, bounds.neLatitude()); 23 | Assert.assertEquals(neLongitude, bounds.neLongitude()); 24 | } 25 | 26 | @Test(expected = IllegalStateException.class) 27 | public void testNonSetSwLatitudeRaiseException() { 28 | BoundingBoxOptions.builder() 29 | .swLongitude(swLongitude) 30 | .neLatitude(neLatitude) 31 | .neLongitude(neLongitude) 32 | .build(); 33 | } 34 | 35 | @Test(expected = IllegalStateException.class) 36 | public void testNonSetSwLongitudeRaiseException() { 37 | BoundingBoxOptions.builder() 38 | .swLatitude(swLatitude) 39 | .neLatitude(neLatitude) 40 | .neLongitude(neLongitude) 41 | .build(); 42 | } 43 | 44 | @Test(expected = IllegalStateException.class) 45 | public void testNonSetNeLatitudeRaiseException() { 46 | BoundingBoxOptions.builder() 47 | .swLatitude(swLatitude) 48 | .swLongitude(swLongitude) 49 | .neLongitude(neLongitude) 50 | .build(); 51 | } 52 | 53 | @Test(expected = IllegalStateException.class) 54 | public void testNonSetNeLongitudeRaiseException() { 55 | BoundingBoxOptions.builder() 56 | .swLatitude(swLatitude) 57 | .swLongitude(swLongitude) 58 | .neLatitude(neLatitude) 59 | .build(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/entities/options/CoordinateOptionsTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.entities.options; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class CoordinateOptionsTest { 7 | Double latitude = 11.11111; 8 | Double longitude = 22.11111; 9 | Double accuracy = 9.5; 10 | Double altitude = 100.11; 11 | Double altitudeAccuracy = 9.5; 12 | 13 | @Test 14 | public void testBuilder() { 15 | CoordinateOptions coordinate = CoordinateOptions.builder() 16 | .latitude(latitude) 17 | .longitude(longitude) 18 | .accuracy(accuracy) 19 | .altitude(altitude) 20 | .altitudeAccuracy(altitudeAccuracy) 21 | .build(); 22 | 23 | Assert.assertEquals(latitude, coordinate.latitude()); 24 | Assert.assertEquals(longitude, coordinate.longitude()); 25 | Assert.assertEquals(accuracy, coordinate.accuracy()); 26 | Assert.assertEquals(altitude, coordinate.altitude()); 27 | Assert.assertEquals(altitudeAccuracy, coordinate.altitudeAccuracy()); 28 | } 29 | 30 | @Test 31 | public void testToStringWithLatLong() { 32 | CoordinateOptions coordinate = CoordinateOptions.builder() 33 | .latitude(latitude) 34 | .longitude(longitude) 35 | .build(); 36 | 37 | Assert.assertEquals(latitude + "," + longitude + ",,,", coordinate.toString()); 38 | } 39 | 40 | @Test 41 | public void testToStringWithLatLongAccuracy() { 42 | CoordinateOptions coordinate = CoordinateOptions.builder() 43 | .latitude(latitude) 44 | .longitude(longitude) 45 | .accuracy(accuracy) 46 | .build(); 47 | 48 | Assert.assertEquals(latitude + "," + longitude + "," + accuracy + ",,", coordinate.toString()); 49 | } 50 | 51 | @Test 52 | public void testToStringWithLatLongAltitude() { 53 | CoordinateOptions coordinate = CoordinateOptions.builder() 54 | .latitude(latitude) 55 | .longitude(longitude) 56 | .altitude(altitude) 57 | .build(); 58 | 59 | Assert.assertEquals(latitude + "," + longitude + ",," + altitude + ",", coordinate.toString()); 60 | } 61 | 62 | @Test 63 | public void testToStringWithLatLongAccuracyAltitude() { 64 | CoordinateOptions coordinate = CoordinateOptions.builder() 65 | .latitude(latitude) 66 | .longitude(longitude) 67 | .accuracy(accuracy) 68 | .altitude(altitude) 69 | .build(); 70 | 71 | Assert.assertEquals( 72 | latitude + "," + longitude + "," + accuracy + "," + altitude + ",", 73 | coordinate.toString() 74 | ); 75 | } 76 | 77 | @Test 78 | public void testToStringWithAllFields() { 79 | CoordinateOptions coordinate = CoordinateOptions.builder() 80 | .latitude(latitude) 81 | .longitude(longitude) 82 | .accuracy(accuracy) 83 | .altitude(altitude) 84 | .altitudeAccuracy(altitudeAccuracy) 85 | .build(); 86 | 87 | Assert.assertEquals( 88 | latitude + "," + longitude + "," + accuracy + "," + altitude + "," + altitudeAccuracy, 89 | coordinate.toString() 90 | ); 91 | } 92 | 93 | @Test(expected = IllegalStateException.class) 94 | public void testNonSetLatitudeRaiseException() { 95 | CoordinateOptions.builder() 96 | .longitude(longitude) 97 | .build(); 98 | } 99 | 100 | @Test(expected = IllegalStateException.class) 101 | public void testNonSetLongitudeRaiseException() { 102 | CoordinateOptions.builder() 103 | .latitude(latitude) 104 | .build(); 105 | } 106 | 107 | @Test 108 | public void testNonSetNullableValueRaiseNoException() { 109 | CoordinateOptions.builder() 110 | .latitude(latitude) 111 | .longitude(longitude) 112 | .build(); 113 | } 114 | } -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/exception/ErrorHandlingInterceptorTest.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.exception; 2 | 3 | import okhttp3.Interceptor; 4 | import okhttp3.MediaType; 5 | import okhttp3.Protocol; 6 | import okhttp3.Request; 7 | import okhttp3.Response; 8 | import okhttp3.ResponseBody; 9 | import com.yelp.clientlib.exception.exceptions.BusinessUnavailable; 10 | import com.yelp.clientlib.exception.exceptions.InternalError; 11 | import com.yelp.clientlib.exception.exceptions.InvalidParameter; 12 | import com.yelp.clientlib.exception.exceptions.UnexpectedAPIError; 13 | import com.yelp.clientlib.utils.ErrorTestUtils; 14 | 15 | import org.easymock.EasyMock; 16 | import org.junit.Assert; 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | import org.junit.runner.RunWith; 20 | import org.powermock.api.easymock.PowerMock; 21 | import org.powermock.core.classloader.annotations.PrepareForTest; 22 | import org.powermock.modules.junit4.PowerMockRunner; 23 | 24 | import java.io.IOException; 25 | 26 | @RunWith(PowerMockRunner.class) 27 | @PrepareForTest({Request.class, Response.class, Protocol.class}) 28 | public class ErrorHandlingInterceptorTest { 29 | 30 | Interceptor errorHandlingInterceptor; 31 | 32 | @Before 33 | public void setUp() { 34 | this.errorHandlingInterceptor = new ErrorHandlingInterceptor(); 35 | } 36 | 37 | /** 38 | * Ensure the interceptor does nothing besides proceeding the request if the request is done successfully. 39 | */ 40 | @Test 41 | public void testSuccessfulRequestNotDoingAnythingExceptProceedingRequests() throws IOException { 42 | Request mockRequest = PowerMock.createMock(Request.class); 43 | Response mockResponse = PowerMock.createMock(Response.class); 44 | Interceptor.Chain mockChain = PowerMock.createMock(Interceptor.Chain.class); 45 | 46 | EasyMock.expect(mockChain.request()).andReturn(mockRequest); 47 | EasyMock.expect(mockChain.proceed(mockRequest)).andReturn(mockResponse); 48 | EasyMock.expect(mockResponse.isSuccessful()).andReturn(true); 49 | 50 | PowerMock.replay(mockRequest, mockResponse, mockChain); 51 | 52 | Response returnedResponse = errorHandlingInterceptor.intercept(mockChain); 53 | 54 | PowerMock.verify(mockChain); 55 | Assert.assertEquals(mockResponse, returnedResponse); 56 | } 57 | 58 | @Test 59 | public void testParseNullResponseBody() throws IOException { 60 | int errorCode = 500; 61 | String errorMessage = "Internal Server Error"; 62 | 63 | Interceptor.Chain mockChain = mockChainWithErrorResponse(errorCode, errorMessage, null); 64 | try { 65 | errorHandlingInterceptor.intercept(mockChain); 66 | } catch (UnexpectedAPIError error) { 67 | ErrorTestUtils.verifyErrorContent(error, errorCode, errorMessage, null, null); 68 | return; 69 | } 70 | 71 | Assert.fail("Expected failure not returned."); 72 | } 73 | 74 | @Test 75 | public void testParseBusinessUnavailable() throws IOException { 76 | int errorCode = 400; 77 | String errorMessage = "Bad Request"; 78 | String errorId = "BUSINESS_UNAVAILABLE"; 79 | String errorText = "Business information is unavailable"; 80 | String errorJsonBody = generateErrorJsonString(errorId, errorText); 81 | 82 | Interceptor.Chain mockChain = mockChainWithErrorResponse(errorCode, errorMessage, errorJsonBody); 83 | try { 84 | errorHandlingInterceptor.intercept(mockChain); 85 | } catch (BusinessUnavailable error) { 86 | ErrorTestUtils.verifyErrorContent(error, errorCode, errorMessage, errorId, errorText); 87 | return; 88 | } 89 | 90 | Assert.fail("Expected failure not returned."); 91 | } 92 | 93 | @Test 94 | public void testParseInternalError() throws IOException { 95 | int errorCode = 500; 96 | String errorMessage = "Internal Server Error"; 97 | String errorId = "INTERNAL_ERROR"; 98 | String errorText = "Some internal error happened"; 99 | String errorJsonBody = generateErrorJsonString(errorId, errorText); 100 | 101 | Interceptor.Chain mockChain = mockChainWithErrorResponse(errorCode, errorMessage, errorJsonBody); 102 | try { 103 | errorHandlingInterceptor.intercept(mockChain); 104 | } catch (InternalError error) { 105 | ErrorTestUtils.verifyErrorContent(error, errorCode, errorMessage, errorId, errorText); 106 | return; 107 | } 108 | 109 | Assert.fail("Expected failure not returned."); 110 | } 111 | 112 | @Test 113 | public void testParseErrorWithField() throws IOException { 114 | int errorCode = 400; 115 | String errorMessage = "Bad Request"; 116 | String errorId = "INVALID_PARAMETER"; 117 | String errorText = "One or more parameters are invalid in request"; 118 | String errorField = "phone"; 119 | String expectedErrorText = String.format("%s: %s", errorText, errorField); 120 | String errorJsonBody = generateErrorJsonString(errorId, errorText, errorField); 121 | 122 | Interceptor.Chain mockChain = mockChainWithErrorResponse(errorCode, errorMessage, errorJsonBody); 123 | try { 124 | errorHandlingInterceptor.intercept(mockChain); 125 | } catch (InvalidParameter error) { 126 | ErrorTestUtils.verifyErrorContent(error, errorCode, errorMessage, errorId, expectedErrorText); 127 | return; 128 | } 129 | 130 | Assert.fail("Expected failure not returned."); 131 | } 132 | 133 | @Test 134 | public void testParseUnexpectedAPIError() throws IOException { 135 | int errorCode = 400; 136 | String errorMessage = "Bad Request"; 137 | String errorId = "COULD_BE_ANY_THING_NOT_DEFINED"; 138 | String errorText = "Woops, there is something unexpected happened"; 139 | String errorJsonBody = generateErrorJsonString(errorId, errorText); 140 | 141 | Interceptor.Chain mockChain = mockChainWithErrorResponse(errorCode, errorMessage, errorJsonBody); 142 | try { 143 | errorHandlingInterceptor.intercept(mockChain); 144 | } catch (UnexpectedAPIError error) { 145 | ErrorTestUtils.verifyErrorContent(error, errorCode, errorMessage, errorId, errorText); 146 | return; 147 | } 148 | 149 | Assert.fail("Expected failure not returned."); 150 | } 151 | 152 | @Test(expected = IOException.class) 153 | public void testParseInvalidJsonBody() throws IOException { 154 | int errorCode = 500; 155 | String errorMessage = "Internal Server Error"; 156 | String errorHTMLBody = "This is not JSON"; 157 | 158 | Interceptor.Chain mockChain = mockChainWithErrorResponse(errorCode, errorMessage, errorHTMLBody); 159 | errorHandlingInterceptor.intercept(mockChain); 160 | } 161 | 162 | private Interceptor.Chain mockChainWithErrorResponse( 163 | int errorCode, 164 | String errorMessage, 165 | String errorBody 166 | ) throws IOException { 167 | Response response = new Response.Builder() 168 | .request(PowerMock.createMock(Request.class)) 169 | .protocol(PowerMock.createMock(Protocol.class)) 170 | .code(errorCode) 171 | .message(errorMessage) 172 | .body(errorBody != null ? ResponseBody.create(MediaType.parse("UTF-8"), errorBody) : null) 173 | .build(); 174 | 175 | Interceptor.Chain mockChain = PowerMock.createMock(Interceptor.Chain.class); 176 | EasyMock.expect(mockChain.request()).andReturn(PowerMock.createMock(Request.class)); 177 | EasyMock.expect(mockChain.proceed(EasyMock.anyObject(Request.class))).andReturn(response); 178 | PowerMock.replay(mockChain); 179 | 180 | return mockChain; 181 | } 182 | 183 | private String generateErrorJsonString(String errorId, String text) { 184 | String errorJsonStringFormat = "{\"error\": {\"id\": \"%s\", \"text\": \"%s\"}}"; 185 | return String.format(errorJsonStringFormat, errorId, text); 186 | } 187 | 188 | private String generateErrorJsonString(String errorId, String text, String field) { 189 | String errorJsonStringFormat = "{\"error\": {\"id\": \"%s\", \"text\": \"%s\", \"field\": \"%s\"}}"; 190 | return String.format(errorJsonStringFormat, errorId, text, field); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/utils/AsyncTestUtils.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.utils; 2 | 3 | import okhttp3.Dispatcher; 4 | import okhttp3.OkHttpClient; 5 | import com.yelp.clientlib.connection.YelpAPIFactory; 6 | 7 | import org.junit.Assert; 8 | 9 | import java.util.List; 10 | import java.util.concurrent.AbstractExecutorService; 11 | import java.util.concurrent.ExecutorService; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | import junitx.util.PrivateAccessor; 15 | 16 | public class AsyncTestUtils { 17 | 18 | /** 19 | * Make a {@link YelpAPIFactory} to send HTTP requests in main thread so we can verify the test results easily. 20 | * Retrofit uses {@link OkHttpClient} for the underlying HTTP calls, this method replaces the {@link Dispatcher} 21 | * in {@link OkHttpClient} so an {@link ExecutorService} runs jobs in main thread will be used to send HTTP 22 | * requests. 23 | */ 24 | public static YelpAPIFactory setToRunInMainThread(YelpAPIFactory yelpAPIFactory) { 25 | Dispatcher synchronousDispatcher = new Dispatcher(newSynchronousExecutorService()); 26 | 27 | try { 28 | OkHttpClient httpClient = (OkHttpClient) PrivateAccessor.getField(yelpAPIFactory, "httpClient"); 29 | OkHttpClient synchronousHttpClient = httpClient.newBuilder().dispatcher(synchronousDispatcher).build(); 30 | PrivateAccessor.setField(yelpAPIFactory, "httpClient", synchronousHttpClient); 31 | } catch (NoSuchFieldException e) { 32 | Assert.fail(e.toString()); 33 | } 34 | 35 | return yelpAPIFactory; 36 | } 37 | 38 | /** 39 | * Create an {@link ExecutorService} which runs jobs in main thread. 40 | */ 41 | public static ExecutorService newSynchronousExecutorService() { 42 | return new AbstractExecutorService() { 43 | @Override 44 | public void execute(Runnable command) { 45 | command.run(); 46 | } 47 | 48 | @Override 49 | public void shutdown() { 50 | throw new UnsupportedOperationException(); 51 | } 52 | 53 | @Override 54 | public List shutdownNow() { 55 | throw new UnsupportedOperationException(); 56 | } 57 | 58 | @Override 59 | public boolean isShutdown() { 60 | throw new UnsupportedOperationException(); 61 | } 62 | 63 | @Override 64 | public boolean isTerminated() { 65 | throw new UnsupportedOperationException(); 66 | } 67 | 68 | @Override 69 | public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { 70 | throw new UnsupportedOperationException(); 71 | } 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/utils/ErrorTestUtils.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.utils; 2 | 3 | import com.yelp.clientlib.exception.exceptions.YelpAPIError; 4 | 5 | import org.junit.Assert; 6 | 7 | public class ErrorTestUtils { 8 | 9 | /** 10 | * Verify a {@link YelpAPIError} contains correct information. 11 | * 12 | * @param error The YelpAPIError to be verified. 13 | * @param expectCode Expected error code. 14 | * @param expectMessage Expected error message. 15 | * @param expectId Expected error Id. 16 | * @param expectText Expected error text. 17 | */ 18 | public static void verifyErrorContent( 19 | YelpAPIError error, 20 | int expectCode, 21 | String expectMessage, 22 | String expectId, 23 | String expectText 24 | ) { 25 | Assert.assertEquals(expectCode, error.getCode()); 26 | Assert.assertEquals(expectMessage, error.getMessage()); 27 | Assert.assertEquals(expectId, error.getErrorId()); 28 | Assert.assertEquals(expectText, error.getText()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/utils/JsonTestUtils.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.utils; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | 9 | public class JsonTestUtils { 10 | public static final String BUSINESS_RESPONSE_JSON_FILENAME = "businessResponse.json"; 11 | 12 | public static final String SEARCH_RESPONSE_JSON_FILENAME = "searchResponse.json"; 13 | 14 | public static JsonNode getBusinessResponseJsonNode() throws IOException { 15 | return getJsonNodeFromFile(BUSINESS_RESPONSE_JSON_FILENAME); 16 | } 17 | 18 | public static JsonNode getSearchResponseJsonNode() throws IOException { 19 | return getJsonNodeFromFile(SEARCH_RESPONSE_JSON_FILENAME); 20 | } 21 | 22 | public static JsonNode getJsonNodeFromFile(String filename) throws IOException { 23 | File jsonFile = new File(JsonTestUtils.class.getClassLoader().getResource(filename).getFile()); 24 | return new ObjectMapper().readTree(jsonFile); 25 | } 26 | 27 | public static T deserializeJson(String content, Class valueType) throws IOException { 28 | return new ObjectMapper().readValue(content, valueType); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/yelp/clientlib/utils/SerializationTestUtils.java: -------------------------------------------------------------------------------- 1 | package com.yelp.clientlib.utils; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.ObjectInputStream; 7 | import java.io.ObjectOutputStream; 8 | import java.io.Serializable; 9 | 10 | public class SerializationTestUtils { 11 | 12 | /** 13 | * Serialize an object into a byte array. The object has to implement {@link Serializable} interface. 14 | * 15 | * @param object Object to be serialized. 16 | * @return Byte array serialized from the object. 17 | */ 18 | public static byte[] serialize(T object) throws IOException { 19 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 20 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); 21 | objectOutputStream.writeObject(object); 22 | objectOutputStream.close(); 23 | 24 | return byteArrayOutputStream.toByteArray(); 25 | } 26 | 27 | /** 28 | * Deserialize a byte array into an object. The object has to implement {@link Serializable} interface. 29 | * 30 | * @param bytes Byte array to be deserialized. 31 | * @param clazz Class type the object should be deserialized into. 32 | * @return Object deserialized from the byte array. 33 | */ 34 | public static T deserialize(byte[] bytes, Class clazz) 35 | throws IOException, ClassNotFoundException { 36 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 37 | ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 38 | Object object = objectInputStream.readObject(); 39 | 40 | return clazz.cast(object); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/resources/businessResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "categories": [ 3 | [ 4 | "Indian", 5 | "indpak" 6 | ], 7 | [ 8 | "Himalayan/Nepalese", 9 | "himalayan" 10 | ] 11 | ], 12 | "deals": [ 13 | { 14 | "currency_code": "USD", 15 | "image_url": "http://s3-media4.ak.yelpcdn.com/dphoto/ShQGf5qi-52HwPiKyZTZ3w/m.jpg", 16 | "options": [ 17 | { 18 | "formatted_original_price": "$20", 19 | "formatted_price": "$10", 20 | "is_quantity_limited": true, 21 | "original_price": 2000, 22 | "price": 1000, 23 | "purchase_url": "http://www.yelp.com/deal/cC24ccQGIH8mowfu5Vbe0Q/view", 24 | "remaining_count": 36, 25 | "title": "$10 for $20 voucher" 26 | } 27 | ], 28 | "url": "http://www.yelp.com/biz/urban-curry-san-francisco?deal=1", 29 | "is_popular": true, 30 | "time_start": 1317414369, 31 | "title": "$10 for $20 voucher" 32 | } 33 | ], 34 | "display_phone": "+1-415-677-9743", 35 | "eat24_url": "http://e24.io/r/5769?utm_campaign=public&utm_medium=yelpapi&utm_source=yelpapi", 36 | "gift_certificates": [ 37 | { 38 | "currency_code": "USD", 39 | "image_url": "http://s3-media4.ak.yelpcdn.com/bphoto/Hv5vsWpqeaUKepr9nffJnw/m.jpg", 40 | "options": [ 41 | { 42 | "formatted_price": "$25", 43 | "price": 2500 44 | }, 45 | { 46 | "formatted_price": "$50", 47 | "price": 5000 48 | } 49 | ], 50 | "url": "http://www.yelp.com/gift-certificates/some-donut-place-pasadena", 51 | "id": "ZZy5EwrI3wyHw8y54jZruA", 52 | "unused_balances": "CREDIT" 53 | } 54 | ], 55 | "id": "urban-curry-san-francisco", 56 | "image_url": "http://s3-media1.fl.yelpcdn.com/bphoto/u5b1u7c04C1GkptUg0grdA/ms.jpg", 57 | "is_claimed": true, 58 | "is_closed": false, 59 | "location": { 60 | "address": [ 61 | "523 Broadway" 62 | ], 63 | "city": "San Francisco", 64 | "coordinate": { 65 | "latitude": 37.7978994, 66 | "longitude": -122.4059649 67 | }, 68 | "country_code": "US", 69 | "cross_streets": "Romolo Pl & Kearny St", 70 | "display_address": [ 71 | "523 Broadway", 72 | "North Beach/Telegraph Hill", 73 | "San Francisco, CA 94133" 74 | ], 75 | "geo_accuracy": 9.5, 76 | "neighborhoods": [ 77 | "North Beach/Telegraph Hill", 78 | "Chinatown" 79 | ], 80 | "postal_code": "94133", 81 | "state_code": "CA" 82 | }, 83 | "menu_date_updated": 1443040751, 84 | "menu_provider": "single_platform", 85 | "mobile_url": "http://m.yelp.com/biz/urban-curry-san-francisco", 86 | "name": "Urban Curry", 87 | "phone": "4156779743", 88 | "rating": 4.0, 89 | "rating_img_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/c2f3dd9799a5/ico/stars/v1/stars_4.png", 90 | "rating_img_url_large": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/ccf2b76faa2c/ico/stars/v1/stars_large_4.png", 91 | "rating_img_url_small": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/f62a5be2f902/ico/stars/v1/stars_small_4.png", 92 | "review_count": 455, 93 | "reviews": [ 94 | { 95 | "excerpt": "One of the owners is a former Sherpa from Nepal who has summitted Mt. Everest twice. While the restaurant is in a seeder part of the City, it's also on one...", 96 | "id": "flAK8Mu4auUdcFNR7iPa6Q", 97 | "rating": 4, 98 | "rating_image_large_url": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/ccf2b76faa2c/ico/stars/v1/stars_large_4.png", 99 | "rating_image_small_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/f62a5be2f902/ico/stars/v1/stars_small_4.png", 100 | "rating_image_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/c2f3dd9799a5/ico/stars/v1/stars_4.png", 101 | "time_created": 1440895245, 102 | "user": { 103 | "id": "3KNNxsQa4uooK5FAj7bVaQ", 104 | "image_url": "http://s3-media3.fl.yelpcdn.com/photo/hk31BkJvJ8qcqoUvZ38rmQ/ms.jpg", 105 | "name": "Hilary C." 106 | } 107 | } 108 | ], 109 | "snippet_image_url": "http://s3-media3.fl.yelpcdn.com/photo/hk31BkJvJ8qcqoUvZ38rmQ/ms.jpg", 110 | "snippet_text": "One of the owners is a former Sherpa from Nepal who has summitted Mt. Everest twice. While the restaurant is in a seeder part of the City, it's also on one...", 111 | "url": "http://www.yelp.com/biz/urban-curry-san-francisco" 112 | } -------------------------------------------------------------------------------- /src/test/resources/noReviewBusinessResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "is_claimed": true, 3 | "rating": 0.0, 4 | "mobile_url": "http://m.yelp.com/biz/yelp-fantastic-san-francisco", 5 | "rating_img_url": "http://media4.fl.yelpcdn.com/assets/2/www/img/04ae5eda5622/ico/stars/v1/stars_0.png", 6 | "review_count": 0, 7 | "name": "Yelp Fantastic", 8 | "rating_img_url_small": "http://media4.fl.yelpcdn.com/assets/2/www/img/d3cd853a8cb7/ico/stars/v1/stars_small_0.png", 9 | "url": "http://www.yelp.com/biz/yelp-fantastic-san-francisco", 10 | "categories": [ 11 | [ 12 | "Local Flavor", 13 | "localflavor" 14 | ], 15 | [ 16 | "Mass Media", 17 | "massmedia" 18 | ] 19 | ], 20 | "phone": "4156069349", 21 | "location": { 22 | "cross_streets": "Natoma St & Minna St", 23 | "city": "San Francisco", 24 | "display_address": [ 25 | "140 New Montgomery St", 26 | "Financial District", 27 | "San Francisco, CA 94105" 28 | ], 29 | "geo_accuracy": 9.5, 30 | "neighborhoods": [ 31 | "Financial District", 32 | "SoMa" 33 | ], 34 | "postal_code": "94105", 35 | "country_code": "US", 36 | "address": [ 37 | "140 New Montgomery St" 38 | ], 39 | "coordinate": { 40 | "latitude": 37.7867703362929, 41 | "longitude": -122.399958372115 42 | }, 43 | "state_code": "CA" 44 | }, 45 | "display_phone": "+1-415-908-3801", 46 | "rating_img_url_large": "http://media2.fl.yelpcdn.com/assets/2/www/img/1d04a136ee3e/ico/stars/v1/stars_large_0.png", 47 | "id": "yelp-fantastic-san-francisco", 48 | "is_closed": false 49 | } 50 | -------------------------------------------------------------------------------- /src/test/resources/sampleFailureResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "id": "BUSINESS_UNAVAILABLE", 4 | "text": "Business information is unavailable" 5 | } 6 | } -------------------------------------------------------------------------------- /src/test/resources/searchResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "region": { 3 | "span": { 4 | "latitude_delta": 0.05983615047641422, 5 | "longitude_delta": 0.04888134068070826 6 | }, 7 | "center": { 8 | "latitude": 37.77991744978345, 9 | "longitude": -122.4147528087815 10 | } 11 | }, 12 | "total": 13807, 13 | "businesses": [ 14 | { 15 | "is_claimed": true, 16 | "rating": 4.0, 17 | "mobile_url": "http://m.yelp.com/biz/brendas-french-soul-food-san-francisco", 18 | "rating_img_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/c2f3dd9799a5/ico/stars/v1/stars_4.png", 19 | "review_count": 6644, 20 | "name": "Brenda's French Soul Food", 21 | "rating_img_url_small": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/f62a5be2f902/ico/stars/v1/stars_small_4.png", 22 | "url": "http://www.yelp.com/biz/brendas-french-soul-food-san-francisco", 23 | "categories": [ 24 | [ 25 | "Breakfast & Brunch", 26 | "breakfast_brunch" 27 | ], 28 | [ 29 | "French", 30 | "french" 31 | ], 32 | [ 33 | "Soul Food", 34 | "soulfood" 35 | ] 36 | ], 37 | "menu_date_updated": 1442008852, 38 | "phone": "4153458100", 39 | "snippet_text": "Crawfish beignets and cheesy grits are baaaaaaae. Brenda's food is absolutely delicious and prices are great, and it's only been a few hours since I was in...", 40 | "image_url": "http://s3-media1.fl.yelpcdn.com/bphoto/mEzEYZ1lIM6mYfbKgHwCjw/ms.jpg", 41 | "snippet_image_url": "http://s3-media4.fl.yelpcdn.com/photo/kO5nMfF6VsB-YTQXThdvvA/ms.jpg", 42 | "display_phone": "+1-415-345-8100", 43 | "rating_img_url_large": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/ccf2b76faa2c/ico/stars/v1/stars_large_4.png", 44 | "menu_provider": "single_platform", 45 | "id": "brendas-french-soul-food-san-francisco", 46 | "is_closed": false, 47 | "location": { 48 | "cross_streets": "Turk St & Eddy St", 49 | "city": "San Francisco", 50 | "display_address": [ 51 | "652 Polk St", 52 | "Tenderloin", 53 | "San Francisco, CA 94102" 54 | ], 55 | "geo_accuracy": 9.5, 56 | "neighborhoods": [ 57 | "Tenderloin" 58 | ], 59 | "postal_code": "94102", 60 | "country_code": "US", 61 | "address": [ 62 | "652 Polk St" 63 | ], 64 | "coordinate": { 65 | "latitude": 37.7828800032306, 66 | "longitude": -122.419018169646 67 | }, 68 | "state_code": "CA" 69 | } 70 | }, 71 | { 72 | "is_claimed": true, 73 | "rating": 4.5, 74 | "mobile_url": "http://m.yelp.com/biz/the-codmother-fish-and-chips-san-francisco", 75 | "rating_img_url": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/99493c12711e/ico/stars/v1/stars_4_half.png", 76 | "review_count": 1599, 77 | "name": "The Codmother Fish and Chips", 78 | "rating_img_url_small": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/a5221e66bc70/ico/stars/v1/stars_small_4_half.png", 79 | "url": "http://www.yelp.com/biz/the-codmother-fish-and-chips-san-francisco", 80 | "categories": [ 81 | [ 82 | "British", 83 | "british" 84 | ], 85 | [ 86 | "Fish & Chips", 87 | "fishnchips" 88 | ], 89 | [ 90 | "Seafood", 91 | "seafood" 92 | ] 93 | ], 94 | "phone": "4156069349", 95 | "snippet_text": "Very very good fish and chips and fish tacos !!!\n\nLooks like a shack in the side of the road but the food is excellent. Try it !", 96 | "image_url": "http://s3-media3.fl.yelpcdn.com/bphoto/JhkeEgh-NOn9wSHyvaRNdQ/ms.jpg", 97 | "snippet_image_url": "http://s3-media2.fl.yelpcdn.com/photo/5tM6qnZXuTgOaglIdkUQzQ/ms.jpg", 98 | "display_phone": "+1-415-606-9349", 99 | "rating_img_url_large": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/9f83790ff7f6/ico/stars/v1/stars_large_4_half.png", 100 | "id": "the-codmother-fish-and-chips-san-francisco", 101 | "is_closed": false, 102 | "location": { 103 | "cross_streets": "Jones St & Taylor St", 104 | "city": "San Francisco", 105 | "display_address": [ 106 | "496 Beach St", 107 | "North Beach/Telegraph Hill", 108 | "San Francisco, CA 94133" 109 | ], 110 | "geo_accuracy": 9.5, 111 | "neighborhoods": [ 112 | "North Beach/Telegraph Hill", 113 | "Fisherman's Wharf" 114 | ], 115 | "postal_code": "94133", 116 | "country_code": "US", 117 | "address": [ 118 | "496 Beach St" 119 | ], 120 | "coordinate": { 121 | "latitude": 37.8071157, 122 | "longitude": -122.4172602 123 | }, 124 | "state_code": "CA" 125 | } 126 | }, 127 | { 128 | "is_claimed": true, 129 | "rating": 4.5, 130 | "mobile_url": "http://m.yelp.com/biz/ikes-place-san-francisco", 131 | "rating_img_url": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/99493c12711e/ico/stars/v1/stars_4_half.png", 132 | "review_count": 6797, 133 | "name": "Ike's Place", 134 | "rating_img_url_small": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/a5221e66bc70/ico/stars/v1/stars_small_4_half.png", 135 | "url": "http://www.yelp.com/biz/ikes-place-san-francisco", 136 | "categories": [ 137 | [ 138 | "Sandwiches", 139 | "sandwiches" 140 | ] 141 | ], 142 | "menu_date_updated": 1445588108, 143 | "phone": "4155536888", 144 | "snippet_text": "I was in town for a few days and had to stop by here based on the fantastic Yelp reviews! \n\nThe place is a small order and go restaurant. They have a large...", 145 | "image_url": "http://s3-media3.fl.yelpcdn.com/bphoto/9jSqZ0UH03FXarOq80Bpww/ms.jpg", 146 | "snippet_image_url": "http://s3-media4.fl.yelpcdn.com/photo/XsrJub-9x7NTpatnk2E0bw/ms.jpg", 147 | "display_phone": "+1-415-553-6888", 148 | "rating_img_url_large": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/9f83790ff7f6/ico/stars/v1/stars_large_4_half.png", 149 | "menu_provider": "eat24", 150 | "id": "ikes-place-san-francisco", 151 | "is_closed": false, 152 | "location": { 153 | "cross_streets": "Dehon St & Sanchez St", 154 | "city": "San Francisco", 155 | "display_address": [ 156 | "3489 16th St", 157 | "Castro", 158 | "San Francisco, CA 94114" 159 | ], 160 | "geo_accuracy": 9.5, 161 | "neighborhoods": [ 162 | "Castro" 163 | ], 164 | "postal_code": "94114", 165 | "country_code": "US", 166 | "address": [ 167 | "3489 16th St" 168 | ], 169 | "coordinate": { 170 | "latitude": 37.7642944915352, 171 | "longitude": -122.430696487427 172 | }, 173 | "state_code": "CA" 174 | } 175 | }, 176 | { 177 | "is_claimed": true, 178 | "rating": 4.5, 179 | "mobile_url": "http://m.yelp.com/biz/hrd-san-francisco-2", 180 | "rating_img_url": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/99493c12711e/ico/stars/v1/stars_4_half.png", 181 | "review_count": 1667, 182 | "name": "HRD", 183 | "rating_img_url_small": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/a5221e66bc70/ico/stars/v1/stars_small_4_half.png", 184 | "url": "http://www.yelp.com/biz/hrd-san-francisco-2", 185 | "categories": [ 186 | [ 187 | "Asian Fusion", 188 | "asianfusion" 189 | ] 190 | ], 191 | "menu_date_updated": 1441920733, 192 | "phone": "4155432355", 193 | "snippet_text": "Found out about this by (don't judge me) looking up Diners Drive-Ins and Dives spot in SF. The wait staff was incredible enthusiastic, and answered a lot of...", 194 | "image_url": "http://s3-media4.fl.yelpcdn.com/bphoto/KEwOE6RPiGRm2H0zVHVAgA/ms.jpg", 195 | "snippet_image_url": "http://s3-media4.fl.yelpcdn.com/photo/jJ3kD6f1yVYIXqxPerTm_w/ms.jpg", 196 | "display_phone": "+1-415-543-2355", 197 | "rating_img_url_large": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/9f83790ff7f6/ico/stars/v1/stars_large_4_half.png", 198 | "menu_provider": "single_platform", 199 | "id": "hrd-san-francisco-2", 200 | "is_closed": false, 201 | "location": { 202 | "cross_streets": "Taber Aly & Park Ave", 203 | "city": "San Francisco", 204 | "display_address": [ 205 | "521A 3rd St", 206 | "SoMa", 207 | "San Francisco, CA 94107" 208 | ], 209 | "geo_accuracy": 9.5, 210 | "neighborhoods": [ 211 | "SoMa" 212 | ], 213 | "postal_code": "94107", 214 | "country_code": "US", 215 | "address": [ 216 | "521A 3rd St" 217 | ], 218 | "coordinate": { 219 | "latitude": 37.7812019, 220 | "longitude": -122.3952255 221 | }, 222 | "state_code": "CA" 223 | } 224 | }, 225 | { 226 | "is_claimed": true, 227 | "rating": 4.0, 228 | "mobile_url": "http://m.yelp.com/biz/box-kitchen-san-francisco", 229 | "rating_img_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/c2f3dd9799a5/ico/stars/v1/stars_4.png", 230 | "review_count": 307, 231 | "name": "Box Kitchen", 232 | "rating_img_url_small": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/f62a5be2f902/ico/stars/v1/stars_small_4.png", 233 | "url": "http://www.yelp.com/biz/box-kitchen-san-francisco", 234 | "categories": [ 235 | [ 236 | "Food Stands", 237 | "foodstands" 238 | ], 239 | [ 240 | "Burgers", 241 | "burgers" 242 | ] 243 | ], 244 | "phone": "4155807170", 245 | "snippet_text": "This is a somewhat hidden gem. The food was outstanding. They are the same owners as Louie Bar that I've been to and they have the same amazing potato skins...", 246 | "image_url": "http://s3-media1.fl.yelpcdn.com/bphoto/nrfAbr4yo57-hK0KsF7gZA/ms.jpg", 247 | "snippet_image_url": "http://s3-media4.fl.yelpcdn.com/photo/fJrH0wlC-Myp6Y4-m_9AyA/ms.jpg", 248 | "display_phone": "+1-415-580-7170", 249 | "rating_img_url_large": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/ccf2b76faa2c/ico/stars/v1/stars_large_4.png", 250 | "id": "box-kitchen-san-francisco", 251 | "is_closed": false, 252 | "location": { 253 | "cross_streets": "5th St & Mary St", 254 | "city": "San Francisco", 255 | "display_address": [ 256 | "431 Natoma St", 257 | "SoMa", 258 | "San Francisco, CA 94103" 259 | ], 260 | "geo_accuracy": 9.5, 261 | "neighborhoods": [ 262 | "SoMa" 263 | ], 264 | "postal_code": "94103", 265 | "country_code": "US", 266 | "address": [ 267 | "431 Natoma St" 268 | ], 269 | "coordinate": { 270 | "latitude": 37.7811688139033, 271 | "longitude": -122.406377480554 272 | }, 273 | "state_code": "CA" 274 | } 275 | }, 276 | { 277 | "is_claimed": true, 278 | "rating": 4.5, 279 | "mobile_url": "http://m.yelp.com/biz/the-chairman-san-francisco-2", 280 | "rating_img_url": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/99493c12711e/ico/stars/v1/stars_4_half.png", 281 | "review_count": 139, 282 | "name": "The Chairman", 283 | "rating_img_url_small": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/a5221e66bc70/ico/stars/v1/stars_small_4_half.png", 284 | "url": "http://www.yelp.com/biz/the-chairman-san-francisco-2", 285 | "categories": [ 286 | [ 287 | "Asian Fusion", 288 | "asianfusion" 289 | ], 290 | [ 291 | "Chinese", 292 | "chinese" 293 | ] 294 | ], 295 | "menu_date_updated": 1445504029, 296 | "phone": "4158138800", 297 | "snippet_text": "I am normally not a fan of delivery fees of more than a dollar or two but the $4.95 fee that The Chairman charges is probably a good thing- otherwise I...", 298 | "image_url": "http://s3-media4.fl.yelpcdn.com/bphoto/ITHb2WpqRc0zb9MDT3d1Dg/ms.jpg", 299 | "snippet_image_url": "http://s3-media3.fl.yelpcdn.com/photo/9nVSCd8GU68CGuxD0Cshug/ms.jpg", 300 | "display_phone": "+1-415-813-8800", 301 | "rating_img_url_large": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/9f83790ff7f6/ico/stars/v1/stars_large_4_half.png", 302 | "menu_provider": "eat24", 303 | "id": "the-chairman-san-francisco-2", 304 | "is_closed": false, 305 | "location": { 306 | "cross_streets": "Willow St & Ellis St", 307 | "city": "San Francisco", 308 | "display_address": [ 309 | "670 Larkin St", 310 | "Tenderloin", 311 | "San Francisco, CA 94109" 312 | ], 313 | "geo_accuracy": 9.5, 314 | "neighborhoods": [ 315 | "Tenderloin" 316 | ], 317 | "postal_code": "94109", 318 | "country_code": "US", 319 | "address": [ 320 | "670 Larkin St" 321 | ], 322 | "coordinate": { 323 | "latitude": 37.7840223067038, 324 | "longitude": -122.41758517921 325 | }, 326 | "state_code": "CA" 327 | } 328 | } 329 | ] 330 | } --------------------------------------------------------------------------------