serpnode 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 12698d52fe2af2a41c4edf43988f3c413a34ec355991c9f4a8f722db2b45704b
4
+ data.tar.gz: 2a010a75db1d835afb5ff07a34af26a9759bcac8341a26f9cf2c4f5d81f7b35a
5
+ SHA512:
6
+ metadata.gz: cd9e45e517ba969a0e385c4b61079f9a2ffedb8abb94a0417e27155073aa5b54c860cb596df099e55141909c102f9c0922e5207b4b9dba5e5429f91d22b88c90
7
+ data.tar.gz: 725350e13ef8512287f62d724f1a40a384d4ac63c44fff404b94e3030e9ac5d59c9d71a84f27eb700157f62a63e9cc33510325de8477c252c459e75980c8b6eb
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # Serpnode Ruby SDK
2
+
3
+ Ruby client for the Serpnode API. Supports header or query auth and implements `status`, `search`, `options`, and `locations`.
4
+
5
+
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ gem build serpnode.gemspec
11
+ gem install serpnode-0.1.0.gem
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```ruby
17
+ require "serpnode"
18
+
19
+ client = Serpnode::Client.new(api_key: ENV["SERPNODE_API_KEY"]) # or use_header_auth: false
20
+
21
+ puts client.status
22
+ puts client.search(q: "site:example.com", engine: "google")
23
+ puts client.options
24
+ puts client.locations(q: "United States")
25
+ ```
@@ -0,0 +1,134 @@
1
+ require "net/http"
2
+ require "json"
3
+ require "uri"
4
+
5
+ module Serpnode
6
+ class Error < StandardError; end
7
+
8
+ class HTTPError < Error
9
+ attr_reader :status, :body
10
+
11
+ def initialize(message, status:, body: nil)
12
+ super(message)
13
+ @status = status
14
+ @body = body
15
+ end
16
+ end
17
+
18
+ class Client
19
+ DEFAULT_OPEN_TIMEOUT = 5
20
+ DEFAULT_READ_TIMEOUT = 30
21
+ DEFAULT_BASE = "https://api.serpnode.com/v1"
22
+
23
+ attr_reader :api_key, :api_base, :use_header_auth, :open_timeout, :read_timeout, :user_agent
24
+
25
+ def initialize(api_key:, api_base: DEFAULT_BASE, use_header_auth: true, open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT, user_agent: nil)
26
+ @api_key = api_key
27
+ @api_base = api_base.sub(/\/$/, "")
28
+ @use_header_auth = use_header_auth
29
+ @open_timeout = open_timeout
30
+ @read_timeout = read_timeout
31
+ @user_agent = user_agent || default_user_agent
32
+ end
33
+
34
+ def status
35
+ get("/status")
36
+ end
37
+
38
+ def search(params = {})
39
+ get("/search", params)
40
+ end
41
+
42
+ def options(params = {})
43
+ get("/options", params)
44
+ end
45
+
46
+ def locations(params = {})
47
+ get("/locations", params)
48
+ end
49
+
50
+ private
51
+
52
+ def get(path, params = {})
53
+ request(:get, path, params: params)
54
+ end
55
+
56
+ def request(method, path, params: {})
57
+ uri = build_uri(path, params)
58
+ http = Net::HTTP.new(uri.host, uri.port)
59
+ http.use_ssl = uri.scheme == "https"
60
+ http.open_timeout = open_timeout
61
+ http.read_timeout = read_timeout
62
+
63
+ request = build_http_request(method, uri)
64
+ attach_authentication(request)
65
+ attach_headers(request)
66
+
67
+ response = http.request(request)
68
+ handle_response(response)
69
+ end
70
+
71
+ def build_uri(path, params)
72
+ path = "/#{path}" unless path.start_with?("/")
73
+ uri = URI.parse("#{api_base}#{path}")
74
+
75
+ normalized_params = params.dup
76
+ unless use_header_auth
77
+ normalized_params = { api_key: api_key }.merge(normalized_params || {})
78
+ end
79
+
80
+ if normalized_params && !normalized_params.empty?
81
+ query = URI.encode_www_form(normalized_params)
82
+ uri.query = [uri.query, query].compact.join("&")
83
+ end
84
+ uri
85
+ end
86
+
87
+ def build_http_request(method, uri)
88
+ case method
89
+ when :get
90
+ Net::HTTP::Get.new(uri)
91
+ else
92
+ raise ArgumentError, "Unsupported method: #{method}"
93
+ end
94
+ end
95
+
96
+ def attach_authentication(request)
97
+ if use_header_auth
98
+ request["apikey"] = api_key
99
+ end
100
+ end
101
+
102
+ def attach_headers(request)
103
+ request["Accept"] = "application/json"
104
+ request["User-Agent"] = user_agent
105
+ end
106
+
107
+ def handle_response(response)
108
+ status = response.code.to_i
109
+ body = response.body
110
+ if status >= 200 && status < 300
111
+ parse_json(body)
112
+ else
113
+ message = begin
114
+ parsed = parse_json(body)
115
+ parsed.is_a?(Hash) && (parsed["message"] || parsed["error"]) || body
116
+ rescue JSON::ParserError
117
+ body
118
+ end
119
+ raise HTTPError.new("HTTP #{status}: #{message}", status: status, body: body)
120
+ end
121
+ end
122
+
123
+ def parse_json(string)
124
+ return nil if string.nil? || string.strip.empty?
125
+ JSON.parse(string)
126
+ end
127
+
128
+ def default_user_agent
129
+ "serpnode-ruby/#{Version::STRING} (Ruby #{RUBY_VERSION}; #{RUBY_PLATFORM})"
130
+ end
131
+ end
132
+ end
133
+
134
+
@@ -0,0 +1,7 @@
1
+ module Serpnode
2
+ module Version
3
+ STRING = "0.1.0"
4
+ end
5
+ end
6
+
7
+
data/lib/serpnode.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "serpnode/version"
2
+ require "serpnode/client"
3
+
4
+ module Serpnode
5
+ end
6
+
7
+
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: serpnode
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Your Name
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: 'Ruby client for the Serpnode API: status, search, options, locations.'
13
+ email:
14
+ - you@example.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - lib/serpnode.rb
21
+ - lib/serpnode/client.rb
22
+ - lib/serpnode/version.rb
23
+ homepage: https://serpnode.com/
24
+ licenses:
25
+ - MIT
26
+ metadata:
27
+ homepage_uri: https://serpnode.com/
28
+ source_code_uri: https://github.com/everapihq/serpnode-ruby
29
+ changelog_uri: https://github.com/everapihq/serpnode-ruby/releases
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubygems_version: 3.7.2
45
+ specification_version: 4
46
+ summary: Serpnode API client
47
+ test_files: []