Implementing Google custom search API in iOS
Brief Step of the process:
- Create a Google account (ignore if you have one)
- You may found some piece of information related to pricing at the bottom of this page helpful(you can ignore this too)
- Create a project and generate the API key
- Go to google console and create a project
- After the project is created, click on it to go to its detail.
- On the left bar under the Auth&API segment, click on APIs.
- Now you'll find CustomSearchAPI link in the Browse APIs section (as it is not activated by default), turn it on by clicking on the button at right.
- Now click on Credentials, just below the APIs option
- On this page under "Public API Access" click on Create New Key Button, for now, choose the browser key(as at first we wanna test it on the browser), create it, and leave it, as it is for now.
- Create Custom Search Engine
- Now on the new tab, open Custom Search Engine page. On this page click on Create a custom search engine, button
- That will lead you to create a new search engine page, here give your domain name in the "Sites to search" field. (If you don't have one no worries, give anything, that has www. at the start and .com in the end)
- Fill in the name, if it hasn't pick one already, then click on create.
- So you got a jumping robot to congratulate you? ;) Yeah, that's it. On this page step up to "Modify your search engine", by clicking on, "Control Panel" button
- There you are, now turn on the Image Search, (if you want to)
- Also in the "Sites to search" section, select, "Search the entire web but emphasize on the included item", instead of, the default one, which is "Search only included site"
- That is it, at the bottom of this page click on update. And then come back to the middle of the page and under the "Detail" title, click on Search engine ID, copy the Id, paste it somewhere.
- Search, using get request:
- To make a get request use this request URL
- In it replace, {API_KEY} which you have created under "Create a project and generate API key" section
- And replace {SEARCH_ENGINE_KEY} with the Search engine Id you just copy-pasted
Call it with some different value, at query string, then 'a', https://www.googleapis.com/customsearch/v1?**q=a**&key={API_KEY}&cx={SEARCH_ENGINE_KEY} change a with anything you wanna search you must have got the beautiful JSON of search result - Other Stuff
- If you wanna see the request status, go back to your project page, that how many requests placed, how many of those failed, etc. Click on the overview and you will get the graph for that, love you google
- If you have trouble with JSON, here are some links at your service,
- What is JSON 1, 2?
- Use JSON in ios.
- Use JSON in android.
How to use Google Custom Search for image search in objective c
The Google Custom Search API lets you develop websites and programs to retrieve and display search results from Google Custom Search programmatically.
With this API, you can use RESTful requests to get either web search or image search results in JSON or Atom format.
See the available documentation here
See this one too
Note:
cx: The identifier of the custom search engine.
Visit the Google Custom Search page to create a custom search engine for testing purposes. Select the sites that you would like to include in the search and configure the other options.
Click on "control panel" and note your Search engine unique ID. This is the cx parameter used by the API.
See the full documentation here
Example:
GET https://www.googleapis.com/customsearch/v1?key=INSERT-YOUR-KEY&cx=017576662512468239146:omuauf_lfve&q=lectures
<script src="https://www.googleapis.com/customsearch/v1?key=YOUR-KEY&cx=017576662512468239146:omuauf_lfve&q=cars&callback=hndlr">
Parse Google Custom Search API Swift
Use Codable
to parse the JSON data
.
Below are the models to only parse the metaTags
for items
,
struct Root: Codable {
let items: [Item]
}
struct Item: Codable {
let pagemap: Pagemap
}
struct Pagemap: Codable {
let metatags: [Metatag]
}
struct Metatag: Codable {
let ogImage: String?
let ogTitle: String?
enum CodingKeys: String, CodingKey {
case ogImage = "og:image"
case ogTitle = "og:title"
}
}
Parse the data
like
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let response = try decoder.decode(Root.self, from: data)
print(response.items.map({ $0.pagemap.metatags.map({ $0.ogImage }) }))
} catch {
print(error)
}
Decoding Google custom search API in Swift 4 using decodable protocol
In the code,
struct Metadata: Decodable
{
var metatags: [enclosedTags]?
}
struct enclosedTags: Decodable
{
let image: String?
let title: String?
let description: String?
let siteName: String?
private enum CodingKeys : String, CodingKey
{
case image = "og:image", title = "og:title", description = "og:description", siteName = "og:site_name"
}
}
It must be
CodingKeys
instead ofcodingKeys
. It is "C" not "c"Also, the properties of the Codable Type i.e.
Metadata
andenclosedTags
must beoptional
. You don't know what you will get from API. In case the properties are not optional and you don't get any one of the keys from API, the complete object will benil
.
Edit:
Use try?
instead of try
let tags = try? JSONDecoder().decode(Metadata.self, from: data)
print(tags?.metatags)
Expected JSON
format:
{
"metatags": [
{
"og:description": "United States declines to criticise removal of term limits as liberal thinkers inside China say move deserves to be ‘mocked by civilised countries’",
"og:image": "https://i.guim.co.uk/img/media/5d33d9276cf4388564b5bf4d42e0cd4ad8ec221e/0_230_6835_4101/master/6835.jpg?w=1200&h=630&q=55&auto=format&usm=12&fit=crop&crop=faces%2Centropy&bm=normal&ba=bottom%2Cleft&blend64=aHR0cHM6Ly91cGxvYWRzLmd1aW0uY28udWsvMjAxOC8wMS8zMS9mYWNlYm9va19kZWZhdWx0LnBuZw&s=391c7c897cafc35a55dd29b48ed544d5",
"og:title": "'Ensuring happier lives': Chinese media defends move to make Xi Jinping all powerful",
}
]
}
Sample code:
let jsonString = """
{
"metatags": [
{
"og:description": "United States declines to criticise removal of term limits as liberal thinkers inside China say move deserves to be ‘mocked by civilised countries’",
"og:image": "https://i.guim.co.uk/img/media/5d33d9276cf4388564b5bf4d42e0cd4ad8ec221e/0_230_6835_4101/master/6835.jpg?w=1200&h=630&q=55&auto=format&usm=12&fit=crop&crop=faces%2Centropy&bm=normal&ba=bottom%2Cleft&blend64=aHR0cHM6Ly91cGxvYWRzLmd1aW0uY28udWsvMjAxOC8wMS8zMS9mYWNlYm9va19kZWZhdWx0LnBuZw&s=391c7c897cafc35a55dd29b48ed544d5",
"og:title": "'Ensuring happier lives': Chinese media defends move to make Xi Jinping all powerful",
}
]
}
"""
if let jsonData = jsonString.data(using: .utf8)
{
let obj = try? JSONDecoder().decode(Metadata.self, from: jsonData)
print(obj?.metatags)
}
Output:
[SampleNavigation.ViewController.enclosedTags(image: Optional("https://i.guim.co.uk/img/media/5d33d9276cf4388564b5bf4d42e0cd4ad8ec221e/0_230_6835_4101/master/6835.jpg?w=1200&h=630&q=55&auto=format&usm=12&fit=crop&crop=faces%2Centropy&bm=normal&ba=bottom%2Cleft&blend64=aHR0cHM6Ly91cGxvYWRzLmd1aW0uY28udWsvMjAxOC8wMS8zMS9mYWNlYm9va19kZWZhdWx0LnBuZw&s=391c7c897cafc35a55dd29b48ed544d5"), title: Optional("\'Ensuring happier lives\': Chinese media defends move to make Xi Jinping all powerful"), description: Optional("United States declines to criticise removal of term limits as liberal thinkers inside China say move deserves to be ‘mocked by civilised countries’"), siteName: nil)]
Edit 2:
struct Response: Decodable
{
var items: [Item]?
}
struct Item: Decodable
{
var pagemap: Pagemap?
}
struct Pagemap: Decodable
{
var metatags: [enclosedTags]?
}
struct enclosedTags: Decodable
{
let image: String?
let title: String?
let description: String?
let siteName: String?
private enum CodingKeys : String, CodingKey
{
case image = "og:image", title = "og:title", description = "og:description", siteName = "og:site_name"
}
}
Decoding JSON:
if let jsonData = jsonString.data(using: .utf8)
{
let obj = try? JSONDecoder().decode(Response.self, from: jsonData)
print(obj?.items)
}
Edit 3:
Instead of creating separate struct for pagemap
, you can use containers
for extracting nested information, i.e. you can use the following structs
,
struct Response: Decodable
{
var items: [Item]?
}
struct Item: Decodable
{
var metatags: [enclosedTags]?
enum CodingKeys : String, CodingKey
{
case pagemap
}
enum PageMapKeys: String, CodingKey
{
case metatags
}
init(from decoder: Decoder) throws
{
let values = try decoder.container(keyedBy: CodingKeys.self)
let pagemap = try values.nestedContainer(keyedBy: PageMapKeys.self, forKey: .pagemap)
metatags = try pagemap.decode([enclosedTags].self, forKey: .metatags)
}
}
struct enclosedTags: Decodable
{
let image: String?
let title: String?
let description: String?
let siteName: String?
private enum CodingKeys : String, CodingKey
{
case image = "og:image", title = "og:title", description = "og:description", siteName = "og:site_name"
}
}
Let me know if you still face any issues. Happy Coding../p>
Google Custom Search: 403 error in iOS
It was missing the header field X-Ios-Bundle-Identifier.
NSString *bundleID = @"com.yourCompany.yourApp";
//...define request as above
[request setHTTPMethod:@"GET"];
[request setValue:bundleID forHTTPHeaderField:@"X-Ios-Bundle-Identifier"];
Google custom search: can't get api key
Turns out the solution is extremely simple, in fact it is so simple it is stupid.
The solution? Don't click that big and obvious CREATE CRENDENTIALS button, because that is clearly what Google wants us users to click, and chances are extremely high that is not what you wanted.
Then how to get an API key to the service?
Well any API key associated with the project is a valid API key for any service enabled in the project, I only figured it out because API key 1
text in "Credentials" box.
But it recommended to use different API keys for different API services because each free API key has a 10,000 daily use quota.
Then how to create an API key?
Well, in the left pane, click Credentials
, then click + CREATE CRENDENTIALS
, then choose API key
, done.
Related Topics
Error: Error Domain=Nsurlerrordomain Code=-1001 "The Request Timed Out."
Automatically Adjustable View Height Based on Text Height in Swiftui
Uicollectionview Spacing Margins
What Are File Owner and First Responder in iOS - Xcode
Uitabbar Items Jumping on Back Navigation on iOS 12.1
Uitableviewcell Checkmark to Be Toggled on and Off When Tapped
This Certificate Has an Invalid Issuer:Keychain Marks All Certificates as "Invalid Issuer"
Centering Subview's X in Autolayout Throws "Not Prepared for the Constraint"
How to Get a Cgpoint from a Tapped Location
How to Get Location User with Cllocationmanager in Swift
Removing Duplicates from Array of Custom Objects Swift
How to Apply a Vignette Cifilter to a Live Camera Feed in iOS
Pull to Refresh Uitableview Without Uitableviewcontroller
How to Retrieve a File Using Wkwebview