Implementing Google Custom Search API in iOS

Implementing Google custom search API in iOS

Brief Step of the process:

  1. Create a Google account (ignore if you have one)
  2. You may found some piece of information related to pricing at the bottom of this page helpful(you can ignore this too)
  3. Create a project and generate the API key
  4. Go to google console and create a project
  5. After the project is created, click on it to go to its detail.
  6. On the left bar under the Auth&API segment, click on APIs.
  7. 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.
  8. Now click on Credentials, just below the APIs option
  9. 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.
  10. Create Custom Search Engine
  11. Now on the new tab, open Custom Search Engine page. On this page click on Create a custom search engine, button
  12. 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)
  13. Fill in the name, if it hasn't pick one already, then click on create.
  14. 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
  15. There you are, now turn on the Image Search, (if you want to)
  16. 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"
  17. 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.
  18. Search, using get request:
  19. To make a get request use this request URL
  20. In it replace, {API_KEY} which you have created under "Create a project and generate API key" section
  21. 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
  22. Other Stuff
  23. 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
  24. If you have trouble with JSON, here are some links at your service,
    1. What is JSON 1, 2?
    2. Use JSON in ios.
    3. 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"
}
}
  1. It must be CodingKeys instead of codingKeys. It is "C" not "c"

  2. Also, the properties of the Codable Type i.e. Metadata and enclosedTags must be optional. 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 be nil.

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



Leave a reply



Submit